全部文章

深入剖析 Unblocker 标志:`unblocker: true` 的实际作用

一个标志控制三个功能:真实的浏览器 header、匹配的连接签名,以及针对 gzip 和 brotli 的自动解压缩。本文将介绍它的作用和原因。

大多数爬虫在读取任何 header 之前就已经失败了。

服务器会检查客户端在网络上发送的连接级签名,并判断你是一个真正的浏览器,还是一个伪装成浏览器的客户端库。Python requests、Go 的 net/http、普通的 curl:它们在发起连接的瞬间都会暴露独特的指纹。对于严格限制的网站 (Datadome、Akamai、Imperva,以及 Cloudflare 的托管端),在你的 User-Agent 字符串发挥作用之前,它们就会丢弃连接或提供质询页面。

这就是 unblocker: true 在 FourA 上解决的问题。在过去的一个月里,我们确定了使它可靠工作的各个组件。

新增功能

unblocker: true 是任何 /api/single 调用上的单一标志。开启它,我们会做三件事:注入浏览器 header 集、通过匹配真实浏览器网络特征的传输方式发送请求,以及解压缩服务器返回的任何内容 (gzip、brotli、deflate)。前两项功能自测试版起就已提供。第三项 (brotli 自动解压缩) 于 3 月 25 日发布,版本固定功能在第二天上线,以确保 header 和传输方式保持同步。

工作原理

请求如下所示:

curl -X POST "https://api.foura.ai/api/single" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "url": "https://example.com/products",
    "method": "GET",
    "unblocker": true
  }'

底层运行着三个层。

Header 注入。 我们设置完整的浏览器 header 组合:User-Agent、Sec-Ch-Ua、Sec-Ch-Ua-Platform、Sec-Fetch-Site、Sec-Fetch-Mode、Sec-Fetch-Dest、Accept、Accept-Language 和 Accept-Encoding。顺序很重要。真正的浏览器会按特定顺序发出这些 header,而检测库会检查这一点。

连接签名。 我们的传输方式在字节级匹配最新浏览器会话的特征:相同的扩展顺序、相同的密码首选项、相同的握手特性。标准的 curl、Python requests 和 Go 的 net/http 产生的签名会在受保护的基础设施上在几毫秒内被机器标记。

自动解压缩。 当开启 unblocker 时,我们将 Accept-Encoding 设置为 gzip, deflate, br,传输层会解包请求体。你会返回一个解码后的字符串 (如果你传递了 returnBuffer: true,则返回 Buffer)。当网站选择 deflate 而不是 gzip 时,无需手动处理 brotli,也不会出现 header 与 body 不匹配的情况。

为什么版本固定很重要

连接签名是与版本绑定的。浏览器本月的网络级细节与上个月不同,仔细进行指纹识别的网站会注意到这种差异。我们将动态部分固定在一起,因此 header、navigator 对象和连接签名都会报告相同的浏览器版本。

这听起来很麻烦,事实确实如此。在 3 月份的 monorepo 迁移期间,当一个部分自动更新而其余部分失去同步时,我们遇到了不匹配的问题。修复方法包含两次提交:固定动态部分,并且永远不要相信包管理器会自动为你保持同步。

影响

在针对受到严重指纹识别目标 (金融、旅游、受保护的电子商务) 的内部测试中,unblocker: falseunblocker: true 之间的区别就是质询页面和 200 响应之间的区别。普通的 curl 访问托管的 Cloudflare 第一次就会收到 403。具有 unblocker: true 的相同 URL 可以通过,因为连接在网络级别看起来像一个浏览器会话。

但是对于不进行指纹识别的网站 (大多数公共 API、较旧的 CMS 模板、任何仅限制 IP 速率的内容),关闭 unblocker 是可以的,并且可以节省几毫秒的协商时间。在需要的地方使用它。

针对高级用户

有几个值得了解的模式。

当目标也检查 IP 信誉时,将 unblocker 与住宅 proxy 配合使用。如果网站已将数据中心 IP 加黑名单,即使是完美连接签名的请求仍然会被标记。我们的 proxy endpoint (/api/proxy) 根据目标域进行轮换,因此在请求中添加 "proxy": "residential" 通常就足够了。

调用不关心浏览器的 JSON API 时,请跳过 unblocker。额外的 header 实际上可能会引起预期编程客户端的 API 的怀疑,例如后端调用其自身的微服务。

如果网站运行 JavaScript 防机器人程序 (Turnstile 交互式质询、最严格的 PerimeterX、启用启发式算法的 Akamai Bot Manager),仅靠 unblocker 是不够的。你需要 browser endpoint,它在完整的浏览器中执行质询。这是不同的产品,计费方式也不同,我们在 Browser Tasks: How to Scrape JavaScript-Heavy Sites 中进行了说明。

你可以将 unblockervalidate 块结合使用,以拒绝技术上返回 200 但包含质询页面的响应:

{
  "url": "https://example.com/products",
  "method": "GET",
  "unblocker": true,
  "validate": {
    "data": { "fail": ["captcha", "Access Denied"] }
  }
}

这会将静默失败变成已分类的失败,这对于你在 dashboard 中的成功率跟踪很重要。

下一步

浏览器每四周发布一个稳定的新版本。我们也会相应更新我们的技术栈。你不需要在自己这边做任何更改:unblocker: true 会始终指向我们经过端到端验证的任何浏览器版本。

更艰巨的工作还在后头。HTTP/3 指纹识别已经出现在托管的反机器人程序上,QUIC 传输比旧传输更难匹配,而且从静态 header 组合向真正动态仿真的迁移已经开始。受保护的网站已转移到检查 HTTP/2 帧顺序,而“看起来像浏览器的库”与“真正的浏览器”之间的差距将从两端缩小。当我们发布它时,我们会写关于它的文章。