下边就由此1个差不多的小例子来看一下,WebMagic作为三个Java开发的爬虫框架很简单上手

 初学爬虫,WebMagic作为2个Java开发的爬虫框架很不难上手,下边就透过三个粗略的小例子来看一下。

 初学爬虫,WebMagic作为八个Java开发的爬虫框架很不难上手,上边就通过1个简单的小例子来看一下。

WebMagic框架简介

WebMagic框架包涵八个零件,PageProcessorSchedulerDownloaderPipeline。

这四大组件对应爬虫生命周期中的处理管理下载持久化等功能。

那四个零件都以Spider中的属性,爬虫框架通过Spider运营和管理。

WebMagic总体架构图如下:

图片 1

WebMagic框架简介

WebMagic框架包蕴八个零部件,PageProcessorSchedulerDownloaderPipeline。

那四大组件对应爬虫生命周期中的处理管理下载持久化等功能。

那么些零部件都以Spider中的属性,爬虫框架通过Spider运转和管理。

WebMagic总体框架结构图如下:

图片 2

四大组件

PageProcessor 担负解析页面,抽取有用音信,以及发现新的链接。须求自个儿定义。

Scheduler 肩负管理待抓取的U普拉多L,以及壹些去重的干活。一般无需协调定制Scheduler。

Pipeline 承担抽取结果的处理,包蕴总括、持久化到文件、数据库等。

Downloader 顶住从互连网上下载页面,以便后续处理。一般无需本人达成。

四大组件

PageProcessor 顶住解析页面,抽取有用音讯,以及发现新的链接。要求团结定义。

Scheduler 负责管理待抓取的UPRADOL,以及部分去重的劳作。壹般无需自身定制Scheduler。

Pipeline 担当抽取结果的拍卖,蕴含总计、持久化到文件、数据库等。

Downloader 肩负从网络上下载页面,以便后续处理。1般无需协调完成。

用以数据流转的靶子

Request 是对U奥迪Q3L地址的一层封装,1个Request对应3个UCR-VL地址。

Page 代表了从Downloader下载到的几个页面——大概是HTML,也大概是JSON大概别的文本格式的剧情。

ResultItems 约等于三个Map,它保存PageProcessor处理的结果,供Pipeline使用。

用于数据流转的目的

Request 是对U卡宴L地址的1层封装,3个Request对应叁个U奥迪Q伍L地址。

Page 代表了从Downloader下载到的三个页面——或许是HTML,也也许是JSON可能别的文本格式的始末。

ResultItems 一定于贰个Map,它保存PageProcessor处理的结果,供Pipeline使用。

环境安排

利用Maven来添加正视的jar包。

<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-core</artifactId>
    <version>0.7.3</version>
</dependency>

<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-extension</artifactId>
    <version>0.7.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

大概直接摸我下载。

添加完jar包就形成了具备准备干活,是否异常粗略。

上面来测试一下。

package edu.heu.spider;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.processor.PageProcessor;

/**
 * @ClassName: MyCnblogsSpider
 * @author LJH
 * @date 2017年11月26日 下午4:41:40
 */
public class MyCnblogsSpider implements PageProcessor {

    private Site site = Site.me().setRetryTimes(3).setSleepTime(100);

    public Site getSite() {
        return site;
    }

    public void process(Page page) {
        if (!page.getUrl().regex("http://www.cnblogs.com/[a-z 0-9 -]+/p/[0-9]{7}.html").match()) {
            page.addTargetRequests(
                    page.getHtml().xpath("//*[@id=\"mainContent\"]/div/div/div[@class=\"postTitle\"]/a/@href").all());
        } else {
            page.putField(page.getHtml().xpath("//*[@id=\"cb_post_title_url\"]/text()").toString(),
                    page.getHtml().xpath("//*[@id=\"cb_post_title_url\"]/@href").toString());
        }
    }

    public static void main(String[] args) {
        Spider.create(new MyCnblogsSpider()).addUrl("http://www.cnblogs.com/justcooooode/")
                .addPipeline(new ConsolePipeline()).run();
    }
}

出口结果:

图片 3

设若您和本身一样在此之前从未用过log四j,或许会产出上边的警示:

图片 4

那是因为少了铺排文件,在resource目录下新建log四j.properties文件,将上边配置音信粘贴进去即可。

目录能够定义成你协调的文本夹。

# 全局日志级别设定 ,file
log4j.rootLogger=INFO, stdout, file

# 自定义包路径LOG级别
log4j.logger.org.quartz=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH:mm:ss}[%p]%m%n

# Output to the File
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\MyEclipse2017Workspaces\\webmagic\\webmagic.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%n%-d{MM-dd HH:mm:ss}-%C.%M()%n[%p]%m%n

目前试一下,未有警示了吧。

环境安顿

接纳Maven来添加依赖的jar包。

<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-core</artifactId>
    <version>0.7.3</version>
</dependency>

<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-extension</artifactId>
    <version>0.7.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

抑或直接摸我下载。

添加完jar包就做到了富有准备工作,是否很不难。

下边来测试一下。

package edu.heu.spider;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.processor.PageProcessor;

/**
 * @ClassName: MyCnblogsSpider
 * @author LJH
 * @date 2017年11月26日 下午4:41:40
 */
public class MyCnblogsSpider implements PageProcessor {

    private Site site = Site.me().setRetryTimes(3).setSleepTime(100);

    public Site getSite() {
        return site;
    }

    public void process(Page page) {
        if (!page.getUrl().regex("http://www.cnblogs.com/[a-z 0-9 -]+/p/[0-9]{7}.html").match()) {
            page.addTargetRequests(
                    page.getHtml().xpath("//*[@id=\"mainContent\"]/div/div/div[@class=\"postTitle\"]/a/@href").all());
        } else {
            page.putField(page.getHtml().xpath("//*[@id=\"cb_post_title_url\"]/text()").toString(),
                    page.getHtml().xpath("//*[@id=\"cb_post_title_url\"]/@href").toString());
        }
    }

    public static void main(String[] args) {
        Spider.create(new MyCnblogsSpider()).addUrl("http://www.cnblogs.com/justcooooode/")
                .addPipeline(new ConsolePipeline()).run();
    }
}

输出结果:

图片 5

比方你和自家同一此前从未用过log4j,恐怕会冒出上边包车型大巴警告:

图片 6

那是因为少了计划文件,在resource目录下新建log4j.properties文件,将下边配置消息粘贴进去即可。

目录能够定义成你自个儿的文件夹。

# 全局日志级别设定 ,file
log4j.rootLogger=INFO, stdout, file

# 自定义包路径LOG级别
log4j.logger.org.quartz=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH:mm:ss}[%p]%m%n

# Output to the File
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\MyEclipse2017Workspaces\\webmagic\\webmagic.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%n%-d{MM-dd HH:mm:ss}-%C.%M()%n[%p]%m%n

当今试一下,未有警示了吧。

爬取列表类网址例子

列表爬取的研商都很类似,首先判定是不是为列表页,如果的话将小说url插足爬取队列,不是的话就象征此时为小说页,直接爬取你要的始末就能够。

慎选二个列表类文章的网址:https://voice.hupu.com/nba

图片 7

先是判断是小说依旧列表,查看多少个页面后方可找到规律,利用正则表明式区分。

page.getUrl().regex("https://voice\\.hupu\\.com/nba/[0-9]{7}\\.html").match()

借使满意下边包车型地铁正则表明式,则该url对应的是贰个小说页面。

接下去要对需求爬取的内容举办抽取,小编选取了xPath(浏览器自带直接粘贴就能够)。

图片 8

WebMagic框架帮衬三种抽取格局,包涵xPath、css选拔器、正则表达式,还是能透过links()方法选拔具有链接。

切记抽取此前要收获通过getHtml()来获取html对象,通过html对象来使用抽取方法。

ps:WebMagic好像不援助x帕特h中的last()方法,假若用到的话能够想其余措施代替。

下一场使用page.putFiled(String key, Object
field)
主意来将你想要的内容放到三个键值对中。

page.putField("Title", page.getHtml().xpath("/html/body/div[4]/div[1]/div[1]/h1/text()").toString());
page.putField("Content", page.getHtml().xpath("/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()").all().toString());

设若不满意文章页的正则,就证实那是3个列表页,此时要因此xPath来稳定页面普通话章的url。

图片 9

page.getHtml().xpath("/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href").all();

那儿,你早已获取要爬取url的list,把她们经过addTargetRequests办法到场到行列中即可。

末段落成翻页,同理,WebMagic会自动添加到爬取队列中。

图片 10

page.getHtml().xpath("/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href").all()

上边是全体代码,本人达成了三个MysqlPipeline类,用到了Mybatis,能够将爬下来的多少直接持久化到数据库中。

也足以用自带的ConsolePipeline恐怕FilePipeline等。

package edu.heu.spider;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import edu.heu.domain.News;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.processor.PageProcessor;

/**
 * @ClassName: HupuNewsSpider
 * @author LJH
 * @date 2017年11月27日 下午4:54:48
 */
public class HupuNewsSpider implements PageProcessor {

    // 抓取网站的相关配置,包括编码、抓取间隔、重试次数等
    private Site site = Site.me().setRetryTimes(3).setSleepTime(100);

    public Site getSite() {
        return site;
    }

    public void process(Page page) {
        // 文章页,匹配 https://voice.hupu.com/nba/七位数字.html
        if (page.getUrl().regex("https://voice\\.hupu\\.com/nba/[0-9]{7}\\.html").match()) {
            page.putField("Title", page.getHtml().xpath("/html/body/div[4]/div[1]/div[1]/h1/text()").toString());
            page.putField("Content",
                    page.getHtml().xpath("/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()").all().toString());
        }
        // 列表页
        else {
            // 文章url
            page.addTargetRequests(
                    page.getHtml().xpath("/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href").all());
            // 翻页url
            page.addTargetRequests(
                    page.getHtml().xpath("/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href").all());
        }
    }

    public static void main(String[] args) {
        Spider.create(new HupuNewsSpider()).addUrl("https://voice.hupu.com/nba/1").addPipeline(new MysqlPipeline())
                .thread(3).run();
    }
}

// 自定义实现Pipeline接口
class MysqlPipeline implements Pipeline {

    public MysqlPipeline() {
    }

    public void process(ResultItems resultitems, Task task) {
        Map<String, Object> mapResults = resultitems.getAll();
        Iterator<Entry<String, Object>> iter = mapResults.entrySet().iterator();
        Map.Entry<String, Object> entry;
        // 输出到控制台
        while (iter.hasNext()) {
            entry = iter.next();
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        // 持久化
        News news = new News();
        if (!mapResults.get("Title").equals("")) {
            news.setTitle((String) mapResults.get("Title"));
            news.setContent((String) mapResults.get("Content"));
        }
        try {
            InputStream is = Resources.getResourceAsStream("conf.xml");
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session = sessionFactory.openSession();
            session.insert("add", news);
            session.commit();
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

查看数据库:

图片 11

爬好的多少已经静静地躺在数据库中了。

合法文书档案中还介绍了经过注解来兑现种种功效,万分省事灵活。

动用xPath时要注意,框架我自定义了几个函数:

Expression Description XPath1.0
text(n) 第n个直接文本子节点,为0表示所有 text() only
allText() 所有的直接和间接文本子节点 not support
tidyText() 所有的直接和间接文本子节点,并将一些标签替换为换行,使纯文本显示更整洁 not support
html() 内部html,不包括标签的html本身 not support
outerHtml() 内部html,包括标签的html本身 not support
regex(@attr,expr,group) 这里@attr和group均可选,默认是group0 not support

 使用起来很有益。


转发请表明原版的书文链接:http://www.cnblogs.com/justcooooode/p/7913365.html

爬取列表类网址例子

列表爬取的想想都很相近,首先判定是还是不是为列表页,要是的话将文章url插手爬取队列,不是的话就代表此时为作品页,直接爬取你要的始末就能够。

选取贰个列表类小说的网址:https://voice.hupu.com/nba

图片 12

率先判断是小说照旧列表,查看几个页面后能够找到规律,利用正则表明式区分。

page.getUrl().regex("https://voice\\.hupu\\.com/nba/[0-9]{7}\\.html").match()

假如满足上边的正则表明式,则该url对应的是2个篇章页面。

接下去要对必要爬取的剧情开始展览抽取,作者选拔了xPath(浏览器自带直接粘贴就能够)。

图片 13

WebMagic框架援救两种抽取情势,包罗xPath、css选用器、正则表明式,还是能够通过links()方法选用具有链接。

纪事抽取此前要拿走通过getHtml()来获得html对象,通过html对象来行使抽取方法。

ps:WebMagic好像不帮忙xPath中的last()方法,假若用到的话能够想其它方式代替。

下一场使用page.putFiled(String key, Object
field)
格局来将您想要的始末放到叁个键值对中。

page.putField("Title", page.getHtml().xpath("/html/body/div[4]/div[1]/div[1]/h1/text()").toString());
page.putField("Content", page.getHtml().xpath("/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()").all().toString());

若果不满意小说页的正则,就印证那是叁个列表页,此时要通过xPath来稳定页面中作品的url。

图片 14

page.getHtml().xpath("/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href").all();

那时,你早就获得要爬取url的list,把她们通过addTargetRequests措施到场到行列中即可。

最后完结翻页,同理,WebMagic会自动添加到爬取队列中。

图片 15

page.getHtml().xpath("/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href").all()

上边是完整代码,本身完结了三个MysqlPipeline类,用到了Mybatis,能够将爬下来的数目间接持久化到数据库中。

也足以用自带的ConsolePipeline或许FilePipeline等。

package edu.heu.spider;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import edu.heu.domain.News;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.processor.PageProcessor;

/**
 * @ClassName: HupuNewsSpider
 * @author LJH
 * @date 2017年11月27日 下午4:54:48
 */
public class HupuNewsSpider implements PageProcessor {

    // 抓取网站的相关配置,包括编码、抓取间隔、重试次数等
    private Site site = Site.me().setRetryTimes(3).setSleepTime(100);

    public Site getSite() {
        return site;
    }

    public void process(Page page) {
        // 文章页,匹配 https://voice.hupu.com/nba/七位数字.html
        if (page.getUrl().regex("https://voice\\.hupu\\.com/nba/[0-9]{7}\\.html").match()) {
            page.putField("Title", page.getHtml().xpath("/html/body/div[4]/div[1]/div[1]/h1/text()").toString());
            page.putField("Content",
                    page.getHtml().xpath("/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()").all().toString());
        }
        // 列表页
        else {
            // 文章url
            page.addTargetRequests(
                    page.getHtml().xpath("/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href").all());
            // 翻页url
            page.addTargetRequests(
                    page.getHtml().xpath("/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href").all());
        }
    }

    public static void main(String[] args) {
        Spider.create(new HupuNewsSpider()).addUrl("https://voice.hupu.com/nba/1").addPipeline(new MysqlPipeline())
                .thread(3).run();
    }
}

// 自定义实现Pipeline接口
class MysqlPipeline implements Pipeline {

    public MysqlPipeline() {
    }

    public void process(ResultItems resultitems, Task task) {
        Map<String, Object> mapResults = resultitems.getAll();
        Iterator<Entry<String, Object>> iter = mapResults.entrySet().iterator();
        Map.Entry<String, Object> entry;
        // 输出到控制台
        while (iter.hasNext()) {
            entry = iter.next();
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        // 持久化
        News news = new News();
        if (!mapResults.get("Title").equals("")) {
            news.setTitle((String) mapResults.get("Title"));
            news.setContent((String) mapResults.get("Content"));
        }
        try {
            InputStream is = Resources.getResourceAsStream("conf.xml");
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session = sessionFactory.openSession();
            session.insert("add", news);
            session.commit();
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

翻开数据库:

图片 16

爬好的数目已经静静地躺在数据库中了。

合法文书档案中还介绍了通过注解来贯彻种种作用,分外便捷灵活。

使用x帕特h时要留意,框架笔者自定义了多少个函数:

Expression Description XPath1.0
text(n) 第n个直接文本子节点,为0表示所有 text() only
allText() 所有的直接和间接文本子节点 not support
tidyText() 所有的直接和间接文本子节点,并将一些标签替换为换行,使纯文本显示更整洁 not support
html() 内部html,不包括标签的html本身 not support
outerHtml() 内部html,包括标签的html本身 not support
regex(@attr,expr,group) 这里@attr和group均可选,默认是group0 not support

 使用起来很有益于。


转发请注脚原来的小说链接:http://www.cnblogs.com/justcooooode/p/7913365.html

参考资料 

合法文书档案:https://github.com/code4craft/webmagic

http://webmagic.io/docs/zh/

xPath教程:http://www.w3school.com.cn/xpath/index.asp

参考资料 

合法文书档案:https://github.com/code4craft/webmagic

http://webmagic.io/docs/zh/

xPath教程:http://www.w3school.com.cn/xpath/index.asp