全部文章

Web Unblocker 剖析:Unblocker 标志的实际作用

一个标志触发三个开关:真实的浏览器 header、匹配的 TLS 指纹,以及针对 gzip 和 brotli 的自动解压。以下是具体变化及其原因。

大多数爬虫在读取单个 header 之前就失败了。

服务器会查看 TLS 握手(密码套件顺序、扩展顺序、曲线偏好),并判断你是一个浏览器,还是一个伪装成浏览器的客户端库。Python requests、Go 的 net/http、普通的 curl:它们在建立连接的瞬间都会交出独特的指纹。重视安全防护的网站(Datadome、Akamai、Imperva、Cloudflare 的托管防护端)甚至在你的 User-Agent 字符串发挥作用之前,就会断开连接或向你提供挑战页面。

这就是 unblocker: true 在 FourA 上解决的问题。在上个月,我们确定了使其可靠运行的关键要素。

最新动态

unblocker: true 是任何 /api/single 调用中的一个单一标志。启用它后,我们会执行三件事:注入浏览器 header 集合,通过具有真实浏览器 TLS 指纹的 curl-impersonate 发送 request,并解压服务器返回的任何内容(gzip、brotli、deflate)。前两项功能自测试版起就已提供。第三项功能(brotli 自动解压)于 3 月 25 日发布,浏览器版本锁定工作于次日上线,以保持 header 和 TLS 同步。

工作原理

以下是 request 的样式:

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。顺序至关重要。真实的浏览器会按特定顺序发送这些内容,而检测库会对此进行检查。

TLS 指纹。 curl-impersonate 0.8.2 针对 BoringSSL 编译了 libcurl,并重新排序 TLS 扩展,以匹配目标浏览器版本在网络上实际发送的内容。你的 JA3 和 JA4 哈希值将与真实的浏览器会话完全相同。标准的 curl、Python requests 和 Go 的 net/http 产生的指纹,在受保护的基础设施上会在几毫秒内被机器标记。

自动解压。unblocker 开启时,我们将 Accept-Encoding 设置为 gzip, deflate, br,并让 libcurl 解包 body。你将获得返回的解码字符串(如果传入 returnBuffer: true,则获得 Buffer)。无需手动处理 brotli,当网站选择 deflate 而非 gzip 时,也不会出现 header 与 body 不匹配的情况。

为什么版本锁定至关重要

TLS 指纹是与版本锁定的。浏览器本月的密码顺序与上月不同,而进行精细指纹识别的网站会注意到这种偏差。curl-impersonate 提供了针对特定浏览器构建版本的配置文件,我们将真实的浏览器二进制文件锁定到 curl-impersonate 当前定位的任何构建版本。header、navigator 对象和 TLS 都会报告相同的版本。

如果这听起来很繁琐,事实确实如此。在 3 月份的 monorepo 迁移期间,我们曾因不匹配而吃过苦头,当时浏览器自动更新,导致 header 与 curl-impersonate 失去同步。修复方法是两个 commit:锁定浏览器二进制文件,并且永远不要相信包管理器会帮你保持它们一致。

实际效果

在针对具有强指纹识别的目标(金融、旅游、受保护的电子商务)的内部测试中,unblocker: falseunblocker: true 之间的区别就是挑战页面与 200 状态码的区别。普通的 curl 访问受托管的 Cloudflare 时,第一次就会遇到 403。而带有 unblocker: true 的相同 URL 则可以顺利通过,因为 TLS hello 看起来就像真实的浏览器握手。

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

针对高级用户

以下是一些值得了解的模式。

当目标网站同时检查 IP 信誉时,请将 unblocker 与住宅 proxy 配合使用。数据中心 IP 加上完美的 TLS 握手,在网站已列入黑名单的 ASN 上仍会被标记。我们的 proxy endpoint (/api/proxy) 会根据目标域名进行轮换,因此在 request 中添加 "proxy": "residential" 通常就足够了。

在调用不在意浏览器的 JSON API 时,请跳过 unblocker。对于期望程序化客户端的 API(例如调用自身微服务的后端),额外的 header 实际上可能看起来很可疑。

如果网站运行 JavaScript 反爬虫机制(Turnstile 交互式挑战、最严格的 Perimeter X、启发式算法调高的 Akamai Bot Manager),仅靠 unblocker 是不够的。你需要浏览器 endpoint,它运行真实的 Chromium 并可以执行挑战。这是一个具有不同积分定价的不同产品,我们在 Browser Tasks:如何抓取重 JavaScript 的网站 中对此进行了详细介绍。

你还可以将 unblockervalidate 块结合使用,以拒绝那些技术上返回 200 但包含挑战页面的 response:

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

这会将静默失败转化为分类失败,这对于你在 dashboard 中的成功率跟踪非常重要。

下一步计划

浏览器每四周发布一个新的稳定版本。curl-impersonate 的维护者通常会在一个月后跟进,届时我们会升级我们的技术栈。你无需在自己这边进行任何操作:unblocker: true 会始终指向我们已完成端到端验证的任何浏览器版本。

更艰巨的工作还在后面。HTTP/3 指纹识别已经出现在托管的反爬虫系统上,QUIC 传输比 TLS 1.3 更难伪装,而且从静态 header 组合向真正的动态模拟的迁移已经开始。受保护的网站已转向检查 HTTP/2 帧顺序和 JA4+ 变体,而“看起来像浏览器的 curl”与“真正的浏览器”之间的差距将从两端缩小。我们将在发布该功能时撰文介绍。