数据从业者必读:抓取了一千亿个网页后我才明白,爬虫一点都不简单

摘要:互联网上有浩瀚的数据资源,要想抓取这些数据就离不开爬虫。鉴于网上免费开源的爬虫框架多如牛毛,很多人认为爬虫定是非常简单的事情。但是如果你要定期上规模地准确抓取各种大型网站的数据却是一项艰巨的挑战,其中包括网站的格式经常会变、架构必须能灵活伸缩应对规模变化同时要保持性能,与此同时还要挫败网站反机器人的手段以及维护数据质量。流行的 Python 爬虫框架 Scrapy 开发者 Scrapinghub 分享了他们抓取一千亿个网页后的经验之谈。

数据从业者必读:抓取了一千亿个网页后我才明白,爬虫一点都不简单

英文原文:FOR E-COMMERCE DATA SCIENTISTS: LESSONS LEARNED SCRAPING 100 BILLION PRODUCTS PAGES

编者按:互联网上有浩瀚的数据资源,要想抓取这些数据就离不开爬虫。鉴于网上免费开源的爬虫框架多如牛毛,很多人认为爬虫定是非常简单的事情。但是如果你要定期上规模地准确抓取各种大型网站的数据却是一项艰巨的挑战,其中包括网站的格式经常会变、架构必须能灵活伸缩应对规模变化同时要保持性能,与此同时还要挫败网站反机器人的手段以及维护数据质量。流行的 Python 爬虫框架 Scrapy 开发者 Scrapinghub 分享了他们抓取一千亿个网页后的经验之谈

数据从业者必读:抓取了一千亿个网页后我才明白,爬虫一点都不简单

现在爬虫技术似乎是很容易的事情,但这种看法是很有迷惑性的。开源的库/框架、可视化的爬虫工具以及数据析取工具有很多,从网站抓取数据似乎易如反掌。然而,当你成规模地在网站上抓东西时,事情很快就会变得非常棘手。

自 2010 年以来抓取超过 1000 亿个产品页面,我们将会通过系列文章来分享从中学到的经验教训,让你深入了解从电子商务商店中规模析取数据时所面临的挑战,并且跟你分享应对这些挑战的某些最佳实践。

本文是该系列文章的第一篇,在这里我们将提供规模抓取产品数据所面临主要挑战的概览,以及 Scrapinghub 从抓取 1000 亿产品页面中学到的经验教训。

成立于 2010 年的 Scrapinghub 是领先的数据析取公司之一,也是当今最健壮和流行的 web 爬虫框架 Scrapy 的作者。目前 Scrapinghub 每月抓取许多全球最大型电子商务公司的页面数超过 80 亿(其中 30 亿是产品页面)。

对于那些对规模爬取网页技术感兴趣但对要不要建立专门的 web 爬取团队或者外包给专门的 web 爬取公司的人来说,最好看看这个免费指南,企业 web 爬虫:规模化 web 爬取技术指南

规模爬取技术为什么重要?

跟标准的 web 爬取应用不一样的是,规模爬取电子商务产品数据有一项独特挑战使得 web 抓取要困难许多。

本质上这些挑战可归结为两件事情:速度和数据质量。

由于时间通常是限制因素,规模抓取要求你的爬虫要以很高的速度抓取网页但又不能拖累数据质量。对速度的这张要求使得爬取大规模产品数据变得极具挑战性。

数据从业者必读:抓取了一千亿个网页后我才明白,爬虫一点都不简单

挑战#1——草率而且总是在变的网站格式

这一点很明显但也许不是最性感的挑战,但是草率而一直在变的网站格式是目前为止你在规模析取数据时将会面临的最大挑战。这未必是因为任务的复杂性,而是由于你要投入的时间和资源。

如果你花过时间开发过电子商务商店的爬虫的话,你就会知道电子商务网站代码之草率是一种流行病。这可不仅仅是 HTML 完构性或者偶尔的字符编码问题。这些年来我们遇到过形形色色的问题——HTTP 响应代码的误用,损坏的 JavaScript 代码,或者 Ajax 的误用:

  • 停掉产品时移除页面的商店在网站升级后突然间会在 404 错误处理程序返回 200 响应码。

  • 不恰当的 JSON 转义破坏了部分页面的 JavaScript 代码(比如‘b0rk’d’),导致你需要用正则表达式来抓取那部分数据。

  • 滥用 Ajax 调用的商店以至于你只能靠渲染该页面(这会导致爬取慢很多)或者模仿 API 调用(导致要付出更多的开发努力)来获得数据。

像这样草率的代码会导致编写爬虫非常痛苦,但也会使得可视化爬取工具或者自动析取不再可行。

在规模爬取的时候,你不仅要浏览成百上千个有着草率代码的网站,还将被迫应对不断演变的网站。一条好的经验法则是要预计你的目标网站每隔 2 到 3 个月就会发生让你的爬虫工作不了的变化。

这也许看起来不像是多大的事,但是当你规模抓取时,那些事件就会累积。比方说,Scrapinghub 有一个规模比较大的电子商务项目大概有 4000 个爬虫抽取约 1000 个电子商务网站,意味着每天可能会经历 20 到 30 次爬虫失败。

而且网站在不同地区、语言的变化,A/B测试以及包装/定价的派生也会制造出各种问题导致爬虫失败。

没有容易的解决方案

不幸的是,不存在银弹可以彻底解决这些问题。很多时候这只是随着规模而扩大投入更多资源到你的项目上才能解决的事情。再拿上一个例子来说吧,那个项目有 18 名全职的爬虫工程师以及 3 名专职的 QA 工程师来确保客户总能得到可靠的数据流。

不过,你的团队有经验以后就会学会如何开发出更加健壮的爬虫,从而检测并处置目标网站格式中的异常。

如何处理目标网站有各种布局可能的情况呢?用多个爬虫也许不是最好的做法,我们的最佳实践是只用一个产品爬虫来处理不同页面布局个各种可能规则和模式。你的爬虫可配置性越强越好。

尽管这些实践会让你的爬虫更加复杂(我们有些爬虫有好几千行),但它会确保你的爬虫更容易维护。

由于大多数公司日常都需要析取产品数据,等待几天让你的工程团队修复任何坏掉的爬虫不是可选项。当出现这些情况时,Scrapinghub 会利用自己开发的基于机器学习的数据析取工具来作为后备,直到爬虫修复好。这个基于 ML 的析取工具会自动识别目标网站的目标字段(产品名称、价格、货币单位、图像、SKU 等)并且返回想要的结果。

我们会在未来几周之内发布这项工具以及相关的指导文章,告诉大家如何将机器学习用到你的数据析取过程当中。

挑战 2:可伸缩的架构

你将面临的第二个挑战是建设一个可随每日请求数增长而扩充且性能不会下降的爬虫基础设施。

在规模析取产品数据时,一个串行爬取的简单 web 爬虫是不堪此任的。通常一个串行的 web 爬虫会循环发出请求,每一项请求都要 2 到 3 秒钟完成。

如果你的爬虫每天发出的请求数不到 40000 的话这种做法是没有问题的。然而,超过这个点你就得过渡到一种让你每天可以完成数百万请求而不会性能下降的爬虫架构。

这个话题得用一篇文章才能说得清楚,未来几周我们将发布一篇专门的文章来讨论如何设计和开发高吞吐量的爬取架构。然而,本节的剩余部分我们将讨论一些高级原则和最佳实践。

正如我们讨论过那样,在规模爬取产品数据时速度是关键。你需要确保在时间阈值范围内(通常是 1 天)可以找到并且爬取所有要求的产品页面。为此你需要做以下一些事情:

将产品发现与产品析取分开

为了规模爬取产品数据你需要将你的产品发现爬虫与产品析取爬虫分开。

产品发现爬虫的目标应该是让它浏览目前产品目录(或者“货架”)然后存储该目录下的产品 URL 供产品析取爬虫使用。

这个可以靠 Scrapinghub 开发的开源工具 Frontera 之类的爬虫前端辅助完成。尽管 Frontera 原先的目的是配合 Scrapy 使用的,但它其实完全是不可知论者,可用于任何爬虫框架或者独立项目。在这篇文章中,我们分享了如何利用 Frontera 来规模抓取 HackerNews 的东西。

分配更多资源给产品析取

由于每一个产品目录“货架”可包含 10 到 100 种产品,而且析取产品数据需要的资源要比析取产品 URL 更多,发现爬虫通常运行要比产品析取爬虫更快。这种情况下,你需要有多个析取爬虫来对应每一个发现爬虫。一条好的经验法则是每 10 万个页面分配一个析取爬虫。

挑战 3:维护吞吐量性能

一级方程式的目标是将车上一切不必要的载荷都剔除掉,并且以速度之名将引擎最后一丝马力都榨干,从这个意义上来说规模抓取可以跟一级方程式相比较。规模 web 抓取也是一样的道理。

在析取大量数据时,在现有硬件资源条件下,你总是会想方设法要寻找请求周期最小化爬虫性能最大化的手段。这一切都是希望你能给每个请求节省下来那么几微秒的时间。

为此你的团队需要对 web 爬取框架、代理管理以及所使用的硬件具备深刻理解,这样才能对它们进行调整以优化性能。你还需要关注:

爬取效能

规模爬取时你应该始终把焦点放在以尽量少的请求析取所需数据上。任何额外请求或者数据析取都会放缓你爬取网站的节奏。在设计你的爬虫时请记住这些提示:

  • 作为最后一招,仅使用无界面浏览器,比如 Splash 或者 Puppeteer 来渲染 JavaScript。用无界面浏览器渲染 JavaScript 同时爬取是非常耗资源的,会严重影响爬取的速度。

  • 如果你可以从货架页面(比如产品名称、价格、评分等)获得所需的数据而不需要向独立的产品页面提出请求的话,那就不要向产品页面发出请求。

  • 不要请求或者析取图像,除非迫不得已。

挑战 4:反机器人的对策

如果你批量抓取电子商务网站的话一定会遇到采用反机器人对策的网站。

规模小一点的网站其反机器人对策就是些基本手段(屏蔽发送请求过量的 IP)。然而,较大的电子商务网站,比如 Amazon 等,会采用复杂的反机器人对策,比如 Distil Networks、Incapsula 或者 Akamai 等来使得析取数据困难许多。

代理

了解到这一点之后,任何项目想要规模抓取才数据,首要的基本需求就是得用代理。规模抓取数据时你需要可观的代理清单,而且需要实现必要的 IP 轮转、请求限制、会话管理以及黑名单逻辑来预防代理被屏蔽。

或者除非你有或者愿意用一支规模可观的团队管理你的代理,否则的话你应该把抓取流程中的这一部分外包出去。提供各种水平服务的代理服务有很多。

然而,我们的建议是找一家能够提供单个代理配置端点并且将所有的代理管理复杂性隐藏起来的代理提供商。在没有重新发明轮子、开发和维护自己的内部代理管理基础设施的情况下规模抓取就已经很耗资源了。

大多数大型电子商务公司都采用这种做法。一些全球最大型的电子商务网站采用 Scrapinghub 开发的智能下载器 Crawlera,这个东西的代理管理完全是外包的。当你的爬虫每天要发出 2000 万条请求时,把注意力放在分析数据而不是管理代理上会有意义得多。

代理以外

不幸的是,光靠使用代理服务并不足以确保你能规避大型电子商务网站的反机器人对策。越来越多的网站正在利用复杂的反机器人对策来监控你的爬虫行为,检测其是否真人访客。

这些范机器人对策不仅使得爬取电子商务网站越来越困难,而且克服这些手段如果做得不对的话也会严重拖累爬虫性能。

这些机器人对策有很大一部分使用到了 JavaScript 来确定请求是否来自于爬虫还是人(Javascript 引擎检查、字体枚举、WebGL 与 Canvas 等)。

不过正如前面所述,规模爬取时你希望限制可编写脚本的无界面浏览器(Splash 或者 Puppeteer 等)的使用,因为渲染页面的任何 JavaScript 都非常耗资源并且放慢爬取网站的速度。

这意味着为了确保你能取得必要的吞吐量让爬虫提交每天的产品数据,你往往需要痛苦地对目标网站采用的反机器人对策进行逆向工程,并且在不使用无界面浏览器的情况下设计你的爬虫抵消那些对策。

挑战 5:数据质量

从数据科学家的角度来说,任何网站爬取项目最重要的考虑是析取数据的质量。规模爬取只会令这一关注变得更加重要。

当每天都要析取数百万数据点时,想靠人工来验证数据是否干净和完整是不可能的。变脏或者不完整的数据很容易就会流入到你的数据流里面,进而破坏了数据分析的效果。

尤其是在抓取同一个的不同版本(不同的语言、地区等)或者不同商店上的产品时更是如此。

在爬虫开发的设计阶段,需要进行仔细的 QA 流程,爬虫代码要经过同行评审和测试以确保用最可靠的方式析取到想要的数据。确保最高数据质量的最好的办法是部署一套自动化 QA 监控系统。

作为任何数据析取项目的一部分,你需要计划和开发一套监控系统,这套系统将提醒你任何不一致的数据以及发生的爬虫错误。Scrapinghub 开发了一个机器学习算法来检测:

  • 数据验证错误——每一个数据项都有定义好的遵循一致模式的数据类型和值。我们的数据验证算法会提醒项目的 QA 团队任何与预期数据类型不一致的数据项,然后再进行人工检查、提醒已验证或者标记为错误。

  • 产品差异化错误——从同一网站的多个版本(不同语言、地区)爬取相同产品数据时,有可能变量或者像产品重量或者尺寸这样本该是固定值的数据项也会不一样。这可能是网站反机器人对策向你的一到多个爬虫提供篡改信息的结果。再次地,你需要算法来识别和标记类似这样的情况。

  • 基于数量的不一致性——另一个关键的监控脚本是检测返回记录的任何异常变化。这可能预示网站已经做出改变或者你的爬虫被提供了篡改的信息。

  • 网站变化——目标网站发生的结构性改变是爬虫失效的主要原因。我们的专用监控系统会监控到这一点。该工具会对目标网站进行频繁的检查,确保自从上次抓取之后没有发生任何变化。如果改变被发现,它也会发出通知。

我们会在稍后的文章中专门讨论自动质量保证的细节。

总结

正如你所看到那样,规模抓取产品数据会面临一系列的独特挑战。希望这篇文章能够让你更加意识到相关挑战,并且就如何解决这些问题获得启发。

然而,这只是本系列文章的第一部分,所以如果你感兴趣的话可以注册我们的电子邮件列表,一旦下一篇文章发表了我们会第一时间通知你。

来自: 36氪

扩展阅读

冰山一角 管窥中国互联网的地下世界
一起围观新周刊理科男
360黑匣子之谜 - 奇虎360“癌”性基因大揭秘
大数据全栈式开发语言 – Python
这些年,这些挖掘机算法,这些反思

为您推荐

中文热门开源项目Top100,你知道多少?
十年后的首次翻新:全球第四大网站 Reddit 重新设计的内幕故事
GitHub上整理的一些工具
这些年,这些挖掘机算法,这些反思
dRuby 的机制与实现

更多

程序员
IT业界