今天学习一个酷炫的封装性很好的爬虫框架WebMagic
1、总体架构
WebMagic总体架构图如下:
四个组件:
Downloader:负责从网络上下载页面,获取到初始的Html文本,供后续处理。默认使用Apache HttpClient作为下载工具。
PageProcessor:负责解析页面,抽取有用的信息,发现新链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup。开发者需要根据每个不同的页面来实现不同的PageProcessor,这是实现业务逻辑的地方
Scheduler: 负责管理带抓取的URL,以及一些去重的工作。WebMagic默认提供了JDK的内存队列来管理URL,并用集合来进行去重。也支持使用Redis进行分布式管理。除非项目有一些特殊的分布式需求,否则无需自己定制Scheduler。
Pipeline:负责处理获取到的结果,包括计算、持久化到文件、数据库等。WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。Pipeline定义了结果保存的方式,如果你要保存到指定数据库,则需要编写对应的Pipeline。对于一类需求一般只需编写一个Pipeline。
数据流传的对象:
Request: 是一个URL地址的一层封装,一个Request对应一个URL,它是PageProcessor与Downloader交互的载体,也是PageProcessor控制Downloader唯一方式。PageProcessor提供Request给Downloader进行页面的下载,除了URL外,还有一个extra字段。可以在extra中保存一些特殊的属性,然后在其他地方读取。例如附加上一个页面的一些信息
Page: 表示Downloader下载到的一个页面——可能是HTML,也可能是JSON或者其他文本格式的内容。Page是WebMagic抽取过程的核心对象,它提供一些方法可供抽取、结果保存等。
Resultitems:相当于一个Map,保存PageProcessor处理的结果,供Pipeline使用,它有一个skip字段,若设置为true则不会被Pipeline处理
核心运转引擎
* Spider: Spider是WebMagic内部流程的核心。Downloader、PageProcessor、Scheduler、Pipeline都是Spider的一个属性,这些属性是可以自由设置的,通过设置这个属性可以实现不同的功能。Spider也是WebMagic操作的入口,它封装了爬虫的创建、启动、停止、多线程等功能。下面是一个设置各个组件,并且设置多线程和启动的例子。
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从https://github.com/code4craft开始抓
.addUrl("https://github.com/code4craft")
//设置Scheduler,使用Redis来管理URL队列
.setScheduler(new RedisScheduler("localhost"))
//设置Pipeline,将结果以json方式保存到文件
.addPipeline(new JsonFilePipeline("D:\\data\\webmagic"))
//开启5个线程同时执行
.thread(5)
//启动爬虫
.run();
}
2、开发流程
在WebMagic里,实现一个基本的爬虫只需要编写一个类,实现PageProcessor接口即可。这个类基本上包含了抓取一个网站,你需要写的所有代码。 以下为抓取http://www.yuerzaixian.com/Item/list.asp?id=1234新闻的代码示例
- 实现PageProcessor
分析相关url
这个网站有两种类型的url,分别是列表页以及新闻详细页,分析得到两种不同的模式。这里需要注意Url中的’?’需要转义
详细页模式:
列表页模式:
继承PageProcessor接口并且进行相关配置
这里注意当html页面中的meta标签中的charset=为空值或者没有值时需要指定一个编码
实现逻辑函数process
如果是列表页,则将所有的符合列表页的links和详细页加入到TargetRequest
这里用到xpath的语法 “//div[@class=\”xinxi\”]” 表示class为”xinxi”的div
.links()表示所有的连接
如果是详情页,则将符合的title和date用xpath语法选择出来并且put到page中
新建spider启动Processor
如果没指定pipeline则为“输出到控制台“的pipeline,可以指定自己的处理方式
添加url 然后Run即可启动
控制台查看结果
3、源码分析
从spider的run()方法函数 分析源码
Spider类:
可以看出四大组件downloader、pipeline、pageProcessor、scheduler还有网站配置Site都为此类的成员
run()方法
checkRunningStat 方法检查spider是否在启动,如果没启动,则stat进行cas操作设置为1
initComponent方法进行相关参数的初始化,例如downloader的设置(默认为HttpClientDownloader),Pipeline(默认为ConsolePipeline)、线程池的设置、将所有的Request都push到scheduler的队列中,然后清空请求
接着如果当前的request为空,即没有请求,则调用waitNewUrl,在此方法中,会调用Condition类的await()的方法进行等待新的请求 此外还会检查线程池中是否有空闲可用的线程
如果不为空 ,则启动线程,首先processRequest进行处理,如果设置了SpiderListener,则调用onsucess方法进行回调 ,最后将pageCount自增。唤醒新的完成后,将stat设为2,关闭Spider
processRequest方法中,调用downloader的download方法获取到页面,如果页面为空或者其他错误,则进行休眠或者相关的错误处理,否则,将Page传给pageProcessor的process(开发者自己定义的业务逻辑)中进行处理,然后调用extractAndAddRequests方法将下一个targetUrl加入到request列表,然后将page的getResultItems传入pageline进行结果的后续处理
HttpClientDownloader是默认的download,其中的download方法调用HttpClient进行请求、编码设置等,然后将内容和statuscode放入page中(调用handleResponse)最后返回 可以设置OnSuccess和OnError回调
extractAndAddRequests方法用来将TargetRequests中的目标url加入到scheduler中(scheduler.push)
默认的scheduler是QueueScheduler,里面维护着一个LinkedBlockingQueue队列,用来管理Url列表,其中继承了DuplicateRemovedScheduler类用来去重url