1、架构介绍
1.1、四大组件
WebMagic的结构分为Downloader、PageProcessor、Scheduler、Pipeline四大组件,并由Spider将彼此组织起来。这四大组件对应爬虫声明周期中的下载、处理、管理和持久化等功能。WebMagic的设计参考了Scapy,但是实现方式更Java化一些。
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,则该网站已经出现过,会被去重。
=j<=n)映射为k个值{g1,g2,….gk},然后再将位数组array中相对应的array[g1],array[g2]….array[gk]置为1。<>