java抓取框架_Java爬虫框架WebMagic入门——爬取列表类网站文章

初学爬虫,WebMagic作为一个Java开发的爬虫框架很容易上手,下面就通过一个简单的小例子来看一下。

WebMagic框架简介

WebMagic框架包含四个组件,PageProcessor、Scheduler、Downloader和Pipeline。

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

这四个组件都是Spider中的属性,爬虫框架通过Spider启动和管理。

WebMagic总体架构图如下:

1201e06f65f81ce69b84213af4b585f0.png

四大组件

PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。需要自己定义。

Scheduler负责管理待抓取的URL,以及一些去重的工作。一般无需自己定制Scheduler。

Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。

Downloader负责从互联网上下载页面,以便后续处理。一般无需自己实现。

用于数据流转的对象

Request是对URL地址的一层封装,一个Request对应一个URL地址。

Page 代表了从Downloader下载到的一个页面——可能是HTML,也可能是JSON或者其他文本格式的内容。

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

环境配置

使用Maven来添加依赖的jar包。

us.codecraft

webmagic-core

0.7.3

us.codecraft

webmagic-extension

0.7.3

org.slf4j

slf4j-log4j12

或者直接摸我下载。

添加完jar包就完成了所有准备工作,是不是很简单。

下面来测试一下。

packageedu.heu.spider;importus.codecraft.webmagic.Page;importus.codecraft.webmagic.Site;importus.codecraft.webmagic.Spider;importus.codecraft.webmagic.pipeline.ConsolePipeline;importus.codecraft.webmagic.processor.PageProcessor;/*** @ClassName: MyCnblogsSpider

*@authorLJH

* @date 2017年11月26日 下午4:41:40*/

public class MyCnblogsSpider implementsPageProcessor {private Site site = Site.me().setRetryTimes(3).setSleepTime(100);publicSite getSite() {returnsite;

}public voidprocess(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 voidmain(String[] args) {

Spider.create(new MyCnblogsSpider()).addUrl("http://www.cnblogs.com/justcooooode/")

.addPipeline(newConsolePipeline()).run();

}

}

输出结果:

8edd9651e9079ce7fbac338f536344f1.png

如果你和我一样之前没有用过log4j,可能会出现下面的警告:

2f908bcce910d26bbf118248ecc95867.png

这是因为少了配置文件,在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

2aa43af7e084ff54e725ac1bea87cdcc.png

首先判断是文章还是列表,查看几个页面后可以找到规律,利用正则表达式区分。

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

如果满足上面的正则表达式,则该url对应的是一个文章页面。

接下来要对需要爬取的内容进行抽取,我选择了

8858be7809881a0b39776165f221fb2e.png

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。

394fe25d319532e70568e76c9b4b5a98.png

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

这时,你已经得到要爬取url的list,把他们通过addTargetRequests方法加入到队列中即可。

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

87b5e32bc405086ed2a9fb2c533d2582.png

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

下面是完整代码,自己实现了一个MysqlPipeline类,用到了Mybatis,可以将爬下来的数据直接持久化到数据库中。

也可以用自带的ConsolePipeline或者FilePipeline等。

packageedu.heu.spider;importjava.io.IOException;importjava.io.InputStream;importjava.util.Iterator;importjava.util.Map;importjava.util.Map.Entry;importorg.apache.ibatis.io.Resources;importorg.apache.ibatis.session.SqlSession;importorg.apache.ibatis.session.SqlSessionFactory;importorg.apache.ibatis.session.SqlSessionFactoryBuilder;importedu.heu.domain.News;importus.codecraft.webmagic.Page;importus.codecraft.webmagic.ResultItems;importus.codecraft.webmagic.Site;importus.codecraft.webmagic.Spider;importus.codecraft.webmagic.Task;importus.codecraft.webmagic.pipeline.Pipeline;importus.codecraft.webmagic.processor.PageProcessor;/*** @ClassName: HupuNewsSpider

*@authorLJH

* @date 2017年11月27日 下午4:54:48*/

public class HupuNewsSpider implementsPageProcessor {//抓取网站的相关配置,包括编码、抓取间隔、重试次数等

private Site site = Site.me().setRetryTimes(3).setSleepTime(100);publicSite getSite() {returnsite;

}public voidprocess(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 voidmain(String[] args) {

Spider.create(new HupuNewsSpider()).addUrl("https://voice.hupu.com/nba/1").addPipeline(newMysqlPipeline())

.thread(3).run();

}

}//自定义实现Pipeline接口

class MysqlPipeline implementsPipeline {publicMysqlPipeline() {

}public voidprocess(ResultItems resultitems, Task task) {

Map mapResults =resultitems.getAll();

Iterator> iter =mapResults.entrySet().iterator();

Map.Entryentry;//输出到控制台

while(iter.hasNext()) {

entry=iter.next();

System.out.println(entry.getKey()+ ":" +entry.getValue());

}//持久化

News news = newNews();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= newSqlSessionFactoryBuilder().build(is);

SqlSession session=sessionFactory.openSession();

session.insert("add", news);

session.commit();

session.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}

查看数据库:😊

18403b8ac1a438aca3851534811e218a.png

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

官方文档中还介绍了通过注解来实现各种功能,非常简便灵活。

使用xPath时要留意,框架作者自定义了几个函数:

ExpressionDescriptionXPath1.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

使用起来很方便。

参考资料

官方文档:https://github.com/code4craft/webmagic

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值