打开一个 Cloudflare 保护的网站,爬虫返回 403,第一反应常是"验证码没识别对"——但问题往往是浏览器完整性检查(Browser Integrity Check,BIC)在标头层拦下了请求,根本没到 CAPTCHA 这一步。BIC 只看 HTTP 标头,不通过就是 403;CAPTCHA 挑战(Turnstile、JavaScript 挑战、托管挑战)给出真实浏览器能做完的任务,做不完返回 503。分不清两者,很容易把改标头就能解决的问题硬塞给验证码识别服务。
30 秒自查:先看你属于哪一种
- 换成浏览器请求头就直接 200 → 只是 BIC 拦截,跟 CaptchaAI 无关。
- 标头已经很"浏览器"了,还是 503 → 命中 CAPTCHA 挑战,交给 CaptchaAI。
- 换哪种标头组合都还是 403 → IP 或 WAF 问题,换 IP。
拿不准就往下看。
一张表看懂 BIC 和 CAPTCHA 挑战的区别
| 对比维度 | 浏览器完整性检查(BIC) | CAPTCHA 挑战 |
|---|---|---|
| 检查内容 | 仅 HTTP 请求标头 | 浏览器行为 + 运行环境 |
| 需要 JavaScript 吗 | 不需要(标头层拦截) | 需要 |
| 用户能看到什么 | 无感通过,或直接 403 | 挑战小部件或整版 JS 页面 |
| 失败时的状态码 | 403 | 503 |
| 能不能"解决" | 不能——只能修标头 | 能——解出验证码即可 |
| 通过后签发的 Cookie | 无 | qa_session_cookie |
| 需要 CaptchaAI 吗 | 不需要——改标头即可 | 需要 |
| 默认是否开启 | 是(所有套餐默认开启) | 否(按 WAF 规则配置) |
| 作用范围 | 每一个请求 | 只命中匹配的 WAF 规则 |
BIC 到底在查什么
BIC 在 JavaScript 或 CAPTCHA 挑战之前运行,只判断标头是否像真实浏览器。
BIC 会核对哪几项
- User-Agent 校验:缺失、为空或已标记异常,如
python-requests/2.31、curl、wget。 - 标头顺序:不符合真实浏览器习惯,常见于非浏览器 HTTP 库。
- 缺少常规浏览器标头:
Accept、Accept-Language、Accept-Encoding缺失。 - 已知机器人特征:扫描器 UA,或非 Google IP 冒充的
Googlebot。 - 恶意 IP 黑名单:命中已知恶意 IP 段或黑名单数据中心 IP。
Request hits Cloudflare edge
↓
BIC evaluates HTTP headers:
├─ User-Agent present and valid?
├─ Required headers (Accept, Accept-Language) present?
├─ Header order consistent with browser?
└─ IP not on abuse list?
↓
Pass → Request forwarded to origin
OR
Fail → 403 Forbidden (no challenge offered)
发送足够"像浏览器"的标头即可,不涉及验证码识别:
import requests
# ❌ FAILS BIC — minimal headers
response = requests.get("https://cloudflare-protected.com")
# User-Agent: python-requests/2.31.0
# Result: 403 Forbidden
# ✅ PASSES BIC — browser-like headers
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
}
response = requests.get("https://cloudflare-protected.com", headers=headers)
# Result: 200 OK (passed BIC)
Node.js 版本同理:
const axios = require("axios");
// Browser-like headers to pass BIC
const headers = {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0",
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
Connection: "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
};
async function fetchWithBIC(url) {
const response = await axios.get(url, { headers });
console.log(`Status: ${response.status}`);
return response.data;
}
CAPTCHA 挑战有哪几种
BIC 通过之后才轮到 CAPTCHA 挑战,需要浏览器执行 JavaScript 并给出可解出的任务:
| 挑战类型 | 触发条件 | 用户是否可见 | CaptchaAI 对应方法 |
|---|---|---|---|
| Turnstile 小部件 | 开发者手动嵌入页面 | 表单上的小部件 | turnstile |
| 托管挑战(Managed Challenge) | 命中 WAF 规则 | 自适应(可能无感,也可能是勾选框) | turnstile |
| JavaScript 挑战 | IUAM 或 WAF 规则触发 | "检查你的浏览器"页面 | cloudflare_challenge |
| 交互式挑战 | 风险评分高 | 整版挑战页面 | cloudflare_challenge |
多一步 JavaScript 执行:
Request passes BIC check
↓
WAF rules evaluate bot score, IP, path
↓
Rule triggers CAPTCHA challenge (HTTP 503)
↓
Browser executes JavaScript challenge
↓
Challenge solved → qa_session_cookie cookie issued
↓
Subsequent requests pass with cookie
写一段脚本,自动判断是 BIC 还是 CAPTCHA
与其凭感觉猜,不如分别发送极简标头和浏览器标头,对比状态码和页面内容,直接定位问题类型:
import requests
def diagnose_cloudflare_block(url):
"""Determine if block is BIC or CAPTCHA."""
# Intentionally use minimal headers to trigger BIC
minimal_response = requests.get(url, timeout=15, allow_redirects=False)
# Use browser headers to QA tanılama BIC
browser_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0",
"Accept": "text/html,application/xhtml+xml,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
}
browser_response = requests.get(
url, headers=browser_headers, timeout=15, allow_redirects=False
)
result = {
"minimal_headers_status": minimal_response.status_code,
"browser_headers_status": browser_response.status_code,
}
if minimal_response.status_code == 403 and browser_response.status_code == 200:
result["diagnosis"] = "BIC only — fix headers to pass"
result["fix"] = "Add browser-like headers"
elif minimal_response.status_code == 403 and browser_response.status_code == 403:
result["diagnosis"] = "IP or WAF block — not just BIC"
result["fix"] = "Change IP or check WAF rules"
elif browser_response.status_code == 503:
html = browser_response.text
if "jschl" in html:
result["diagnosis"] = "IUAM JavaScript challenge"
result["fix"] = "Use CaptchaAI cloudflare_challenge method"
elif "cf-turnstile" in html or "challenge-platform" in html:
result["diagnosis"] = "Managed/Turnstile challenge"
result["fix"] = "Use CaptchaAI turnstile method"
else:
result["diagnosis"] = "Unknown Cloudflare 验证流程"
result["fix"] = "Inspect page source for challenge type"
elif browser_response.status_code == 200:
html = browser_response.text
if "cf-turnstile" in html:
result["diagnosis"] = "Page loads but has Turnstile widget"
result["fix"] = "Use CaptchaAI turnstile method for form submission"
else:
result["diagnosis"] = "No challenge — page accessible"
result["fix"] = "None needed"
return result
# Usage
diagnosis = diagnose_cloudflare_block("https://example-cf-site.com")
print(f"Diagnosis: {diagnosis['diagnosis']}")
print(f"Fix: {diagnosis['fix']}")
四种真实场景,先对号入座
举例:杭州一个跨境电商团队抓取海外供应商库存数据,脚本本地跑得好好的,一上云服务器就大面积 403——服务器脚本用 requests 直发请求,标头缺 Accept、Accept-Language,加上数据中心 IP 更敏感,两点叠加被 BIC 拦下。下面四种场景覆盖了同类排查的主要分支。
Request with python-requests UA → 403
Request with Chrome UA → 200 ✓
Fix: Add proper browser headers. No CaptchaAI needed.
场景一,只被 BIC 拦截: 换成浏览器 UA 就能通过,说明只是标头不够"像浏览器",与 CaptchaAI 无关。
Request with Chrome UA → 503 (challenge page)
Fix: Headers are fine. 使用 CaptchaAI solve the challenge.
场景二,BIC 能过、卡在 CAPTCHA: 标头没问题,503 说明命中了 WAF 挑战,这一步才需要 CaptchaAI。
Request with python-requests UA → 403 (BIC block)
Request with Chrome UA → 503 (CAPTCHA challenge)
Fix: First fix headers, then solve CAPTCHA with CaptchaAI.
场景三,BIC 和 CAPTCHA 都要处理: 先改标头消掉 403,还有 503 就再用 CaptchaAI 解决。
Request with python-requests UA → 403
Request with Chrome UA → 403
Fix: Neither BIC nor solvable challenge. IP is blocked.
Try different IP/proxy.
场景四,两个都不是、IP 被封: 换了浏览器标头还是 403,只能换 IP 或代理。
请求头该怎么配置
以下组合可以稳定通过 BIC:
CLOUDFLARE_SAFE_HEADERS = {
# Mandatory
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
# Strongly recommended
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
# Sec-Fetch headers (modern Chrome)
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
# Recommended for consistency
"Sec-Ch-Ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
}
下面这些写法会直接触发拦截:
User-Agent: python-requests/2.31.0—— 已知 HTTP 库标识。User-Agent: curl/7.81.0—— 命令行工具标识。- 缺少
Accept或Accept-Language—— 真实浏览器不会漏发。 User-Agent: ""(空值)—— 明显的自动化特征。- 非 Google IP 发出的
Googlebot/2.1—— 一查 IP 就穿帮。
故障排查速查表
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 极简标头 403,浏览器标头 200 | 只是 BIC 拦截 | 换成像浏览器的请求头 |
| 换哪种标头都是 403 | IP 被封或命中 WAF 规则 | 换 IP 或走代理 |
| 返回 503 并带挑战页面 | CAPTCHA 挑战(不是 BIC) | 用 CaptchaAI 解决 |
| 403 时有时无 | 限流或会话状态问题 | 降低请求频率,保持会话一致 |
| 标头都对了还是 403 | TLS 指纹检测(JA3/JA4) | 换用 curl_cffi 或真实浏览器 |
常见问题
同样一段抓取代码,本地能跑通,一部署到服务器就被拦截,为什么?
本地开发机常用完整浏览器标头;服务器脚本常用最基础的 HTTP 库,标头只剩 UA,数据中心 IP 也更容易被 Cloudflare 重点关照。用诊断脚本分测极简标头和浏览器标头,能快速定位是标头问题还是 IP 问题。
CaptchaAI 能处理 Cloudflare Turnstile 和 Cloudflare Challenge 吗?速度怎么样?
能。CaptchaAI 支持 turnstile 和 cloudflare_challenge,Turnstile 通常 10 秒内解出,Cloudflare Challenge 通常 15 秒内解出,但解决不了 BIC 的 403,那部分只能靠调整标头。
已经通过了 BIC,为什么还会跳出验证码? 两者是独立防线,通过 BIC 只说明标头看起来正常,不代表不会再触发 WAF 规则、机器人评分或 IUAM 判定。
是不是只要看到 503 就一定是验证码? 不一定,也可能是限流或会话异常。先看页面里有没有 cf-turnstile 或 challenge-platform 特征,再决定该解验证码还是该降频率。
网站可以关闭 BIC 吗?关闭后会不会更容易被刷?
可以,在 Cloudflare 控制台"安全性 > 设置"里关闭,所有套餐默认开启。BIC 几乎不影响正常用户,关闭后风险转移到 WAF 和 CAPTCHA 挑战上,不建议只为兼容爬虫关闭它。
总结
BIC 看的是请求头够不够"像浏览器",通不过给 403,调标头就能解决,不需要 CaptchaAI。CAPTCHA 挑战出现在 BIC 通过之后,返回 503,需要解出 Turnstile 或 Cloudflare Challenge 才能拿到 qa_session_cookie——这一步才轮到 CaptchaAI。先诊断类型:403 修标头,503 用 CaptchaAI,怎么改都还是 403 就换 IP。