设计 一个高性能爬虫系统

时间:2021-03-21 19:39:13

资料来源 http://www.xuebuyuan.com/1296711.html

开源中国 http://my.oschina.net/eshijia/blog/136595  



最近看了一篇来自纽约大学理工学院的论文,讲述的是如何设计一个高性能的分布式网络爬虫。原文标题是:Design and Implementation of a High-Performance Distributed Web Crawler。个人认为虽然此文发布的时间已经是8、9年前,但其内容仍然具有很多实践意义,故写此博文对文中内容进行一个总结。

正如原文中所说,设计一个爬虫不断的抓取网页并不是什么难事,但是如何更高效地进行调度以适应不同的需求才是网络爬虫设计的关键。

1 爬虫应用程序的种类

在应对不同场景的应用时,需要有不同的爬虫策略。目前主要有以下几种:

1.1 广度优先爬虫:如果是为了构建一个搜索引擎,那么一个高性能的爬虫首先应该从一个较小集合的页面开始,由于页面中还会有其它页面的链接,其就以广度优先的策略来抓取其它链接所指向的页面。当然,在实际使用中,往往并不是严格的遵循广度优先的策略,可能会重点先抓取预先定义好的比较重要的页面。

1.2 对页面重爬以进行更新:由于一个固定的页面在一段时间后可能会发生改变。因此,可以简单的在一段时间后再进行一次全面的广度优先爬行。当然,这肯定会涉及到如何避免重复的抓取某个页面。后文会说明当前比较普遍的一个解决此问题的方法。

1.3 垂直搜索爬虫:所谓垂直搜索,即某些搜索引擎可能只是想关注某一领域的内容。因此,爬虫也只是抓取和主题相关的页面。

1.4 专注“Hidden Web”的爬虫:网络中很多的内容并不是直接就可以访问的,可能有些内容需要我们对网页中的表单进行相关填写后才能获取到,因此专注“Hidden Web”的爬虫就是设法抓取这样的隐藏页面。

2 爬虫的基本体系结构

我们希望设计一个爬虫,其能够较为方便的适应多种不同的爬行策略。因此,将爬虫的体系结构分成了两个主要部分:应用端和系统端。如下图所示:

设计 一个高性能爬虫系统

应用端主要功能是决定在当前状态下,我们紧接着要请求哪一个页面,即向系统端发起一波URL请求。系统端的功能就是下载所请求的页面,并将这些页面返回给应用端以进行分析和存储。

由此就发现,我们主要可以在应用端配置不同的爬行策略,和系统端在不同的策略下几乎做着相同的事情。应用端主要负责完成以下几件事:对网页的解析、维护一个数据结构——其保存着我们已经发现了哪些网页、与系统端和存储部分的通信。

乍一看,似乎实现这样一个系统没什么大不了的,但是若想做到每秒下载很大数量级的网页,还是需要注意很多地方的,后文会对该体系结构进行细化。

3 谈谈如何避免重复抓取

想想也能知道,基本思想就是在每次抓取前和当前以抓取的网页进行一次比较,判断该网页(集)是否已抓取过。具体的实现方法有很多种,这里给出一种采用Hash函数的方式。

我们通过Hash函数存储网络爬虫的遍历轨迹,并规定某一Web页被遍历过,则在哈希表中的相应部分填1,否则填充0。哈希函数可以采用MD5。也就是说用相应位为1的URL的MD5集合判断URL是否已抓取过,如果没有被抓取过,则放入未爬行的URL数据中,否则放入已爬行的URL库中。

4 体系结构的细化

之前的内容可以看做是一个基本思想的介绍,接下来将对分布式爬虫的设计进行更加详细的说明。

如我们之前所示,我们已经将爬虫的体系结构分成了两部分:应用端和系统端。这里我们先对系统端进行详细的说明。系统端本身就包含很多专门的部件:爬虫管理器、一个或多个下载器以及一个或多个DNS解析器。所有的这些部件再加上应用端都可以在不同的机器上运行。

爬虫管理器的职责就是从应用端那里接受URL输入流,并其转发给可用的下载器。当然与此同时,还要遵循robots协议。robots协议就是指网站通过robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。

下载器就是一个高性能的HTTP客户端,其能并行地下载上百个网页。

一个更为详细的爬虫配置如下图所示:

设计 一个高性能爬虫系统

4.1 爬虫管理器:爬虫管理器是我们系统的核心部件,也是首先被启动的部件。之后,其它部件才开始运行,并“登记”到管理器上,以提供或请求服务。管理器接受来自爬虫应用程序的URL请求,每一个请求都有一个优先级、一个包含几百或几千URL的文件指针。管理器将会对这些请求进行排队,最终会载入相应的文件以准备进行下载。

当载入含有URL的请求文件后,除非该地址已经被缓存了,否则管理器就开始到DNS解析器中查询相应服务器的IP地址。管理器之后就请求在Web服务器根目录的robots.txt文件,来看一下哪些URL地址是可以抓取的。最后,当解析完robots文件并移除了不能抓取的URL后,没有被移除的URL就可以”绑“在一起发送给下载器。

4.2 下载器和DNS解析器:下载器是用Python实现的,其通过与不同的服务器简历1000个连接来从Web上获取文件,并将获取到的文件存储到一个目录下。由于一个下载器通常每秒能够下载几百甚至几千个页面,因此大量的页面不得不在一次磁盘操作中全部写入。为了避免重复的页面被下载,应用端可以对这些已经完成的请求进行跟踪,这样下载器就可以据此来调节自己的下载速度。对于DNS解析器,我们需要注意,DNS解析的过程将产生一定的网络流量,这一定程度上会限制爬行的速度。

5 分布式扩展

我们的设计目标是为了能够很方便的扩展所设计的爬虫结构,以提高其性能。为此,在上一个图的基础上,我们可以在添加额外的下载器和DNS解析器以提高我们的性能。我们估计为一个管理器配备8个下载器将会使得整体的速度足够快,这也因此需要2或3个DNS解析器。除了这一点,我们还可以创建第二个爬虫管理器。这样,应用端将需要在两个管理器之间分离它的请求。具体配置见下图:

设计 一个高性能爬虫系统

在以上配置中,我们用到了4个应用端。我们可以使用一个哈希函数将所有可能的URL分成4个子集,这样每个应用端负责处理一个子集。管理器将会确保为不同应用端下载的页面存放在每个应用端所确定的单独的目录。如果在解析机建,一个部件遇到了一个超链接属于另外一个子集,则那个URL就被转发到处理相应子集的应用端中。

在这样的分布式结构中,唯一涉及到大量数据通信的就是已经下载的页面间的传输。因此,理论上,如果我们允许下载的页面存储在不同的位置,则我们的系统能够在范围非常广的分布式环境中使用。

--------------------------------------------------------------------------------------------------

以上内容为原文所讲述的爬虫系统的原理介绍,原文在文章的后半部分还对所涉及到的数据结构以及一些算法技巧进行了讲解,有兴趣可以进行深究。虽然以上内容不足以让我们实现一个爬虫,但可以对爬虫系统的设计进行一些思考,各大搜索引擎的架构都是相对封闭的,只要我们能设计出一个符合我们需求的爬虫系统便是成功。