网络爬虫也被称为机器人或蜘蛛,它被搜索引擎用于发现网络上的新内容或更新内容。内容可以是网页、图片、视频、PDF文件等。网络爬虫开始时会收集一些网页,然后跟随这些网页上的链接收集新的内容。图9-1展示了爬取过程的可视化示例。
爬虫的作用:
开发网络爬虫的复杂度取决于我们打算支持的规模。它可能是一个只需几个小时就能完成的小项目,或者是需要一个专业工程团队不断改进的巨大项目。因此,我们将在下面探讨需要支持的规模和特性。
网络爬虫的基本算法很简单:
网络爬虫真的像这个基本算法那样简单吗?并非如此。设计一个可扩展的可大规模网络爬虫是一项极其复杂的任务。在面试时间内设计一个大规模的网络爬虫对任何人来说都不太可能。在开始设计之前,我们必须提问以理解需求并确定设计范围:
候选人:爬虫的主要目的是什么?它是用于搜索引擎索引、数据挖掘,还是其他什么?
面试官:搜索引擎索引。
候选人:网络爬虫每月收集多少网页?
面试官:10亿个网页。
候选人:包括哪些内容类型?仅HTML,还是也包括PDF和图片等其他内容类型?
面试官:仅HTML。
候选人:我们应该考虑新添加或编辑过的网页吗?
面试官:是的,我们应该考虑新添加或编辑过的网页。
候选人:我们需要存储从网络爬取的HTML页面吗?
面试官:是的,存储时间长达5年。
候选人:我们如何处理具有重复内容的网页?
面试官:应忽略具有重复内容的页面。
以上是我们向面试官提问的一些样本问题。理解需求和澄清歧义非常重要。即使你被要求设计一个像网络爬虫这样的需求清晰的产品,你和你的面试官可能也会有不同的侧重。
除了需要与面试官澄清的功能,还要注意记录下一个好的网络爬虫的以下特点:
以下估计基于许多假设,与面试官沟通以达成共识非常重要。
一旦需求明确,我们就可以进行高级设计。受到以往关于网络爬虫的研究的启发,我们提出了如图9-2所示的高级设计。
首先,我们探索每个设计组件以理解他们的功能。然后,我们逐步检查爬虫的工作流程。
种子URL
网络爬虫使用种子URL作为爬行过程的起点。例如,要从大学的网站上爬取所有网页,选择种子URL的直观方式是使用大学的域名。
要爬取整个网络,我们需要在选择种子URL时富有创造性。一个好的种子URL作为一个好的起点,爬虫可以利用它遍历尽可能多的链接。通常的策略是将整个URL空间分割成更小的部分。首先提出的方法是基于区域性,因为不同的国家可能有不同的热门网站。另一种方式是根据主题选择种子URL;例如,我们可以将URL空间划分为购物、体育、健康保健等。种子URL的选择是一个开放性问题。你不需要给出完美的答案。只需给面试官给出你的思考即可。
URL集合
大多数现代网络爬虫将爬行状态分为两种:待下载和已下载。存储待下载URL的组件称为URL集合。你可以将其视为先进先出(FIFO)队列。要获取关于URL集合的详细信息,请参考深入了解部分。
HTML下载器
HTML下载器从互联网上下载网页。这些URL由URL集合提供。
DNS解析器
要下载一个网页,必须将URL转换为IP地址。HTML下载器调用DNS解析器,获取URL对应的IP地址。例如,URL http://www.wikipedia.org 被转换为IP地址198.35.26.96。
内容解析器
下载一个网页后,必须对其进行解析和验证,因为格式不正确的网页可能会引发问题并浪费存储空间。在爬虫服务器中实现内容解析器会减慢爬行过程。因此,内容解析器最好是一个独立的组件。
内容爬过了吗?
在线研究显示,29%的网页是重复内容,这可能导致相同的内容被多次存储。我们引入“内容爬过了吗?”数据结构来消除数据冗余并缩短处理时间。它有助于检测以前存储在系统中的新内容。比较两个HTML文档,我们可以逐字符地比较它们。然而,这种方法慢且耗时,特别是当涉及到数十亿个网页时。一种有效的方法是比较两个网页的哈希值。
内容存储
这是一个用于存储HTML内容的存储系统。存储系统的选择取决于诸如数据类型、数据大小、访问频率、寿命等因素。使用的存储介质包括磁盘和内存。
URL提取器
URL提取器从HTML页面中解析并提取链接。图9-3显示了一个链接提取过程。通过添加“https://en.wikipedia.org”前缀,将相对路径转换为绝对URL。
URL过滤器
URL过滤器排除某些内容类型,文件扩展名,错误链接和“黑名单”网站中的URL。
URL爬过了吗?
“URL爬过了吗?”是一个跟踪之前访问过的URL或已经在前沿的URL的数据结构。“URL爬过了吗?”有助于避免多次添加同一URL,因为这可能会增加服务器负载并可能导致潜在的无限循环。
布隆过滤器和哈希表是实现“URL爬过了吗?”组件的常见技术。我们在这里不会详细介绍布隆过滤器和哈希表的实现。
URL存储
URL存储存放已经访问过的URL。
到目前为止,我们已经讨论了每个系统组件。接下来,我们将它们组合在一起,以解释工作流程。
网络爬虫工作流程
为了更好地逐步解释工作流程,我们在设计图中添加了序列号,如图9-4所示。
步骤1:将种子URL添加到URL集合。
步骤2:HTML下载器从URL集合获取URL列表。
步骤3:HTML下载器从DNS解析器获取URL的IP地址并开始下载。
步骤4:内容解析器解析HTML页面并检查页面是否有误。
步骤5:在内容被解析和验证后,它被传递到“内容已爬过?”组件。
步骤6:“内容已爬过”组件检查HTML页面是否已经在存储中。
步骤7:链接提取器从HTML页面中提取链接。
步骤8:提取的链接被传递给URL过滤器。
步骤9:链接被过滤后,它们被传递给“URL已爬过?”组件。
步骤10:“URL已爬过”组件检查URL是否已经在存储中,如果是,那么它已经被处理过,无需做任何事情。
步骤11:如果URL之前没有被处理过,那么它被添加到URL集合。
到现在为止,我们已经讨论了高层设计。接下来,我们将深入讨论最重要的构建组件和技术:
你可以将网络视为一个有向图,其中网页作为节点,超链接(URL)作为边。爬取过程可以被看作是从一个网页到其他网页的有向图遍历。两种常见的图遍历算法是DFS和BFS。然而,DFS通常不是一个好的选择,因为在网络爬虫的场景下DFS的深度可能非常深。
网络爬虫常用的是BFS,它通过一个先进先出(FIFO)队列来实现。在一个FIFO队列中,URL按照他们入队的顺序出队。然而,这种实现有两个问题:
• 标准的BFS并没有考虑到URL的优先级。网络很大,不是每个页面的质量和重要性都一样。因此,我们可能希望根据他们的页面排名,网页流量,更新频率等来对URL进行优先排序。
URL集合有助于解决这些问题。URL集合是一个存储待下载URL的数据结构。URL集合是确保礼貌、URL优先级和新鲜度的重要组件。
礼貌
通常,网络爬虫应避免在短时间内向同一主机服务器发送过多的请求。发送过多的请求被视为“不礼貌的”,甚至被视为拒绝服务(DOS)攻击。例如,如果没有任何限制,爬虫可以每秒向同一网站发送数千个请求。这可能会压垮网络服务器。
实施礼貌的一般思想是一次从同一主机下载一个页面。并且在两个下载任务之间添加延迟。礼貌约束是通过维护从网站主机名到下载(工作线程)的映射来实现的。每个下载线程都有一个独立的FIFO队列,并且只从该队列下载URL。图9-6显示了管理礼貌的设计。
优先级
论坛上的随机帖子与首页上的帖子具有不同的权重。尽管它们都包含“Apple”关键字,但爬虫优先爬取Apple首页是更成熟的做法。
我们根据有用性对URL进行优先级排序,这可以通过PageRank ,网站流量,更新频率等来衡量。"优先级处理器"是处理URL优先级的组件。有关这个概念的深入信息,请参考参考资料。
图9-7显示了管理URL优先级的设计。
图9-8展示了URL集合设计,它包含两个模块:
image-
新鲜度
网页一直处于不断地添加、删除和编辑的状态。网络爬虫必须定期重新爬取已下载的页面,以保持我们的数据集新鲜。重新爬取所有的URL既耗时又资源密集。以下列出了一些优化新鲜度的策略:
URL Frontier的存储
在现实世界中为搜索引擎进行爬取时,集合中的URL数量可能达到几亿。把所有东西都放在内存中既不持久也不可扩展。但是磁盘速度慢,我们也不希望把所有东西都存储在磁盘中;并且它很容易成为爬取的瓶颈。
我们采取了一种混合方法。大部分URL存储在磁盘上,因此存储空间不是问题。为了减少从磁盘读取和写入磁盘的成本,我们在内存中维护用于入队/出队操作的缓冲区。缓冲区中的数据会定期写入磁盘。
HTML下载器使用HTTP协议从互联网下载网页。在讨论HTML下载器之前,我们先看一下机器人排除协议。
Robots.txt
Robots.txt,也被称为机器人排除协议,是网站用来与爬虫交流的一种标准。它指定了爬虫允许下载的页面。在尝试爬取一个网站之前,爬虫应该先检查其对应的robots.txt文件,并遵循其规则。
为了避免重复下载robots.txt文件,我们将文件的结果缓存在内存中。该文件会定期下载并保存到缓存中。这是从https://www.amazon.com/robots.txt获取的一部分robots.txt文件。像creatorhub这样的目录对于Google bot来说是禁止访问的。
User-agent: Googlebot Disallow: /creatorhub/* Disallow: /rss/people//reviews Disallow: /gp/pdp/rss//reviews Disallow: /gp/cdp/member-reviews/ Disallow: /gp/aw/cr/
除了robots.txt,性能优化是我们将要涉及到的HTML下载器的另一个重要概念。
性能优化
以下是HTML下载器的性能优化列表。
1. 分布式爬取
为了达到高性能,爬取工作分布在多个服务器上,并且每个服务器运行多个线程。URL空间被划分为更小的片段,因此,每个下载器负责URL的一个子集。图9-9展示了分布式爬取的一个例子。
2. 缓存DNS解析器
由于许多DNS接口的同步性质,DNS请求可能需要一些时间,这使得DNS解析器成为爬虫的瓶颈。DNS响应时间范围从10ms到200ms。一旦一个爬虫线程进行了对DNS的请求,其他线程就会被阻塞,直到第一个请求完成。为了避免频繁调用DNS,维护我们自己的DNS缓存是一种有效的速度优化技术。我们的DNS缓存保存域名到IP地址的映射,并由定时任务定期更新。
3. 区域性
地理分布爬取服务器。当爬取服务器更接近网站主机时,可以缩短下载时间。区域性设计适用于大多数系统组件:爬取服务器、缓存、队列、存储等。
4. 短超时
一些网页服务器响应慢或者可能根本不响应。为了避免长时间等待,我们设定了最大等待时间。如果一个主机在预定的时间内没有响应,爬虫将停止该任务并爬取其他页面。
除了性能优化外,鲁棒性也是一个重要的考虑因素。我们提出了几种提高系统鲁棒性的方法:
几乎每个系统都会发展,所以我们的一个设计目标是使系统足够灵活,以支持新的内容类型。爬虫可以通过插入新的模块来扩展。图9-10显示了如何添加新的模块。
本节讨论了冗余、无意义或有害内容的检测和防止。
1. 冗余内容
如前所述,近30%的网页是重复的。哈希或校验和有助于检测重复内容。
2. 蜘蛛陷阱
蜘蛛陷阱是一个会导致爬虫陷入无限循环的网页。例如,一个无限深的目录结构如下所示: http://www.spidertrapexample.com/foo/bar/foo/bar/foo/bar/...
通过设置URL的最大长度,可以避免这样的蜘蛛陷阱。然而,没有一种万全之策可以检测蜘蛛陷阱。包含蜘蛛陷阱的网站很容易识别,因为在这些网站上发现的网页数量异常大。开发自动避免蜘蛛陷阱的算法很难;但是,用户可以手动验证并识别蜘蛛陷阱,并将这些网站从爬虫中排除或应用一些自定义的URL过滤器。
3. 数据噪声
有些内容的价值很小或者没有价值,如广告、代码片段、垃圾URL等。这些内容对爬虫无用,如果可能,应该被排除。
在本章中,我们首先讨论了好的爬虫的特点:可扩展性、礼貌性、可扩展性和鲁棒性。然后,我们提出了一个设计并讨论了关键组件。构建一个可扩展的网页爬虫并非易事,因为网页数量庞大且充满陷阱。尽管我们已经涵盖了许多话题,但我们仍然遗漏了许多相关的讨论点: