大多数抓取指南只优化一件事:拿到数据而不被拦下。这是个合理的目标,但它跳过了决定你的管线能不能撑过第一个月的那部分。一个尽可能快地猛击目标的抓取器不只是无礼,它还很脆弱。它把站点的负载顶上去,触发它拥有的每一条限速和反爬规则,并把一个你本想安静地读取的数据源,变成一个正主动想把你挡在门外的数据源。
反直觉的地方在于:负责任的抓取方式和持久的抓取方式,是同一件事。表现得像一个体贴的客户端——一个尊重限制、分摊负载、只请求它所需之物的客户端——正是那个能停在检测阈值之下、并持续工作的画像。这是与如何避免被封同一枚硬币的礼仪那一面:那篇讲的是别看起来像个机器人,这篇讲的是别表现得像个有害的机器人。做到后者,前者基本就自己解决了。
下面就是负责任、可持久的抓取在实践中的样子。
读 robots.txt,并且认真对待它
每个管理良好的站点都会在其根目录发布一个 robots.txt,声明自动化客户端不应触碰哪些路径,有时还会给一个 Crawl-delay。它不是法律合同,也不是技术屏障,它是站点在唯一为此而建的地方告诉你它的偏好。完全无视它,是”你不是善意访客”的最清楚信号。
务实的立场:在一次运行开始时抓取一次 robots.txt、把它缓存起来,并针对你所呈现的 user-agent 遵守它禁止的路径。如果它指定了爬取延迟,把它当作下限、而不是建议。有些项目出于正当理由会偏离其中某些部分,但”我从没看过”不是其中之一。读它还会告诉你站点把 sitemap 放在哪里,而那往往是比一条链接一条链接地爬取干净得多的 URL 发现方式。
在站点不得不出手之前,先给自己限速
一个抓取器做的最有害的事,就是以网络允许的最快速度发请求。一个按人类流量规模设计的目标,可能被单一个激进的客户端推入响应时间劣化、甚至更糟的境地。那会伤害真实用户,也是让你的整个 IP 段被封的最快方式。
设一个刻意的请求速率并保持在其之下。对大多数活儿来说,每个主机每秒几个请求已绰绰有余,而在较小的站点上更慢更安全。在请求之间加一点随机抖动,而不是固定的节拍器式间隔,好让你的流量看起来不那么机械划一。目标是做众多访客中一个不起眼的访客,而不是某人监控面板上的一个尖峰。如果你需要更多的总吞吐,把它分摊到时间上、分摊到一个轮换池上,而不是提高对任何单一主机的压力。
当站点说不时,就退避
一个 429 Too Many Requests 或一个 503,是服务器在明确告诉你放慢。错误的反应是立刻重试,而那恰恰是一个过载的服务器承受不了的。正确的反应是指数退避:等待、重试,如果再次失败就等更久,每次把延迟翻倍、直到一个上限。当服务器发来 Retry-After 头时就遵守它,它在精确地告诉你该等多久。
这和重试一个真正失败的请求不同。一个断掉的连接或一个超时,是一次值得尽快重试的破碎尝试;而一个 429,是一个正常工作的服务器在请求喘息空间。要区别对待它们。在一个紧凑的循环里盲目重试 429,正是一个抓取器把一条柔性限速变成一次硬封禁的方式。
积极缓存,同一样东西绝不抓两次
最便宜的请求,是你没发出的那个。在扩大规模之前,认真看看你到底重复抓取了多少。缓存响应、用条件请求遵守 ETag 和 Last-Modified、并对你的 URL 前沿去重,通常能把真实的请求量削减很大幅度。每一个被避免的请求,都是你没加到目标身上的负载、你没花掉的带宽,以及一次从未发生的封锁风险事件。
这直接和成本重叠。让你成为更轻的客人的那套纪律,同样削减你的代理带宽账单:只请求你需要的页面,只抓取你用得到的字段,当你只想要 HTML 时就跳过图片和字体这类资源。礼貌和高效是同一套习惯。
在非高峰时段抓取
如果你能控制一个作业何时运行,就在目标清闲时运行它。一个在正午会引人注意的批次,在站点本地时区的深夜低流量面前是隐形的。这就是”在服务器最负担不起时增加负载”和”借用本会闲置的容量”之间的区别。对于大型的周期性拉取,按目标的非高峰窗口来排期,而不是按你的。
在你能做到的地方,诚实地表明身份
这里有一个真实的张力,值得坦白地说清楚。好的抓取礼仪传统上意味着发送一个描述性的 User-Agent,标明你的机器人以及一种联系你的方式,好让注意到你流量的管理员能联系你、而不是伸手去封。许多严肃、合规的爬虫正是这么做的。
与此同时,站点越来越多地不论行为如何、只要自我表明为自动化就封,这把抓取器推向把自己呈现为一个普通浏览器。取决于你的用例,两种立场都站得住脚。站不住脚的是:冒充一个你并非的特定服务,或伪造另一家公司的爬虫。为你的处境选一个诚实的呈现方式,并保持一致。如果你在为一家企业采集数据,拥有一个公开页面来解释你的爬虫做什么、以及如何联系你,不花什么成本,却能化解许多冲突。
只取公开数据,并留意其中包含什么
负责任的抓取意味着公开页面——在不攻破认证墙、也不接受你随后又无视的条款的情况下抵达。登录之后的数据是一个不同的法律与伦理范畴,而抓取本身是否合法在很大程度上取决于这条线。留在它公开的那一侧。
对数据包含什么,要和对它来自哪里一样谨慎。如果页面包含个人信息,你在存储它的那一刻就继承了隐私义务,而大规模采集个人数据会把 GDPR 及类似制度牵扯进来。最干净的姿态是:除非你有具体的合法理由去持有,否则把个人数据排除在你的采集之外,并且不保留你不需要的东西。
代理在哪里发挥作用,以及为什么好代理让你更温和
上面这些没有一条是反对代理的,它们都是主张正确地使用代理。一个高质量的住宅池,正是让你能把一个合理的请求速率分摊到许多 IP 和地理之上、而不是从单一地址把压力集中到一个目标上的东西。用得好,它是一个负载分摊和本地化的工具,而不是把一个站点打得更狠的手段。
池的质量也决定了你到底会不会频繁重试。有良好信誉的干净 IP 能顺畅通过,而被标记的则会遭到挑战,所以一个更好的池意味着更少的失败尝试、更少的重试,以及为同样的数据你所产生的更少总负载。理智地轮换——每个逻辑工作单元用一个身份,而不是在会话中途换一个新 IP(粘性 vs 轮换)——会让你的足迹保持连贯而轻盈。而保持低延迟意味着每个请求都能快速完成并释放,而不是堆积起来。
一份简短清单
- 抓取并遵守
robots.txt;使用它指向的 sitemap。 - 为每个主机设一个刻意的速率并加随机抖动;每秒几个请求通常就够。
- 对
429/503指数退避;遵守Retry-After。别把它和重试一个破碎请求搞混。 - 缓存、用条件请求、去重。最便宜的请求是你跳过的那个。
- 只抓取你需要的页面和字段;跳过你用不到的资源。
- 对大型作业,优先按目标时区的非高峰时段。
- 选一个诚实、一致的身份。绝不冒充另一家公司的爬虫。
- 只要公开数据。把你没有合法理由保留的个人数据排除在外。
- 用一个干净的住宅池来分摊负载,而不是加剧它。
底线
那些能持续运行多年的抓取器,不是最激进的那些,而是目标几乎察觉不到的那些。这里的每一项实践——限速、退避、缓存、非高峰排期、诚实表明身份——都指向同一个方向:取你所需,让站点保持健康,看起来就像你本来就是的那个体贴客户端。这就是抓取的伦理方式,而它恰好也是不会让你被封的方式。
如果你想要一套为分摊负载而非集中负载而建的基础设施,我们的住宅代理跑在一个干净、轮换的池上,而定价页面有按 GB 计费的套餐,好让更轻、更聪明的抓取实际上让你花得更少。