tva
← 洞察

如何让大规模浏览器自动化免遭封锁

Playwright 和 Puppeteer 的教程非常丰富。安装、配置选择器、处理异步操作、截取屏幕截图——大多数指南都讲得很清楚。但它们往往略过两个问题:当自动化面向一个主动阻止这类访问的生产网站时,会发生什么;要让它连续数周乃至数月可靠运行,而不只是完成一个下午的概念验证,又需要做些什么。

本文主要讨论从能运行的脚本到能稳定运行的系统之间的差距。这不是教程——相关文档已经存在——而是我们在生产场景中运行浏览器自动化所积累的运维经验。

什么时候浏览器自动化才是合适的工具

使用 Playwright 之前,首先应该问:有没有 API?很多情况下都有,而且使用 API 显然更好。相较于抓取展示层,API 速度更快、运行成本更低、可靠性更高,法律方面的不确定性也更少。

真正必须使用浏览器自动化的场景,比宣传中所说的要少。目标系统没有公开 API,也没有开发计划;虽然有 API,但速率限制或收费结构使其无法满足所需规模;数据位于 SaaS 平台的登录会话之后,而平台的导出功能有限;系统诞生时根本没有考虑程序化访问;或者集成测试必须验证真实浏览器行为,而不能使用模拟的 HTTP 调用。

但实际上,最常见的情况更简单:数据就在浏览器界面中,没有其他获取途径,而拿不到数据的代价高于维护自动化的运维开销。这才是值得采用的判断标准。如果有 API,而且您更愿意用 API,那就用它。当浏览器自动化是唯一可行的选择时,它才是合适的选择。

检测系统实际上如何识别自动化

现代机器人检测同时作用于多个层面,这也是只针对单一层面的应对措施总会失效的原因。

在网络层,TLS 指纹识别通过 ClientHello 消息的特征识别自动化:客户端发送的密码套件顺序、扩展和椭圆曲线。大型 CDN 提供商多年来一直在生产环境中使用 JA3 和 JA4 指纹。由 Playwright 驱动的真实浏览器会发送浏览器自身的 ClientHello,因此 TLS 层主要识别的是不一致的情况:指纹与用户代理声明的浏览器及版本不符,或在浏览器发送请求的同时,还有非浏览器 HTTP 客户端发送请求。

在 HTTP 层,请求头的顺序和值会以细微的方式偏离浏览器的正常表现。真实的 Chrome 按特定顺序发送请求头,自动化环境往往无法精确复现。Accept-Language、Accept-Encoding 和 Sec-Fetch-* 请求头中的信号叠加起来,会形成可区分的模式。

在 JavaScript 层,navigator.webdriver 是最明显的特征——Chromium 在受到程序控制时会设置这个标志。但检测远不止于此。硬件并发数、插件数量、屏幕尺寸,以及特定浏览器 API 是否存在,都能构成复合指纹。Canvas 和 WebGL 在同一硬件配置下会产生一致的渲染结果;使用相同虚拟硬件的浏览器集群会输出相同结果,而这本身就是一个信号。

行为分析则处于更高层面。从页面加载到首次交互的时间分布、鼠标移动轨迹、滚动模式和打字节奏,都带有统计特征。人的行为在自然波动范围内具有一致性。自动化行为也具有一致性,但其变化方式不符合人的自然波动——这种差异可以被检测出来。

商业检测服务会汇总所有这些层面的信号,并使用在人类和机器人流量的大型数据集上训练的模型。只消除一个信号,却在其他方面暴露自动化特征,并不能解决问题。

持久化浏览器配置:最重要的一项改动

多数自动化实现最初都会犯一个错误:把浏览器上下文当作一次性资源。每个新上下文都像是来自一台新机器的首次访问——没有历史记录、没有 cookie,也没有已建立的指纹身份。检测系统默认会更严格地审查新配置。每次运行都从零开始,就意味着每次都要接受这种审查。

解决方法是使用 Chrome 的用户数据目录来持久化浏览器配置。不要为每次会话启动一个新的隔离上下文,而是维护一个包含完整浏览器状态的目录:cookie、localStorage、IndexedDB、缓存的证书和浏览历史。这样,浏览器呈现出的就是已有用户的状态,而非刚安装的状态。

除了持久化,配置预热也很重要。一个配置如果只访问目标网站,而且访问顺序完全固定、没有其他活动,即使此前使用过,看起来仍然很不自然。真实的浏览器配置包含多样的历史记录、多个服务的已保存凭据、许多域名的缓存资源,以及数月正常使用积累的状态。逐步形成这种状态——哪怕只能做到一部分——也能使统计特征明显接近正常用户。

实际操作中,这意味着把配置当作持久资产,而不是用完即弃的上下文。先创建配置,通过多样的浏览活动进行预热,再分配给特定自动化任务。配置一旦遭遇验证或被标记,就停用它,而不是立即重试。管理配置池、跟踪配置状态和运行历史,本身就成了一项基础设施工作。

Patchright 与反检测分支生态

标准 Playwright 会留下反检测系统专门探测的自动化特征,从 --enable-automation 等启动标志,到 Runtime.enable 等 CDP 命令的副作用。JavaScript 层的隐身插件试图在运行时掩盖这些特征:修改 navigator.webdriver、覆盖 navigator.plugins、伪装 Canvas 指纹。但这种方式有一个根本局限:被掩盖的特征仍可通过时序攻击、属性不一致,以及作用于 JavaScript 表层之下的探测技术识别。可以隐藏标志,却无法隐藏“有东西在隐藏它”这一事实。

Patchright 采用了另一种方法。它修改的是 Playwright 驱动程序本身:避免使用 Runtime.enable、禁用 Console 域,并更改默认启动标志,从源头移除这些特征,而不是事后掩盖。这种区别在实践中很重要:没有 JavaScript 层的修改可供检测系统识别。但 Patchright 并非无法检测;其维护者也指出,它的初始化脚本注入可通过时序攻击检测出来。

playwright-extra 生态及其隐身插件提供了运维开销更低的 JavaScript 层替代方案:可接入标准 Playwright 工具,配置也很快。对于检测能力中等的目标,这通常就够了。对于采用企业级检测或在 JavaScript 表层之下进行探测的自定义反机器人基础设施的目标,在驱动程序层进行修改更可靠。

两者都不是永久解决方案。检测系统会根据遇到的工具不断演进。今天能绕过某家检测服务模型的方法,几个月后可能就会被提取为指纹并纳入训练数据。反检测工具的维护开销是真实且持续的,不能靠一次配置就结束。

模拟人的行为,不能只靠随机延迟

常见的实现错误,是把“像人一样”理解成“添加随机延迟”。操作间的均匀随机延迟很容易与人的行为区分,因为人的行为并不是均匀随机的,而是具有反映认知和身体限制的结构、节奏及波动模式。

鼠标移动是最明显的例子。人不会从当前位置沿直线移动到目标。移动路径会受到惯性、目标大小,以及临近目标时修正动作的影响。贝塞尔曲线插值比直线路径或随机抖动更能近似这种行为。速度变化也很重要:朝目标加速、靠近时减速、到达后进行微调。这些不是外观细节,而是检测系统会测量的特征。

打字模式也遵循类似逻辑。打字速度会随单词熟悉度、需要别扭手指动作的字符组合,以及单词之间的思考停顿而变化。所有按键之间都固定间隔 80ms,并不能反映这种分布。基于键盘布局对字符对的输入延迟建模,比任何固定值或均匀随机值都能产生更真实的变化。

人的页面停留时间与内容复杂度相关。一个内容很多的页面,加载后 300ms 就收到点击,这本身就是一个信号。根据渲染内容的长度按比例调整停留时间——采用有结构的变化,而不是随机变化——更接近实际阅读行为。

目标是在统计上与检测模型学习到的人类行为分布无法区分,而不是在哲学意义上完美还原人的行为。理解模型被训练来检测什么,比试图模拟人类行为的每一个方面更有用。

多次运行之间的会话管理

生产环境中的自动化会持续运行,而不是只执行一次。会话会过期,登录会超时,速率限制的影响会累积,状态也会在多次运行之间发生偏移。如何管理这些变化,决定了自动化能否平稳降级,还是会悄然失效。

架构上的选择是:采用只认证一次、按需刷新的长会话,还是采用每次运行都重新认证的短会话。长会话可以减少认证频率——这一点很重要,因为许多系统将高频认证视为机器人信号。短会话在运维上更简单,但会产生更多登录事件。正确选择取决于目标系统会标记什么,以及您的运维模式能够支撑什么。

在运行之间序列化状态,不只是保存主要会话 cookie。浏览器存储、缓存响应和多个域名的会话令牌,都是配置状态的一部分。完整序列化并恢复浏览器状态,才能维持持久化配置所要求的一致性。如果配置在运行之间丢失状态,每次执行都重新建立状态,就无法保持预热后的状态。

重新认证必须避免引发额外审查。同一配置连续进行高频登录尝试,会被标记。在重新认证事件之间留出自然的间隔,并将认证失败视为暂停的信号,而不是立即重试,可以减少登录流程暴露的检测特征。

教程没有讲到的生产环境故障

IP 信誉会让已经解决其他所有问题的自动化实现仍然受阻。数据中心 IP 地址段在大多数机器人检测服务提供商那里的信誉较差,经常需要通过额外验证,或直接被封锁。自动化在本地测试中运行正常,却在生产环境中悄然失效,因为流量来自已被标记多年的 IP 地址段。这不是边缘情况,而是在标准云基础设施上托管自动化时的常见结果。

住宅代理可以解决 IP 信誉问题,却也带来自己的运维问题:可靠性、地理位置一致性、会话保持和成本。代理基础设施会成为一个依赖,需要投入与依赖它的自动化规模相称的运维精力。

静默失败比直接封锁更隐蔽。返回 HTTP 200 却展示中间验证页,或者页面加载成功但呈现的是机器人检测内容而非实际数据,都可能在不触发任何错误处理的情况下失败。监控必须对数据内容进行断言,而不能只确认请求完成,这才是可靠的检测方式。脚本返回空结果却记录成功的情况很常见,也很危险。

软封锁也值得单独讨论。一些检测系统对可疑流量不会直接封锁,而是悄悄降低返回内容的质量:减少结果、遗漏字段,或者提供略有偏差的数据。这类故障比直接封锁更难发现,因为一切看起来都在正常运行。校验预期的数据结构,而不只是检查 HTTP 状态码是否成功,才能发现这类故障。

检测与反检测的持续较量是运维现实。一套成功运行了数月的配置,可能在检测服务更新模型后开始失效——而它们经常更新。建立监控、对数据提取质量下降发出告警,并安排定期重新评估反检测方案,不是过度担忧,而是生产环境中的浏览器自动化所必需的维护方式。

客观评估

生产环境中的浏览器自动化是一项正规的工程工作,确实具有复杂性。从可运行的概念验证到长期可靠运行,涉及 IP 基础设施、浏览器指纹、行为建模、会话管理,以及检测系统演进带来的持续维护。低估这种复杂性的团队,通常是在运维故障中才认识到它,而不是在规划时就做好准备。

在值得做的情况下,它的价值在于:数据无法通过其他方式获得,而数据价值足以支撑相应开销。这需要逐项评估。无论自动化的具体对象是什么,本文描述的运维复杂度都大致相同,因此问题在于,您提取的数据是否值得承担这份开销。

对于正在构建这类自动化系统,或处理无头浏览器部署、代理管理和会话状态存储等基础设施问题的团队,tva 的技术咨询服务能够基于生产实践提供支持。对浏览器自动化基础设施或具体实现难题有疑问?请访问 tva.sg/contact。

相关洞察

延伸阅读