【爬虫系统】设计核心
【爬虫系统】设计核心
学习核心
- 如何设计一个【爬虫】系统?(系统的核心功能)
- 沟通对齐
- ① 需求分析
- ② 请求量分析:基于5k/s、5k/s-10w/s、10w/s+的不同请求量场景分析
- ③ 精准度分析:一般情况下MySQL+缓存、Redis方案,或者多个数据存储结合应用
- 如果是精准度要求不高,可以采取内存计算、Redis当存储等方式,允许小概率少量数据丢失
- 如果精准度要求比较高,那么就需要采取更可靠的方式来兜底,比如MySOL
- ④ 难点分析
- 整体设计
- ① 服务设计(分层设计)
- ② 存储设计(存储选型)
- ③ 业务设计(业务流程)
- 要点分析(或难点分析)
- ① 存储结构:核心数据存储结构分析
- 存储选型
- 数据结构设计优化方向
- ② 高并发:异步化(内存聚合+异步写库、引入MQ组件)
- ③ 高精准:少写、多写、数据一致性 等
- .... 围绕功能核心要点展开叙述
- ① 存储结构:核心数据存储结构分析
- 总结陈述
学习资料
🟢【爬虫系统】场景核心
网络爬虫被称为机器人或蜘蛛。搜索引擎广泛使用它来发现 Web 上的新内容或更新内容。内容可以是网页、图像、视频、PDF 文件等。网络爬虫首先收集一些网页,然后按照这些页面上的链接收集新内容。下图显示了抓取过程的可视化示例
可以理解为全世界的页面事实上是一个通过超链接连接的巨大网络,其中每个页面都包含一些指向其他页面的URL链接,这些有指向的链接将全部网页构成一个有向(网络)图。如下图所示,每个节点是一个网页,每条有向的边就是一个超链接。
而爬虫的主要工作就是从某个节点页面出发,将遍历到的链接网页下载保存起来,在这个过程中会将每个遍历节点页面指向的关联节点一并遍历(可以理解为一层层往下剥),理论上可以遍历范围内的所有网页。因此,对于爬虫系统而言,它并不需要事先知道数千亿的URL,然后再去下载,而是只需要知道一小部分URL(也就是所谓的种子URL),然后从这些种子URL开始遍历,理想情况下就可以得到全世界的URL,并下载全世界的网页
爬虫有多种用途:
- 搜索引擎索引:这是最常见的用例,通过爬虫收集网页以为搜索引擎创建本地索引
- 例如,Googlebot 是 Google 搜索引擎背后的网络爬虫
- 网络存档:这是从网络收集信息以保存数据以备将来使用的过程
- 例如,许多国家图书馆运行爬虫来存档网站(著名的例子是美国国会图书馆和欧盟网络档案馆)
- 网络挖掘:网络的爆炸式增长为数据挖掘提供了前所未有的机会
- 网络挖掘有助于从 Internet 中发现有用的知识(例如,顶级金融公司使用爬虫下载股东大会和年度报告以了解公司的关键举措)
- 网络监控:这些爬虫有助于监控 Internet 上的版权和商标侵权行为
- 例如,Digimarc利用爬虫来发现盗版作品和报告
🚀【爬虫系统】场景实战
1.沟通对齐
此处的沟通对齐方向,主核心方向是需求分析、请求量分析、精准度分析、难点/要点分析,可能还有涉及到其他的一些容量、设计等方面的对齐
① 需求分析
【爬虫】系统核心功能
爬虫系统的设计可以从以下几个方面切入
- 爬虫的目的?(例如搜索引擎索引、数据挖掘或其他用途)=》搜索引擎索引
- 爬虫每个月收集多少网页?=》10 亿页
- 包括哪些内容类型?仅 HTML 还是其他内容类型(如 PDF 和图像)=》爬取目标:HTML
- 是否考虑新增或编辑的网页?=》应该考虑新添加或编辑的网页
- 需要存储从网络上爬取的 HTML 页面吗?=》提供存储,存储时长最多5年
- 如何处理内容重复的网页?=》忽略重复网页
除却上述基础点,还可扩展优秀网络爬虫的特征
- 可伸缩性(Scalability):为了适配未来可增长的爬取需求,系统需考虑灵活部署机制,通过扩大集群规模,增强其爬取网页的速度(并行爬取,分布式爬取概念)
- 鲁棒性(Robustness):网络充满了陷阱。错误的 HTML、无响应的服务器、崩溃、恶意链接等都很常见,爬虫必须处理所有这些边缘情况
- 礼貌(Politeness):爬虫不应该在短时间间隔内向网站发出太多请求,且需遵循互联网爬虫协议(即目标网站的robots.txt协议),不爬取目标网站禁止爬取的内容
- 去重:一方面需要对超链接URL去重,相同的URL不需要重复下载;另一方面还要对内容去重,不同URL但是相同内容的页面也不需要重复存储
- 可扩展性(Extensibility):系统非常灵活,因此只需进行最少的更改即可支持新的内容类型。比如以后要抓取图片文件,应该不需要重新设计整个系统
业务流程分析
② 性能指标估算
以下估算基于许多假设:
- 假设每月下载 10 亿个网页
- QPS: 1,000,000,000/30天/24小时/3600秒=400页/秒。1,000,000,000/30天/24小时/3600秒=400页/秒
- 峰值QPS=2×QPS=800
- 假设平均网页大小为 500k
- 10亿页×500k=每月500TB10亿页×500k=每月500TB 存储空间
- 假设数据存储五年, 500TB×12个月×5年=30PB500TB×12个月×5年=30PB。需要 30 PB 的存储来存储五年的内容
④ 难点/要点分析
2.整体设计(架构设计)
① 服务设计(分层设计)
- 各组件含义
seed URLs
:网络爬虫使用种子URL作为起点,一个好的种子起点为爬虫效果提供支撑,因此要考虑从不同方向切入选择- 思路1:基于位置,不同国家可能有不同的流行网站,可以根据位置进行抽选
- 思路2:基于主题,将URL空间划分为购物、体育、医疗保健等领域
URL 调度器
:URL调度器从种子URL中选择一些URL进行处理(核心取决于URL调度器算法)HTML 下载器
:HTML Downloader 从互联网上下载网页HTML 内容解析器
:HTML Parser 用于解析网页内容是否正确(避免一些错误、异常网页干扰进程,错误的网页可能会引发异常问题或者浪费存储空间)Content seen?
:网页内容去重(此处校验网页内容是否出现超出一定重复度比例,以消除数据冗余,缩短处理时间)- HTML 比较 可以基于逐个字符比较,但是这个方式非常耗时;因此针对涉及到数十亿的网页比较时,选用比较这两个网页的哈希值来进行重复判定
URL 提取器
:URL Extractor(网址提取器)用于 从 HTML 页面解析和提取链接网址过滤器
:URL Filter 用于排除某些内容类型、文件扩展名、错误链接和“黑名单”站点中的 URLURL seen?
:"URL Seen? "是一个数据结构,用于跟踪之前被访问过的或已经在Frontier中的URL。"URL Seen? "有助于避免多次添加相同的URL,因为这可能会增加服务器负载并导致潜在的无限循环- 布隆过滤器和哈希表是实现 "URL Seen? "组件的常用技术
存储 Storage
:存储系统的选择取决于诸如数据类型、数据大小、访问频率、寿命等因素,磁盘和内存都被使用。此处拆分两个存储便于理解,一个是用于存储网页内容,一个是用于URLContent Storage
:内容存储(存储HTML内容的存储系统),热门内容保存在内存中以减少延迟,其余大部分内容存储在磁盘上URL Storage
:存储已经访问过的URL
- 爬虫流程分析:结合图示理解爬虫流程
- ① 选择种子URL作为起点,将其添加到URL调度器
- ② 通过URL调度器选出要进行遍历的URL列表,通过DNS域名解析获取到真正的访问IP
- ③ HTML 下载器从DNS解析器获取到URL的IP地址并开始下载
- ④ HTML 内容解析器解析文件内容(验证、解析),确认无误后传递给
Content seen?
组件 Content seen?
组件检查页面是否已在存储中- 如果已存在,则丢弃该页面(避免重复解析)
- 如果不存在,则将该页面加入存储(对应⑤),并执行后续的提取、解析操作 (对应⑥)
- ⑦ 网址提取器从HTML页面中提取URL网址,并传递给过滤器进行过滤
- ⑧ 网址过滤器会过滤掉一些"坏网站",然后将过滤后的URL传递给
URL seen?
组件 URL seen?
组件会进一步校验URL是否存在于存储中- 如果已存在,则丢弃该URL(已存在说明该URL已经被处理过)
- 如果不存在,则将该URL加入存储(对应⑨),加入URL调度器(对应⑩),等待后续的调度流程
② 存储设计(存储选型)
③ 业务设计(业务流程)
3.要点分析
从下述几个方面切入爬虫系统的核心设计(构建组件和核心技术)
- 深度优先搜索 (DFS) 与广度优先搜索 (BFS)
- URL Frontier(URL 调度器,核心调度算法)
- HTML Downloader(HTML 下载器)
- 鲁棒性(Robustness)
- 可扩展性(Extensibility)
- 检测并避免有问题的内容
① DFS VS BFS
可以将网络想象成一个有向图,其中网页作为节点,而关联的超链接(URL)作为边,抓取过程可以被视为从一个网页到其他网页的有向图的遍历。两种常见的图形遍历算法是DFS和BFS。然而,DFS通常不是一个好的选择,因为DFS的深度可能很深。因此BFS在网络爬虫场景中并经常应用
BFS 通常被网络爬虫使用,并通过先进先出 (FIFO) 队列实现。在 FIFO 队列中,URL 按照它们入队的顺序出队。但是,这种实现有两个问题:
- (1)频繁回源访问不礼貌:来自同一网页的大多数链接都链接回同一主机
- 例如假设爬取维基百科,但wikipedia.com 中的所有链接都是内部链接,使得爬虫忙于处理来自同一主机(wikipedia.com)的 URL。当爬虫试图并行下载网页时,维基百科服务器将被请求淹没。这被认为是“不礼貌的”
- (2)无法支持URL的优先级:标准的BFS没有考虑到一个URL的优先级。网络很大,不是每个页面都有相同的质量和重要性。因此,我们可能希望根据页面排名、网络流量、更新频率等来确定URL的优先级
BFS 遍历的思路:由于待下载URL集合存储在文件中,URL下载服务器只需要向待下载URL集合文件尾部追加URL记录,而URL调度器只需要从文件头顺序读取URL,这样就天然实现了先进先出的广度优先算法

② URL Frontier(URL 调度器,核心调度算法)
URL Frontier 是确保礼貌、URL 优先级和新鲜度的重要组成部分
(1)礼貌性 & URL 优先级
一般来说,网络爬虫应该避免在短时间内向同一个托管服务器发送过多的请求。发送过多请求会被视为“不礼貌”,甚至被视为拒绝服务 (DOS) 攻击。例如,在没有任何限制的情况下,爬虫可以每秒向同一个网站发送数千个请求。这会使 Web 服务器不堪重负。
【解决思路1】:强制礼貌的一般想法是一次从同一主机下载一个页面,可以在两个下载任务之间添加延迟
【解决思路2】:礼貌约束是通过维护从网站主机名到下载(工作)线程的映射来实现的。每个下载线程都有一个单独的 FIFO 队列,并且只下载从该队列中获得的 URL
通常针对一个网站,一次只下载一个页面,所以URL调度器需要将待下载URL根据域名进行分类。此外,不同网站的信息质量也有高低之分,爬虫应该优先爬取那些高质量的网站。优先级和域名都可以使用不同队列来区分
① 优先级分类器会根据网页内容质量将域名分类(例如PageRank质量排名算法),并为不同质量等级的域名设置不同的优先级,然后将不同优先级记录在“域名优先级表”中
② 按照广度优先算法,URL列表会从待下载URL集合文件中装载进来。根据“域名优先级表”中的优先级顺序,优先级分类器会将URL写入不同的队列中
③ 优先级队列选择器会根据优先级使用不同的权重,从这些优先级队列中随机获取URL,这样使得高优先级的URL有更多机会被选中,而被选中的URL都会交由域名分类器进行分类处理。域名分类器的分类依据就是“域名队列映射表”,这个表中记录了不同域名对应的队列,所以域名分类器可以顺利地将不同域名的URL写入不同的域名队列中
④ 最后,域名队列选择器将轮询所有的域名队列,从其中获得URL并分配给不同的URL下载服务器,进而完成下载处理
(2)新鲜度
网页不断被添加、删除和编辑。网络爬虫必须定期重新抓取下载的页面以保持我们的数据集最新。重新抓取所有 URL 既耗时又耗费资源。下面列出了几种优化新鲜度的策略:
- 根据网页的更新历史重新抓取
- 对URL进行优先排序,优先和频繁地重新抓取重要页面
(3)缓存区
在搜索引擎的真实世界抓取中,frontier 的 URL 数量可能达到数亿。将所有内容都放在内存中既不耐用也不可扩展。将所有内容都保存在磁盘中是不可取的,因为磁盘很慢;它很容易成为抓取的瓶颈。可以考虑采用混合方法,让大多数 URL 都存储在磁盘上,因此存储空间不是问题。为了降低从磁盘读取和写入磁盘的成本,在内存中维护缓冲区以进行入队/出队操作,缓冲区中的数据会定期写入磁盘
③ HTML Downloader(HTML 下载器)
(1)Robots.txt
HTML下载器使用HTTP协议从互联网上下载网页,既然涉及到爬虫下载,那么必须要遵守规则,也就是所谓的Robots排除协议
Robots.txt,称为Robots排除协议,是网站用来与爬虫沟通的标准。它规定了爬虫可以下载哪些页面。在尝试爬行一个网站之前,爬虫应首先检查其相应的robots.txt,并遵守其规则。为了避免重复下载 robots.txt 文件,我们对该文件的结果进行了缓存。该文件会定期下载并保存到缓存中。下面是取自https://www.amazon.com/robots.txt 的robots.txt文件的一个片段。一些目录,如creatorhub,是不允许谷歌机器人访问的。
User-agent: Googlebot
Disallow: /creatorhub/*
Disallow: /rss/people/*/reviews
Disallow: /gp/pdp/rss/*/reviews
Disallow: /gp/cdp/member-reviews/
Disallow: /gp/aw/cr/
(2)性能优化
⚽ 分布式抓取
为了实现高性能,抓取工作被分配到多个服务器,每个服务器运行多个线程。URL空间被分割成更小的部分;因此,每个下载器负责URL的一个子集

⚽ 缓存DNS解析器
DNS解析器是爬虫的一个瓶颈,因为由于许多DNS接口的同步性,DNS请求可能需要时间。DNS响应时间从10ms到200ms不等。一旦爬虫线程对DNS进行了请求,其他线程就会被阻断,直到第一个请求完成。维护DNS缓存以避免频繁调用DNS是一种有效的速度优化技术。DNS缓存保持域名到IP地址的映射,并通过cron作业定期更新
⚽ 位置
按地理分布抓取服务器。当爬行服务器离网站主机较近时,爬行者会体验到更快的下载时间。设计定位适用于大多数系统组件:抓取服务器、缓存、队列、存储等
⚽ 短暂超时
有些网络服务器响应缓慢,或者根本不响应。为了避免漫长的等待时间,指定了一个最大的等待时间。如果一个主机在预定的时间内没有反应,爬虫将停止工作并抓取一些其他的网页
④ 鲁棒性(Robustness)
除了性能优化,鲁棒性也是一个重要的考虑因素,下述提出了一些提高系统鲁棒性的方法
- 一致性哈希:这有助于在下载者之间分配负载,可以使用一致性哈希添加或删除新的下载服务器
- 保存爬行状态和数据:为了防止失败,爬行状态和数据被写入存储系统。 通过加载保存的状态和数据,可以轻松地重新启动中断的爬网。
- 异常处理:错误在大型系统中是不可避免的,也是常见的。 爬虫必须在不使系统崩溃的情况下优雅地处理异常。
- 数据校验:这是防止系统出错的重要措施
⑤ 可扩展性(Extensibility)
结合上述架构图可以看到,URL 抓取器可以通过插入新的模块来支持扩展,例如引入图片下载模块、网络监控模块等
- PNG下载器模块是用于下载PNG文件的插件
- 增加了网络监控模块,以监控网络并防止版权和商标侵权
⑥ 检测并避免有问题的内容
冗余内容:如前所述,近30%的网页是重复的。哈希值或校验和有助于检测重复[11]。
搜索引擎蜘蛛陷阱:搜索引擎蜘蛛陷阱是导致爬虫陷入无限循环的网页。 例如,一个无限深的目录结构如下:
http://www.spidertrapexample.com/foo/bar/foo/bar/foo/bar/...
可以通过设置 URL 的最大长度来避免此类蜘蛛陷阱。但是,不存在检测蜘蛛陷阱的万能解决方案。 包含蜘蛛陷阱的网站很容易识别,因为在此类网站上发现的网页数量异常多。 很难开发自动算法来避免蜘蛛陷阱; 但是,用户可以手动验证和识别蜘蛛陷阱,并从爬虫中排除这些网站或应用一些自定义的 URL 过滤器垃圾数据:有些内容价值很小或没有价值,例如广告、代码片段、垃圾邮件 URL 等。这些内容对爬虫没有用,应尽可能排除。
4.总结陈述
- 深刻总结
- 要点牵引
- 收尾请教
爬虫的特征:可伸缩性、礼貌性、可扩展性和健壮性。 提出了设计方案并讨论了关键组件。 构建可扩展的网络爬虫并不是一项简单的任务,因为网络非常庞大且充满陷阱。 即使涵盖了所有主题,仍然遗漏了许多相关的讨论要点:
- 服务器端渲染:众多的网站使用JavaScript、AJAX等脚本来即时生成链接。如果直接下载并解析网页,将无法检索到动态生成的链接。为了解决这个问题,在解析网页之前先进行服务器端的渲染(也叫动态渲染)
- 过滤不需要的页面:有限的存储容量和抓取资源,反垃圾信息组件有利于过滤掉低质量和垃圾页面
- 数据库复制和分片:复制和分片等技术用于提高数据层的可用性、可扩展性和可靠性
- 水平扩展:对于大规模爬取,需要数百甚至数千台服务器来执行下载任务。 关键是保持服务器无状态
- 可用性、一致性和可靠性:这些概念是任何大型系统成功的核心
- 分析:收集和分析数据是任何系统的重要组成部分,因为数据是微调的关键要素