文档章节

Java爬虫框架:SeimiCrawler——结构化解析与数据存储

无极小子
 无极小子
发布于 2016/04/21 00:19
字数 802
阅读 214
收藏 1

本文将介绍如何使用SeimiCrawler将页面中信息提取为结构化数据并存储到数据库中,这也是大家非常常见的使用场景。数据抓取将以抓取博客园的博客为例。

建立基本数据结构

为了演示,简单起见只建立一个用来存储博客标题和内容两个主要信息的表即可。表如下:

CREATE TABLE `blog` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(300) DEFAULT NULL,
  `content` text,
  `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

同时建一个与之对应的Bean对象,如下:

package cn.wanghaomiao.model;

import cn.wanghaomiao.seimi.annotation.Xpath;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

/**
 * Xpath语法可以参考 http://jsoupxpath.wanghaomiao.cn/
 */
public class BlogContent {
    @Xpath("//h1[@class='postTitle']/a/text()|//a[@id='cb_post_title_url']/text()")
    private String title;
    //也可以这么写 @Xpath("//div[@id='cnblogs_post_body']//text()")
    @Xpath("//div[@id='cnblogs_post_body']/allText()")
    private String content;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        if (StringUtils.isNotBlank(content)&&content.length()>100){
            //方便查看截断下
            this.content = StringUtils.substring(content,0,100)+"...";
        }
        return ToStringBuilder.reflectionToString(this);
    }
}

这里面的@Xpath注解要着重介绍下,注解中配置的是针对对应字段的XPath提取规则,后面会介绍到SeimiCrawler会调用Response.render(Class<T> bean)来自动解析填充对应字段。对于开发者而言,提取结构化数据所要做的最主要的工作就在这里,且就这么多,接下来介绍的就是整体上如何串起来的。

实现数据存储

本文演示使用的是paoding-jade,一款人人网早期开源出来的ORM框架。由于SeimiCrawler的对象池以及依赖管理是使用spring来实现的,所以SeimiCrawler天然支持一切可以和spring整合的ORM框架。 要启用Jade需添加pom依赖:

<dependency>
	<groupId>net.paoding</groupId>
	<artifactId>paoding-rose-jade</artifactId>
	<version>2.0.u01</version>
</dependency>
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-dbcp2</artifactId>
	<version>2.1.1</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.37</version>
</dependency>

添加resources下seimi-jade.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

       <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
           <property name="driverClassName" value="com.mysql.jdbc.Driver" />
           <property name="url" value="jdbc:mysql://127.0.0.1:3306/xiaohuo?useUnicode=true&characterEncoding=UTF8&autoReconnect=true&autoReconnectForPools=true&zeroDateTimeBehavior=convertToNull" />
           <property name="username" value="xx" />
           <property name="password" value="xx" />
       </bean>
       <!-- 启用Jade配置 -->
       <bean class="net.paoding.rose.jade.context.spring.JadeBeanFactoryPostProcessor" />
</beans>

编写DAO,

package cn.wanghaomiao.dao;

import cn.wanghaomiao.model.BlogContent;
import net.paoding.rose.jade.annotation.DAO;
import net.paoding.rose.jade.annotation.ReturnGeneratedKeys;
import net.paoding.rose.jade.annotation.SQL;

@DAO
public interface StoreToDbDAO {
    @ReturnGeneratedKeys
    @SQL("insert into blog (title,content,update_time) values (:1.title,:1.content,now())")
    public int save(BlogContent blog);
}

数据存储搞定后接下来就是我们的爬虫规则类了

Crawler

直接上:

package cn.wanghaomiao.crawlers;

import cn.wanghaomiao.dao.StoreToDbDAO;
import cn.wanghaomiao.model.BlogContent;
import cn.wanghaomiao.seimi.annotation.Crawler;
import cn.wanghaomiao.seimi.struct.Request;
import cn.wanghaomiao.seimi.struct.Response;
import cn.wanghaomiao.seimi.def.BaseSeimiCrawler;
import cn.wanghaomiao.xpath.model.JXDocument;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * 将解析出来的数据直接存储到数据库中
 */
@Crawler(name = "storedb")
public class DatabaseStoreDemo extends BaseSeimiCrawler {
    @Autowired
    private StoreToDbDAO storeToDbDAO;

    @Override
    public String[] startUrls() {
        return new String[]{"http://www.cnblogs.com/"};
    }

    @Override
    public void start(Response response) {
        JXDocument doc = response.document();
        try {
            List<Object> urls = doc.sel("//a[@class='titlelnk']/@href");
            logger.info("{}", urls.size());
            for (Object s:urls){
                push(Request.build(s.toString(),"renderBean"));
            }
        } catch (Exception e) {
            //ignore
        }
    }
    public void renderBean(Response response){
        try {
            BlogContent blog = response.render(BlogContent.class);
            logger.info("bean resolve res={},url={}",blog,response.getUrl());
            //使用神器paoding-jade存储到DB
            int blogId = storeToDbDAO.save(blog);
            logger.info("store sus,blogId = {}",blogId);
        } catch (Exception e) {
            //ignore
        }
    }
}

Github上亦有完整的demo,大家可以下载下来,自行尝试,点击直达

© 著作权归作者所有

共有 人打赏支持
无极小子
粉丝 11
博文 8
码字总数 6214
作品 4
朝阳
程序员
Java爬虫框架 - SeimiCrawler

SeimiCrawler An agile,powerful,distributed crawler framework. SeimiCrawler的目标是成为Java世界最好用最实用的爬虫框架。 简介 SeimiCrawler是一个敏捷的,独立部署的,支持分布式的Jav...

无极小子
2015/11/10
0
5
手把手教你写网络爬虫(3):开源爬虫框架对比

原文出处:拓海 介绍 大家好!我们从今天开始学习开源爬虫框架Scrapy,如果你看过《手把手》系列的前两篇,那么今天的内容就非常容易理解了。细心的读者也许会有疑问,为什么不学出身名门的A...

拓海
04/28
0
0
webmagic的设计机制及原理-如何开发一个Java爬虫

此文章是webmagic 0.1.0版的设计手册,后续版本的入门及用户手册请看这里:https://github.com/code4craft/webmagic/blob/master/user-manual.md 之前就有网友在博客里留言,觉得webmagic的实...

黄亿华
2013/07/20
0
94
Java软件开发者,如何学习大数据?(了解一下)大数据的前世今生

Java软件开发者,如何学习大数据? 最近有不少初学者来问到,学习大数据,学习spark,公司主要使用那些语言编写,每听到这一个问题,起码还是很不错的,证明你已经开始学习大数据了,并了解大...

董黎明
06/05
0
0
如何打造类似数据虫巢官网系列教程之二:爬虫是怎么炼成的

文·blogchong 本文接上一篇《如何打造类似数据虫巢官网系列教程之一:介绍已经准备工作》,不清楚前面剧情的童鞋可以先看看。 这篇文章重点在于解决“数据虫巢官网”的底层数据问题,即那些...

数据虫巢
2017/03/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

angular 解决其他电脑不能访问的问题。

ng serve --host 0.0.0.0 --disable-host-check

miaojiangmin
今天
1
0
优酷视频文件怎么转换格式

  以前在优酷上下载视频都只是在手机上观看,但随着科技的发展,对于视频的要求也逐渐增多,不再只是观看视频那么简单,在精彩的部分还会将其单独分割出来,然后进行视频剪辑,可以做出我们...

萤火的萤火
今天
0
0
数据结构:散列

在一个数据结构中查找key元素,用顺序查找、二分查找都需要经过一系列关键之比较才能查找到结果,平均查找长度与数据量有关,元素越多比较次数就越多。 如果根据元素的关键字就能知道元素的存...

京一
今天
0
0
Apache RocketMQ 正式开源分布式事务消息

近日,Apache RocketMQ 社区正式发布4.3版本。此次发布不仅包括提升性能,减少内存使用等原有特性增强,还修复了部分社区提出的若干问题,更重要的是该版本开源了社区最为关心的分布式事务消...

阿里云云栖社区
今天
30
0
使用JavaScript和MQTT开发物联网应用

如果说Java和C#哪个是最好的开发语言,无疑会挑起程序员之间的相互怒怼,那如果说JavaScript是动态性最好的语言,相信大家都不会有太大的争议。随着越来越多的硬件平台和开发板开始支持JavaS...

少年不搬砖老大徒伤悲
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部