1、架构介绍

1.1、四大组件

WebMagic的结构分为Downloader、PageProcessor、Scheduler、Pipeline四大组件,并由Spider将彼此组织起来。这四大组件对应爬虫声明周期中的下载、处理、管理和持久化等功能。WebMagic的设计参考了Scapy,但是实现方式更Java化一些。

img
img

1.2、用于数据流转的对象

1、Request

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

它是PageProcessor与Downloader交互的载体,也是PageProcessor控制Downloader唯一方式。

2、Page

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

Page是WebMagic抽取过程的核心对象,它提供一些方法可供抽取、结果保存等。

3、ResultItems

ResultItems相当于一个Map,它保存PageProcessor处理的结果供Pipeline使用。它的API与Map很类似,值得注意的是它有一个字段skip,若设置为true,则不应被Pipeline处理。

2、实现PageProcessor

2.1抽取元素Selectable

webMageic里使用的三种抽取技术:XPath、正则表达式和CSS选择器。对于 JSON格式的内容,可使用JsonPath进行解析。

2.2 抽取元素API

Selectable相关的抽取元素链式API是WebMagic的一个核心 功能。使用Selectable接口,可以直接完成页面元素的链式抽取,也无需去关心抽取的细节。

从刚才的例子中可以看到,page.getHtml()返回的是一个Html对象,它实现了Selectable接口。这个接口包含的方法分为两类:抽取部分和获取结果部分。

方法 说明
xpath(String xpath) 使用XPath选择 html.xpath(“//div[@class=’title’]”)
$(String selector) 使用Css选择器选择 html.$(“div.title”)
$(String selector, String attr) 使用Css选择器选择 html.$(“div.title”,”text”)
css(String selector) 功能同$(),使用Css选择器选择 html.css(“div.title”)
links() 选择所有链接 html.links()
regex(String regex) 使用正则表达式抽取 html.regex(“\(.\*?)\“)

不同API获取一个或多个元素

说明 示例
get() 返回一条String类型的结果 String link = html.links().get()
toString() 同get(),返回一条String类型的结果 String link = html.links().toString()
all() 返回所有抽取结果 List links = html.links().all()

3、实现多页面爬虫流程

开始-> 列表页面 -> 获取url(url去重) -> url加入任务 ->结束

3.1 Scheduler组件

Scheduler是WebMagic中进行URL管理的组件。

作用:

对待抓取的URL队列进行管理。

对已抓取的URL进行去重。

WebMagic内置了几个常用的Scheduler。

说明 备注
DulicateRemovedScheduler 抽象基类,提供一些模板方法 继承它可以实现自己的功能
QueueScheduler 使用内存队列保存待抓取URL
PriorityScheduler 使用带有优先级的内存队列保存待抓取URL 耗费内存较QueueScheduler更大,但是当设置request.priority之后,只能使用PriorityScheduler才可使优先级生效
FileCacheQueueScheduler 使用文件保存抓取URL,可以在关闭程序并下次启动时,从之前抓取到的URL继续抓取 需指定路径,会建立.urls.txt和.cursor.txt
RedisScheduler 使用R额滴神保存抓取队列,可进行多台机器同时合作抓取 需要安装并启动redis

去重部分被单独抽象成一个接口:DuplicateRemover,从而可以为同一个Scheduler选择不同的去重方式,以适应不同的需要,目前提供两种去重方式。

说明
HashSetDuplicateRemover 使用HashSet来进行去重,占用内存较大
BloomFilterDuplicateRemover 使用BloomFilter来进行去重,占用内存较小,但是可能漏抓页面

3.2 三种去重方式

  • HashSet

    使用Java中的HashSet不能重复的特点去重

    优点:容易理解,使用方便。

    缺点:占用内存大,性能较低。

  • Redis去重

    使用Redis的set进行去重。

    优点:速度快(Redis本身速度快),去重不会占有爬虫服务器的资源,可以处理更大数据量的数据爬取

    缺点:需要准备Redis服务器,增加开发和使用成本。

  • 布隆过滤器(BloomFilter)

    优点:占用的内存要比使用HashSet要小的多,也适合大量数据的去重操作。

    缺点:有误判的可能。没有重复可能会判断重复,但是重复的数据一定会判断重复。

    介绍:

    布隆过滤器是一种space efficient的概率型数据结构,用于判断一个元素是否在集合中。在垃圾邮件过滤黑白名单方法、爬虫(crawler)的网址判重模块中等等经常被用到。

    哈希表也能用于判断元素是否在集合中,但布隆过滤器只需要哈希表的1/8或1.4的空间复杂度就能完成同样的问题。布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,误报率越大,但是漏报是不可能的。

    原理:

    布隆过滤器需要的是位数组(二进制数组),全部赋值为0,对于有n个元素的集合S={S1, S2…Sn},通过k个映射函数{f1,f2,…..fk},将集合S中的每个元素Sj(1<=j<=n)映射为k个值{g1,g2,….gk},然后再将位数组array中相对应的array[g1],array[g2]….array[gk]置为1。< p>

    【注】:网站去重为例,对于一个url列表,一个url可以对应一组kv集合,也就是说可以获得多个v,把得到的v,将对应数组中的数值置为1。若下个网站遇到相同的位置已经是1,则该网站已经出现过,会被去重。