系统设计面试:卷1 第九章 如何设计一个网络爬虫

596 阅读19分钟

在本章中,我们重点讨论了网络爬虫设计:一个有趣而经典的系统设计面试问题。

网络爬虫被称为机器人或蜘蛛。它被搜索引擎广泛用于发现网络上新的或更新的内容。内容可以是网页、图像、视频、PDF文件等。网络爬虫首先收集一些网页,然后按照这些网页上的链接收集新内容。图9-1展示了爬行过程的可视化示例。

image.png

爬虫有很多用途:

  • 搜索引擎索引:这是最常见的用例。爬虫收集网页,为搜索引擎创建本地索引。例如,Googlebot是谷歌搜索引擎背后的网络爬虫。

  • 网络存档:这是从网络上收集信息以保存数据以备将来使用的过程。例如,许多国家图书馆运行爬虫到存档网站。值得注意的例子是美国国会图书馆和欧盟网络档案馆。

  • 网络挖掘:网络的爆炸性增长为数据挖掘提供了前所未有的机会。网络挖掘有助于从互联网中发现有用的知识。例如,顶级金融公司使用爬虫下载股东会议和年度报告,以了解公司的主要举措。

  • Web监控。爬虫程序有助于监控互联网上的版权和商标侵权行为。例如,Digimarc利用爬虫来发现盗版作品和报告。

开发网络爬虫的复杂性取决于我们打算支持的规模。它可以是一个小型的学校项目,只需要几个小时就可以完成,也可以是一个需要专业工程团队不断改进的大型项目。因此,我们将在下面探讨要支持的规模和特性。😊

第一步-理解需求并且建立设计范围

网络爬虫的基本算法很简单: 1.给定一组url,下载这些url所指向的所有网页。

  1. 从这些网页中提取url将新的url添加到要下载的url列表中。重复这3个步骤。

网络爬虫的工作真的像这个基本算法一样简单吗?不完全是。设计一个可扩展的网络爬虫是一项极其复杂的任务。任何人都不太可能在面试期间设计一个庞大的网络爬虫。在进入设计之前,我们必须提出问题以了解需求并确定设计范围: 候选人:爬虫的主要目的是什么?它是用于搜索引擎索引、数据挖掘还是其他用途? 面试官:搜索引擎索引。

候选人:网络爬虫每月收集多少网页? 面试官:10亿页。

候选人:包括哪些内容类型?仅使用HTML还是其他内容类型,如pdf和图像? 面试官:只有HTML。

候选人:我们是否考虑新添加或编辑的网页? 面试官:是的,我们应该考虑新添加或编辑的网页。

候选人:我们需要存储从网络抓取的HTML页面吗? 面试官:是的,最多5年。 应聘者:我们如何处理内容重复的网页? 面试官:有重复内容的页面应该忽略。

以上是一些你可以问面试官的问题。理解需求和澄清歧义是很重要的。即使你被要求设计一个简单的产品,如网络爬虫,你和你的面试官可能有不同的假设。

除了向你的面试官澄清功能之外,记下一个好的网络爬虫的以下特征也很重要:

  • 可扩展性:网络非常庞大。世界上有数十亿的网页。使用并行化,Web爬行应该非常高效。

  • 稳健性:网络充满了陷阱。糟糕的HTML,无响应的服务器,崩溃,恶意链接等都是常见的。爬虫必须处理所有这些边缘情况。

  • 礼貌:爬虫不应该在短时间间隔内对网站发出太多请求。

  • 灵活性:系统是灵活的,因此需要最小的更改来支持新的内容类型。例如,如果我们将来想要抓取图像文件,我们应该不需要重新设计整个系统。

数据估计

以下的估计是基于许多假设,与面试官沟通以达成一致是很重要的。

  • 假设每个月有10亿个网页被下载。

  • QPS: 1000,000,000 / 30天/ 24小时/ 3600秒=每秒约400页。

  • 峰值QPS = 2 * QPS = 800

  • 假设平均网页大小为500k。

  • 每月10亿页x 500k = 500tb存储空间。如果您不清楚数字存储单元,请再次阅读第2章中的“2的幂”部分。

  • 假设数据存储5年,500tb * 12个月* 5年= 30pb。存储5年的内容需要30pb的存储空间

第二步-提出顶层设计并且获取面试官的支持

一旦需求明确了,我们就继续进行高级设计。受前人对网络爬行研究的启发,我们提出了如图9-2所示的高级设计。

image.png

首先,我们探索每个设计组件以了解它们的功能。然后,我们逐步检查爬虫工作流程。

Seed URLs

web爬虫使用Seed url作为爬行过程的起点。例如,要从一所大学的网站上抓取所有网页,选择种子url的一种直观方法是使用该大学的域名。

为了抓取整个网络,我们需要创造性地选择种子url。一个好的种子URL可以作为一个好的起点,爬虫可以利用它来遍历尽可能多的链接。

一般策略是将整个URL空间划分为更小的URL空间。第一种建议的方法是基于地域的,因为不同的国家可能有不同的热门网站。

另一种方法是基于主题选择种子url;例如,我们可以将URL空间划分为购物、体育、医疗等。种子URL选择是一个开放式的问题。你不需要给出完美的答案。大胆地想。

URL Frontier

大多数现代网络爬虫将抓取状态分为两个:待下载状态和已下载状态。存储要下载的URL的组件称为URL Frontier。

您可以将其称为先进先出(FIFO)队列。有关URL Frontier的详细信息,请参阅深入研究

HTML下载器

HTML下载器从互联网上下载网页。这些URL由URL Frontier提供。

DNS解析器

下载网页时,需要将URL转换为IP地址。HTML下载程序调用DNS解析器来获取URL对应的IP地址。例如,从3/5/2019开始,URL www.wikipedia.org转换为IP地址198.35.26.96。

内容解析器

网页下载后,必须对其进行解析和验证,因为格式错误的网页可能会引发问题并浪费存储空间。在抓取服务器中实现内容解析器将减慢抓取过程。因此,内容解析器是一个单独的组件。

内容重复?

在线研究显示,29%的网页是重复内容,这可能导致相同的内容被多次存储。我们引入了“看到的内容?”的数据结构,以消除数据冗余,缩短处理时间。它有助于检测以前存储在系统中的新内容。为了比较两个HTML文档,我们可以逐个字符地比较它们。然而,这种方法是缓慢和耗时的,特别是当涉及数十亿的网页。完成此任务的有效方法是比较两个网页的哈希值。

内容存储

它是一个存储HTML内容的存储系统。存储系统的选择取决于数据类型、数据大小、访问频率、寿命等因素。磁盘和内存都被使用。

  • 大部分内容存储在磁盘上,因为数据集太大,内存无法容纳。

  • 热点内容保存在内存中以减少延迟。

URL提取器

URL Extractor解析和提取HTML页面中的链接。链路提取流程示例如图9-3所示。通过添加“en.wikipedia.org”前缀将相对路径转换为绝对url。

image.png

URL过滤

URL过滤器排除了某些内容类型、文件扩展名、错误链接和“黑名单”网站中的URL

URL重复?

“URL见过吗?是一种数据结构,它跟踪在边界之前或已经访问过的url。“URL见过吗?有助于避免多次添加相同的URL,因为这会增加服务器负载并导致潜在的无限循环。

布隆过滤器和哈希表是实现“URL看到?”组件。我们不会在这里详细介绍布隆过滤器和哈希表的实现。更多信息请参考参考资料。

URL存储

URL存储存储已访问的URL。

到目前为止,我们已经讨论了每个系统组件。接下来,我们把它们放在一起来解释工作流程。

网络爬虫工作流程 为了更好地说明工作流程,在图9-4所示的设计图中添加了序号。

image.png

步骤1:将种子URL添加到URL边界 步骤2:HTML下载程序从URL边界获取URL列表。

步骤3:HTML Downloader从DNS解析器获取url的IP地址并开始下载。

步骤4:内容解析器解析HTML页面并检查页面是否格式错误。

步骤5:在内容被解析和验证之后,它被传递给“content Seen?””组件。

步骤6:“Content Seen”组件检查HTML页面是否已经在存储中。

  • 如果它在存储中,这意味着不同URL中的相同内容已经被处理。在这种情况下,HTML页面将被丢弃。

  • 如果不在存储中,说明系统之前没有处理过相同的内容。内容被传递给链接提取器。

步骤7:链接提取器从HTML页面中提取链接。

步骤8:将提取的链接传递给URL过滤器。

步骤9:在链接被过滤后,它们被传递到“URL Seen?””组件。

步骤10:“URL Seen”组件检查URL是否已经在存储中,如果是,则在之前处理过,不需要做任何操作。

步骤11:如果一个URL之前没有被处理过,它将被添加到URL边界。

第三步-底层实现

到目前为止,我们已经讨论了高层设计。接下来,我们将深入讨论最重要的构建组件和技术:

  • 深度优先搜索(DFS)与广度优先搜索(BFS)
  • URL边界
  • HTML下载器
  • 鲁棒性
  • 可扩展性
  • 检测和避免有问题的内容

DFS vs BFS

你可以把网络想象成一个有向图,其中网页是节点,超链接(url)是边。爬行过程可以看作是将有向图从一个网页遍历到另一个网页。两种常见的图遍历算法是DFS和BFS。然而,DFS通常不是一个好的选择,因为DFS的深度可能非常深。

BFS通常被网络爬虫使用,并通过先进先出(FIFO)队列实现。在FIFO队列中,url按照它们进入队列的顺序被退出队列。然而,这种实现有两个问题:

  • 来自同一网页的大多数链接被链接回同一主机。图9-5中,wikipedia.com中的所有链接都是内部链接,爬虫忙于处理来自同一主机(wikipedia.com)的url。当爬虫试图并行下载网页时,维基百科服务器将被请求淹没。这被认为是“不礼貌的”。

image.png

  • 标准BFS不考虑URL的优先级。网络很大,并不是每个页面的质量和重要性都是一样的。因此,我们可能希望根据页面排名、网络流量、更新频率等来对url进行优先级排序。

URL Frontier

URL边界有助于解决这些问题。URL边界是存储要下载的URL的数据结构。URL边界是确保礼貌、URL优先级和新鲜度的重要组成部分。参考资料中提到了一些值得关注的关于URL frontier的论文。这些论文的研究结果如下:

礼貌

一般来说,网络爬虫应该避免在短时间内向同一主机服务器发送太多请求。发送太多请求被认为是“不礼貌的”,甚至被视为拒绝服务(DOS)攻击。例如,在没有任何约束的情况下,爬虫每秒可以向同一个网站发送数千个请求。这会使web服务器不堪重负。

加强礼貌的一般思路是从同一主机一次下载一个页面。可以在两个下载任务之间添加延迟。礼貌约束是通过维护从网站主机名到下载(工作线程)线程的映射来实现的。

每个下载线程都有一个单独的FIFO队列,并且只下载从该队列获得的url。礼貌管理设计如图9-6所示。

image.png

  • 队列路由器:它确保每个队列(b1, b2,…bn)只包含来自同一主机的url。

  • 映射表:将每个主机映射到一个队列。

  • FIFO队列b1, b2到bn:每个队列包含来自同一主机的url。

image.png

  • 队列选择器:每个工作线程都映射到一个FIFO队列,并且它只从该队列下载url。队列选择逻辑由queue选择器完成。

  • 工作线程1到n。一个工作线程从同一台主机一个接一个地下载网页。可以在两个下载任务之间添加延迟。

priority

在论坛上随便发一篇关于苹果产品的帖子,其分量与苹果主页上的帖子大不相同。尽管它们都有“Apple”关键字,但对于爬虫来说,首先爬取Apple主页是明智的。

我们根据有用性对URL进行优先排序,这可以通过PageRank[10]、网站流量、更新频率等来衡量。“优先排序器”是处理URL优先级的组件。参考资了解该概念的深入信息。

URL优先级管理的设计如图9-7所示。

image.png

  • 优先排序器:它将url作为输入并计算优先级。

  • 队列f1到fn:每个队列都有一个分配的优先级。高优先级队列被选择的概率更高。

  • 队列选择器:随机选择一个优先级较高的队列。

URL frontier的设计如图9-8所示,它包含两个模块:

  • 前队列:管理优先级
  • 后队列:管理礼貌

image.png

Freshness

网页不断地被添加、删除和编辑。网络爬虫必须定期重新抓取下载的页面,以保持我们的数据集新鲜。重新抓取所有url既耗时又耗费资源。以下列出了一些优化新鲜度的策略:

  • 根据网页的更新历史进行抓取。

  • 优先考虑url并首先更频繁地抓取重要页面。

Storage for URL Frontier

在现实世界的搜索引擎抓取中,URL Frontier的数量可能达到数亿。将所有内容放在内存中既不持久也不可扩展。将所有内容保存在磁盘中是不可取的,因为磁盘很慢;它很容易成为爬行的瓶颈。

我们采用了混合方法。大多数url都存储在磁盘上,因此存储空间不是问题。为了降低从磁盘读取和写入磁盘的成本,我们在内存中维护了用于排队/脱队列操作的缓冲区。缓冲区中的数据定期写入磁盘。

HTML下载器

HTML Downloader通过HTTP协议从互联网上下载网页。

在讨论HTML下载程序之前,我们先看看机器人排除协议

Robots.text

Robots.txt,即机器人排除协议,是网站用来与爬虫通信的标准。它指定允许哪些页面爬虫下载。在尝试抓取网站之前,爬虫应该首先检查相应的robots.txt并遵循其规则。

为了避免重复下载robots.txt文件,我们缓存了该文件的结果。定时下载并保存到缓存中。这是取自www.amazon.com/robots.txt的…

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所示

image.png

2. 缓存DNS解析器

DNS解析器是爬虫程序的瓶颈,因为由于许多DNS接口的同步特性,DNS请求可能需要一些时间。DNS响应时间范围为10ms ~ 200ms。一旦一个爬虫线程执行了对DNS的请求,其他线程就会被阻塞,直到第一个请求完成。维护我们的DNS缓存以避免频繁调用DNS是一种有效的速度优化技术。我们的DNS缓存保存域名到IP地址的映射,并由cron作业定期更新

3. 位置

按地理位置分布抓取服务器。当抓取服务器离网站主机更近时,抓取程序的下载时间会更快。设计局部性适用于大多数系统组件:抓取服务器、缓存、队列、存储等。

4. 短的超时时间

一些web服务器响应缓慢或根本不响应。为了避免长时间的等待,指定了最大等待时间。如果主机在预定义的时间内没有响应,爬虫程序将停止该作业并抓取其他页面。

健壮性

除了性能优化之外,鲁棒性也是一个重要的考虑因素。我们提出了一些方法来提高系统的健壮性:

  • 一致哈希:这有助于在下载器之间分配负载。可以使用一致散列添加或删除新的下载服务器。更多细节请参考第5章:设计一致哈希。

  • 保存爬行状态和数据:为了防止失败,将爬行状态和数据写入存储系统。中断的爬行可以通过加载保存的状态和数据轻松重新启动。

  • 异常处理:在大规模系统中,错误是不可避免的,也是常见的。crawler必须在不使系统崩溃的情况下优雅地处理异常。

  • 数据验证:这是防止系统错误的重要措施。

可扩展性

随着几乎每个系统的发展,设计目标之一是使系统足够灵活以支持新的内容类型。可以通过插入新的模块来扩展爬虫。添加新模块的操作如图9-10所示。

image.png

  • PNG下载模块插入下载PNG文件。

  • 网络监控模块被添加到监控网络和防止版权和商标侵权。

检测并避免有问题的内容

本节讨论冗余、无意义或有害内容的检测和预防

冗余内容

如前所述,近30%的网页是重复的。哈希或校验和有助于检测重复。

爬虫陷阱

爬虫陷阱是一个网页,使爬虫陷入无限循环。例如,无限深度的目录结构如下所示:www.spidertrapexample.com/foo/bar/foo…

数据噪声

有些内容几乎没有价值,例如广告、代码片段、垃圾url等。这些内容对爬虫没有用处,应该尽可能排除。

总结

在本章中,我们首先讨论了一个好的爬虫的特征:可伸缩性、礼貌性、可扩展性和健壮性。然后,提出了设计方案,并对关键部件进行了讨论。

构建一个可扩展的网络爬虫不是一项微不足道的任务,因为网络是巨大的,充满了陷阱。尽管我们已经涵盖了很多话题,但我们仍然错过了很多相关的话题:

  • 服务器端渲染:许多网站使用脚本,如JavaScript, AJAX等来动态生成链接。如果我们直接下载和解析网页,我们将无法检索动态生成的链接。为了解决这个问题,我们在解析页面之前先执行服务器端渲染(也称为动态渲染)。

  • 过滤掉不需要的页面:在有限的存储容量和抓取资源下,反垃圾邮件组件有利于过滤掉低质量和垃圾页面。

  • 数据库复制和分片:像复制和分片这样的技术被用来提高数据层的可用性、可扩展性和可靠性。

  • 水平扩展:对于大规模爬行,需要数百甚至数千台服务器来执行下载任务。关键是保持服务器无状态。

  • 可用性、一致性和可靠性:这些概念是任何大型系统成功的核心。我们在第一章中详细讨论了这些概念。唤起你对这些话题的记忆。

  • 分析:收集和分析数据是任何系统的重要组成部分,因为数据是微调的关键因素。