网页爬虫抓取百度图片(本文侧重于的系统设计和实现的部分细节,内容来源于两方面)
优采云 发布时间: 2022-02-06 01:09网页爬虫抓取百度图片(本文侧重于的系统设计和实现的部分细节,内容来源于两方面)
网络爬虫经常被忽视,尤其是与搜索引擎的光环相比,这似乎有点黯淡。我很少看到 文章 或详细说明爬虫实现的文档。但是,爬虫其实是一个非常重要的系统,尤其是在当今数据为王的时代。如果你是一个没有任何原创数据积累的初创公司或项目,那么使用爬虫在互联网上找到那些有价值的数据,然后对数据进行清洗和整理是快速获取数据的重要手段。
本文重点介绍爬虫的系统设计和实现的一些细节。内容来自两个方面。一个是我做了一个多月的爬虫经验,但是我做的爬虫规模不是太大,性能要求不能满足。百度这么高的要求,二是从阅读几个文档中衍生出来的。我找到的关于爬虫系统的文献大多是2000年左右,之后就很少了,说明10年前爬虫的系统设计基本解决了(不是百度刚开始的2000年,说可能是它的爬虫)也指这些文章^-^)。
另外,由于本文关注的是系统问题,所以有些内容就不再赘述了,比如那些隐藏的web数据如何爬取,ajax页面如何爬取,如何动态调整爬取频率等等。
文本
一个正式的、完整的网络爬虫其实是一个非常复杂的系统:首先,它是一个海量数据处理系统,因为它要面对的是整个互联网网页,即使是一个小的、垂直的爬虫,一般它也需要抓取数十亿或数百亿的网页;其次,它也是一个性能要求不错的系统,可能需要同时下载上千个网页,快速提取网页中的url,处理海量的url。重复数据删除等;归根结底,它真的不是一个面向最终用户的系统,所以虽然也非常需要稳定性,但偶尔的宕机也不是什么灾难,也不存在流量激增的情况同时,如果性能在短时间内下降,这不是问题。从这个角度来看,
上图是一个爬虫系统框架,基本收录了一个爬虫系统所需的所有模块。
在任何爬虫系统的设计图中,你都会发现有一个循环,代表了爬虫的一般工作流程:根据URL下载对应的网页,然后提取网页中收录的URL,然后根据到这些新的 URL 下载相应的网页,然后一遍又一遍地重新开始。爬虫系统的子模块都位于这个循环中,完成一个特定的功能。
这些子模块通常包括:
fetcher:用于根据url下载对应的网页;
DNS解析器:DNS解析;
看到的内容:网络内容的重复数据删除;
Extractor:提取网页中的url或者其他一些内容;
URL过滤器:过滤掉不需要下载的URL;
URL Seen:对 url 进行重复数据删除;
URL Set:存储所有的url;
URL Frontier:类似于调度器,决定接下来下载哪些URL对应哪些网页;
提取器和 DNS 解析器
这两个模块是两个非常简单的独立服务:DNS Resolver负责域名解析;fetcher的输入是域名解析后的url,返回的是url对应的网页内容。对于任何网页抓取,都需要调用这两个模块。
对于一般的爬虫来说,这两个模块可以做得很简单,甚至可以合并在一起。但是对于具有高性能要求的系统,它们可能成为潜在的性能瓶颈。主要原因是域名解析和爬取都是耗时的任务。比如抓取网页时,一般延迟在几百毫秒。如果遇到慢网站,可能需要几秒甚至十几秒,会导致工作线程阻塞等待很长时间。如果希望 Fetcher 能够每秒下载数千页或更多页面,则需要启动大量工作线程。
因此,对于性能要求较高的爬虫系统,一般采用epoll或类似的技术,将两个模块改成异步机制。另外,DNS解析的结果也被缓存,大大减少了DNS解析的操作。
看到的内容
互联网上有些网站经常有镜像网站(镜像),即两个网站的内容相同但网页对应的域名不同。这将导致多次重复爬取同一个网络爬虫。为了避免这种情况,对于每一个爬取的网页,首先需要进入 Content Seen 模块。模块会判断网页内容与下载的网页内容是否一致。如果它们一致,则不会发送网页进行进一步处理。这种方法可以显着减少爬虫需要下载的网页数量。
至于判断两个网页的内容是否一致,大致思路是这样的:不是直接比较两个网页的内容,而是计算网页的内容,生成一个FingerPrint(指纹),通常是一个指纹是固定长度。该字符串比网页的正文短得多。如果两个网页的指纹相同,则认为它们的内容相同。
提取器和 URL 过滤器
提取器的工作是从下载的网页中提取它收录的所有 URL。这是一项精细的工作,需要考虑所有可能的 url 样式,例如网页中往往收录相对路径 url,在提取时需要将其转换为绝对路径。
Url Filter 是对提取的 url 进行再次过滤。不同的应用有不同的筛选标准。比如baidu/google搜索一般不会被屏蔽,但是对于垂直搜索或者定向爬取的应用,可能只需要满足一定条件的url,比如不需要图片的url,比如只需要一个图片的url需要具体的网站等。Url Filter是一个与应用密切相关的模块。
看到的网址
Url Seen 用于对 url 进行重复数据删除。之前写过一篇关于url去重的博客,这里不再赘述。
对于一个大型爬虫系统来说,它可能已经有 100 亿或 1000 亿个 URL。如何快速判断是否出现了新的 URL 非常重要。因为大型爬虫系统可能在一秒钟内下载数千个网页,一个网页一般可以提取几十个url,每个url都需要进行去重操作。可以想象,每秒需要执行大量的去重操作。. 因此 Url Seen 是整个爬虫系统中技术含量很高的部分。(Content Seen其实有这个问题)
网址集
url经过前面的一系列处理后,会被放入到Url Set中进行调度获取。由于 url 数量众多,可能只有一小部分会放在内存中,而大部分会写入磁盘。通常,Url Set 的实现是一些文件或数据库。
网址边界
Frontier(不知道为什么叫这个名字)放在最后是因为它可以说是整个爬虫系统的引擎和驱动,组织和调用其他模块。
当爬虫启动时,Frontier 内部会有一些*敏*感*词* url。它首先将*敏*感*词*url发送给Fetcher进行抓取,然后将抓取的网页发送给Extractor提取新的url,然后将新的url重放进入Url Set;而当 Frontier 里面的 url 已经被爬取完毕时,它会从 Url Set 中提取那些没有被爬取的新 url,如此循环往复。
Frontier的调度实现有很多,这里只介绍最常用的实现方式。在此之前,需要稍微解释一下。虽然我们在介绍 Fetcher 的时候说过,一个好的 Fetcher 每秒可以下载几十万个网页,但是对于特定的目标 网站,比如爬虫系统会爬得很慢,而且只会每十秒被抓一次。这是为了确保目标 网站 不会被爬虫捕获。
为了做到这一点,Frontier 内部对每个域名都有一个对应的 FIFO 队列,该队列存储了域名下的 url。Frontier 每次都会从某个队列中拉出一个 url 进行爬取。队列将保存 Frontier 上次调用它的时间。如果时间距离已经超过某个值,则可以再次调用队列。
Frontier 可能同时有上千个这样的队列,它会轮询得到一个可以调用的队列,然后从队列中拉出一个 url 去获取。一旦队列中的所有url都被消费到一定程度,Frontier就会从Url Set中抽取一批新的url,放入对应的队列中。
分散式
当*敏*感*词*爬虫性能不能满足要求时,应考虑使用多台机器组成分布式爬虫系统。分布式爬虫架构其实比想象的要简单得多。一个简单的做法是:假设有N台机器,每台机器都有一个完整的爬虫系统在运行,每台机器的爬虫都在从Extractor模块中获取新的信息。在url之后,根据url的域名进行hash,然后取模N得到结果n,然后将url放入第n台机器的Url Set中。这样,不同的网站 URL就会在不同的机器上处理。
以上是完整爬虫的系统实现。当然,由于篇幅限制,有些细节被省略了。例如,在爬取每个网站之前,爬虫需要读取网站的robots.txt来判断网站是否允许被爬取(京东把robots. txt 前一段时间在 robots.txt 中)。一淘的爬虫被堵住了。需要注意的是robots.txt只是行业协议,在技术上不能强行拒绝爬虫的爬取);再例如,一些网站 提供站点地图,它可以直接从站点地图中获取该网站 的所有url;等等。