爬虫
通过程序代码将网页中我们需要的文本信息批量、自动保存下来。
自己如何实现
如果不用框架,完全我们自己手写实现爬虫的功能,思路流程应该是怎样的?
- 使用http类库下载一个起始url得到html字符串
- 解析html字符串得到我们需要的文本字符串
- 将第2步解析得到的文本字符串保存到数据库
- 如果起始url是博客文章列表页,我们还需要从html字符串中解析出每篇文章详细信息的url地址,再下载、解析文章详细信息url的网页html拿到文章的正文内容。这个过程肯定不能是手动的,第一想法是使用个内存阻塞队列来存储要爬取的url,然后多线程-生产者消费者模式去解决。
WebMagic框架就是做了上面流程的这些事,只需要我们自己写解析网页html字符串和保存到数据库的逻辑就行了(因为每个网页html字符串是不一样的),其他的都帮我们写好了。
WebMagic的内部实现也是生产者/消费者模式(后续的源码分析篇会看到) ,四个组件根据名称就能知道其大概功能:Downloader下载网页的,PageProcesser解析html字符串的,Pipeline写保存到数据库的逻辑,Scheduler生产者/消费者模式中的阻塞队列。
WebMagic核心设计
WebMagic的结构分为Downloader、PageProcessor、Scheduler、Pipeline四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。下面是官方给的架构图:
四个组件
Downloader
网页下载器。将一个URL地址对应的网页HTML文本下载到本地来。为了提高下载效率,WebMagic在这一块设计成了多线程实现的方式。
可以继承HttpClientDownloader,将下载失败的URL保存到redis中。
PageProcessor
页面处理器。对下载到本地的网页HTML文本进行分析,提取出我们需要的文本。
因为每个网页的内容是不同的,需要我们自定义处理逻辑。
Pipeline
持久化操作。将提取出的文本保存到数据库或文件中。
同样需要我们自定义保存到数据库的逻辑。
Scheduler
URL管理器。所有URL都会存到Scheduler中,它相当于一个保存URL字符串的容器,内置了使用set进行URL去重功能。当我们需要爬取一个URL地址对应的网页时,就把这个URL推送到Scheduler中。下载器Downloader每次会从Scheduler中拉取出一个URL进行下载——典型的生产者/消费者模式。
因为需要分布式运行,所以需要我们自定义基于redis保存URL的RedisScheduler类,可以参考官方源码webmagic-extension包中us.codecraft.webmagic.scheduler.RedisScheduler实现。
执行引擎Spider
将四个组件串起来进行整个爬取流程的核心组件,也是整个流程的入口,每个组件作为Spider的一个属性。
数据流转组件
Request
对请求的封装,也可以说是对URL的封装,内部还包含一个extraMap, 用于传递一些额外的辅助信息
Page
对Downloader下载到的HTML页面的封装,从中可以获取到网页html文本,使用xpath解析dom提取出目标文本。
ResultItems
包裹从PageProcessor提取出来的数据,内部使用Map实现,用于PageProcessor和Pipeline之间的数据传递。
WebMagic运行机制
- 创建Spider对象,设置自定义的PageProcessor和Pipeline,如果自定义了RedisScheduler则设置,否则使用默认内存阻塞队列实现的Scheduler,设置并发线程数,添加起始url,启动爬虫run()。
- 将封装起始url的Request对象推送到Scheduler的阻塞队列中。
- Downloader从Scheduler中拉取Request进行下载,将得到的网页html文本封装成Page对象传递给PageProcessor。
- PageProcessor中自定义的解析逻辑从html文本中提取到目标文本,封装成ResultItems对象传递给Pipeline。
- Pipeline中自定义的持久化逻辑将目标文本保存到数据库。
- 如果html文本中有我们后续需要爬取的页面url,将其提取出推送到Scheduler,继续整个生产者/消费者循环。
小结
WebMagic将爬取网页的流程分解成多个组件,封装其中不变的成分,内部使用生产者/消费者模式实现爬虫批量、自动爬取网页的特性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。