对于一项获准执行的浏览器智能体任务,先从一个由提供商支持的稳定出口、一个浏览器上下文,以及提取之前的一道响应门控开始。然后只更换故障真正指向的那个组件。代理认证问题需要修配置。目标站点的拒绝需要做访问决策。验证页面必须被挡在你的 RAG 语料库之外,即便它返回的是 HTTP 200。
这就是面对 Cloudflare 故障的抓取器、检索工作进程或浏览器智能体应有的实用配置。这里没有任何证据表明切换到住宅代理或移动代理能解决所有拦截。
日期核对:2026 年 9 月 14 日。 Cloudflare 宣布的变更计划于 9 月 15 日生效。本文描述的是该公告和一套诊断工作流;它不报告已观察到的上线情况,也不能确定你当前错误的原因。
9 月 15 日会发生什么变化
Cloudflare 7 月的公告把 Search、Agent 和 Training 活动区分开。新接入的域名将默认在展示广告的页面上拦截 Training 和 Agent 活动,而 Search 仍然被允许。另外,把 Search 与 Training 结合在一起的爬虫将遵循最严格的适用规则,包括已有的 Training 拦截。广告页默认设置和混合用途分类是两项不同的变更。Cloudflare 的原始公告
该公司的新闻稿说明,广告页默认设置覆盖新客户、现有客户的新站点,以及在 9 月 15 日之前没有改动过控制面板设置的现有 Free 客户。「所有免费套餐站点」这种说法丢掉了这个限定条件。客户可以更改自己的设置。Cloudflare 关于受影响客户群体的公告
站点所有者可以为每个类别选择全站拦截、广告页拦截或 Allow。这些类别描述的是活动;你的浏览器库或 RAG 流水线的名称并不决定它的分类。Cloudflare 自行检测广告页,所以在浏览器里禁用广告下载并不能绕过策略。AI bot 策略参考
更换代理之前,先找出失败的那一跳
在检索记录中,把代理交互、目标站点导航和任何托管抓取 API 的响应分开保存。来自 api.firecrawl.dev 的 HTTP 402 和来自出版方的 HTTP 402 需要不同的处理。
单独一个 403 并不能指向 9 月 15 日的策略。Cloudflare 记录了多种可能的来源,包括源站权限和其他安全规则。cf-ray 有助于把请求与站点运营者的事件关联起来;它不会说明是哪条规则拒绝了请求。记录 UTC 时间戳、相关路径,以及可用时的 Ray ID。敏感的 URL 参数要保密。403 的原因、Ray ID 诊断
| 观察结果 | 下一步动作 | RAG 处理 |
|---|---|---|
| 代理返回 407,或浏览器认证/连接错误 | 核实配置的网关、凭据和提供商账户。Chromium 可能把代理故障表现为导航异常。 | 标记检索不可用;保留原因。 |
目标站点返回 cf-mitigated: challenge | 调查该站点允许的访问途径和浏览器要求。停止自动重试验证。 | 隔离该响应,即使名义上是 200。 |
| 目标站点返回 403 且没有该验证信号 | 请站点运营者把请求与访问/安全规则关联起来;有条件时使用约定的 API、feed 或放行途径。 | 不可用;具体策略仍然未知。 |
| 来自已知一跳的 429 | 若提供了 Retry-After 则遵守;在受影响的范围内减少工作量,并为总重试预算设上限。 | 推迟检索;保留其新鲜度状态。 |
| 目标站点返回 402 | 检查出版方的付费/访问上下文和文档化的集成方式。 | 不可用,直到之后有一次被接受的抓取。 |
| Firecrawl API 返回 HTTP 402 | 检查 Firecrawl 的额度和计费配置。 | 除非另有报告,目标状态仍然未知。 |
| HTTP 200 但内容缺失、为空或不正确 | 检查渲染、必需的子资源和提取契约。 | 保留此前任何有效的文档;标记这次刷新失败。 |
验证响应头是 Cloudflare 记录在文档中的响应信号。没有这个响应头并不能确定内容可用。HTTP 407 指向代理认证;429 的计数范围由响应服务决定,所以更换出口并不能证明配额已重置。验证检测、407 语义、429 语义
对于托管版 Firecrawl,把外层 API 错误与返回的目标元数据和任务错误一起检查。其 API 错误目录把 402 描述为额度不足或缺少计费配置。其 scrape 响应可以单独携带 data.metadata.statusCode。这些字段在你的日志中必须保持分开。Firecrawl 错误、scrape 响应契约
完整浏览器任务的代理配置
对于有状态的工作流,在任务持续期间申请一个稳定出口,并在各个步骤中保留同一个浏览器上下文。提供商控制出口的亲和性;上下文保存 cookie 和浏览器存储。确认提供商的会话时长、重连行为以及出口提前失效时的替换策略。仅凭一个固定的网关地址无法证明这些属性中的任何一项。会话连续性指南说明了需要核实的内容。
当站点所有者允许某个固定地址时,经批准的固定地址是一个有用的起点。必需的地区可以成为使用区域出口的理由。对于其他工作负载,在相同的 URL 集合、账户、会话、地区和并发下比较候选路线。统计每次尝试文档中新鲜且有效的文档数,以及每个被接受文档的成本,包括重试和渲染流量。「住宅/移动」这个标签不足以用来选出胜者;代理比较介绍了这种评估。
把代理设置放在发起页面请求的地方:
| 技术栈 | 配置边界 | 会改变诊断结果的细节 |
|---|---|---|
| Playwright | 向 browser.newContext 传入包含 server、username 和 password 的 proxy 对象,或在浏览器启动时配置。 | httpCredentials 是目标站点认证。单独的 Node/Python HTTP 客户端需要自己的配置。Network 文档 |
| Puppeteer | 设置上下文的 proxyServer;在导航之前用 page.authenticate 提供代理用户名/密码。 | proxyServer 是一个端点字符串。新创建的页面也要配置。上下文选项、认证 |
| Browser Use | 开源版浏览器接受 Browser(proxy=ProxySettings(...))。 | 使用 CDP 或托管浏览器时,核实远程浏览器的出口契约。本地设置并不能控制一个已经在运行的远程浏览器。参数、远程浏览器 |
| 托管版 Firecrawl | v2 scrape 的 proxy 字段可选 basic、enhanced 或 auto;默认为 auto。 | 这是一个托管策略选择器,不是自定义代理 URL。设置本地 HTTP_PROXY 不会配置远程的目标抓取。Scrape API |
把重试控制在同一个任务预算之内。托管服务的内部尝试,加上 SDK 的重试,再加上智能体的「再试一次」循环,会成倍放大工作量。遭到拒绝后,保留原因,并按上表选择下一步动作,然后再安排另一次尝试。
在提取之前运行响应门控
可下载的 Playwright 探测程序执行一次导航,对其主响应进行分类,并检查预期 CSS 选择器中是否有非空文本。它输出一小段 JSON 诊断信息,不包含目标 URL、正文、凭据或原始异常。它不提取也不摄入内容。
把 probe.mjs、package.json、package-lock.json、test-fixture.mjs 和 README 下载到同一个目录。使用 Node.js 22 或更高版本,运行 npm ci,然后运行 npx playwright install chromium。该包锁定了 Playwright 1.63.0。
通过你现有的配置/密钥机制注入以下设置,然后运行 node probe.mjs:
PROXY_SERVER:不含凭据的http://网关 URL,不带路径或查询参数。PROXY_USERNAME和PROXY_PASSWORD:你的提供商凭据,连同任何文档规定的会话设置。TARGET_URL:你要检查的页面。EXPECTED_SELECTOR:一个具体的 CSS 选择器,例如main article[data-document-id],其匹配到的元素必须包含文本。
探测程序允许 15 秒用于导航,另有 5 秒用于内容检查。每次调用都会创建并关闭一个全新的上下文。对于多步骤的生产任务,保留任务的上下文,并对其相关响应应用同样的检查。Playwright 配置指南介绍了凭据和上下文配置。
这段分类代码在选择器检查之前运行:
if (result.cf_mitigated) return 'challenge';
if (result.status === 402) return 'payment_or_access_review';
if (result.status === 403) return 'access_review';
if (result.status === 407) return 'proxy_auth_error';
if (result.status === 429) return 'rate_limited';
if (result.status >= 500 && result.status < 600) return 'upstream_error';
if (result.status !== 200) return 'unexpected_status';
if (!/^text\/html(?:\s*;|$)/i.test(headers['content-type'] ?? '')) return 'invalid_content';
return null;完整函数只在响应头等于 challenge 时才设置 cf_mitigated。这里返回 null 表示继续进行内容检查。最终的 accepted_content 结果要求 HTTP 200、HTML 且预期内容非空;它以退出码 0 结束。其他结果以退出码 2 结束。
在我们的 18 次合成检查中,所有预期结果都匹配:4 个响应通过了这道最小门控,14 个被拦下。一个状态为 200 且带有 cf-mitigated: challenge 的测试响应产生了 outcome: challenge 和退出码 2。预期内容缺失或为空同样失败。错误的代理凭据在两次认证质询之后暴露出 407 和 proxy_auth_error;没有任何请求被转发。有一个被接受的案例故意包含了一个失败的 403 子资源,用来展示主文档检查的局限。确切的测试结果
运行 node test-fixture.mjs 可以复现这套本地测试。它使用了 Node 26.8.1、Playwright 1.63.0 和 Chromium 153.0.8010.12,以及一个本地源站和一个需要认证的 HTTP 代理。安装命令和测试也用从本地 HTTP 服务器下载的完全相同的文件运行过。这些检查确定的是该探测程序在合成响应上的行为;它们不能确定真实的 Cloudflare 访问、提供商出口的稳定性或 HTTPS CONNECT 的行为。
把「接受」视为可以运行更深入校验的许可。宽泛的选择器可能匹配到登录页,而主 HTML 通过时某个必需的 JSON 子请求可能失败。在你的工作进程将要摄入的确切内容上校验文档身份、必需字段、语言区域和新鲜度。一次成功的探测不能为之后返回不同内容的抓取背书。刷新失败时保留上一份有效文档,并让消费者能看到其旧的检索时间。
当解决方案属于站点的访问规则时
如果目标站点由你运营,把命中的安全规则和它的 AI 爬虫策略放在一起检查。AI Crawl Control 中设为 Allow,仍然可能被更早执行的 WAF 规则覆盖。因此,AI 爬虫视图中缺少某个请求,也是去检查安全事件的一个理由。如果站点归另一个团队所有,共享请求标识符,并就预期的访问路径达成一致。Cloudflare 的规则优先级
Pay Per Crawl 是一种单独的访问安排。其文档目前把它标为封闭测试;一个未付费的收费请求可能收到带 crawler-price 的 HTTP 402。付费请求需要文档规定的注册和签名付款意向流程。仅添加一个未签名的付款头是不够的,而且 WAF/Bot Management 拦截仍然可能阻止访问。要审慎地决定是否参与和预算多少,而不是让智能体把任何 402 都解释为可以花钱的授权。Pay Per Crawl 范围、请求协议
你的流水线应当能够返回带原因和时间戳的「来源不可用」。这样,当仍然需要修复认证、由所有者批准规则变更或使用受支持的内容接口时,调用方也能得到一个可用的决定。
方法:由 ipvolt 在 AI 辅助下撰写,并于 2026 年 9 月 14 日对照所链接的一手文档进行了核对。可下载的测试使用本地合成响应。它不衡量真实的 Cloudflare 拦截、代理提供商性能、HTTPS CONNECT 行为或 9 月 15 日的上线情况。
ipvolt 仍在开发中。加入后,访问开放时只发一封邮件。没有别的。
参考来源
- Cloudflare: Your site, your rules — new AI traffic options
- Cloudflare: September 15 announcement and existing Free customer scope
- Cloudflare: Block AI Bots
- Cloudflare: Detect a Challenge Page response
- Cloudflare: AI Crawl Control with WAF
- Cloudflare: Error 403
- Cloudflare: Ray ID
- Cloudflare: What is Pay Per Crawl?
- Cloudflare: Pay Per Crawl request protocol
- Playwright: HTTP proxy configuration
- Puppeteer: BrowserContextOptions
- Puppeteer: Page.authenticate
- Browser Use: Browser parameters
- Browser Use: Remote browser configuration
- Firecrawl: Hosted v2 scrape API
- Firecrawl: API errors
- RFC 6585: HTTP 429
- RFC 9110: Proxy authentication required