解决 CAPTCHA 层:集成 CapMonster Cloud
通过 TLS 检查是必要的,但并不总是充分的。像 Cloudflare、 DataDome 和 Imperva 这样的平台采用分层机制:在 TLS 之后,它们可能会下发 JavaScript 质询或 CAPTCHA,以验证客户端是否为真实浏览器。任何一层中的行为不匹配都可能触发拦截。
这正是 CapMonster Cloud 在整个技术栈中的作用所在。它是一项基于云的 CAPTCHA 求解服务,提供 API,可处理这些反机器人系统下发的质询类型:
CAPTCHA / 质询类型 | CapMonster Cloud 支持情况 |
Cloudflare Turnstile | ✅ |
Cloudflare Bot Challenge | ✅(需要代理) |
DataDome CAPTCHA | ✅(需要代理) |
Imperva / Incapsula | ✅ |
reCAPTCHA v2 / v3 | ✅ |
Amazon WAF CAPTCHA | ✅ |
一般工作流程是:你的 TLS 仿真客户端负责传输层;CapMonster Cloud 负责解析质询令牌;然后你将该令牌注入后续请求中。在实际场景中,是否成功取决于具体的 WAF 配置,以及除令牌之外的其他附加信号。
下面的示例涵盖的是 Cloudflare Bot Challenge——这是一种常见场景,即受保护站点返回 403 "Just a moment" 页面。它使用带有 cloudflareTaskType: "cf_clearance" 参数的 TurnstileTask,这是专门针对 Cloudflare Challenge 的流程—— 不同于常规的 Turnstile 任务(后者用于独立的 Turnstile 小组件)。由于 API 模式可能会随版本变化,请始终参考 当前的 CapMonster Cloud 文档,确认所需字段的准确要求。
import tls_client
import base64
import time
import requests
from urllib.parse import urlparse
# ===================== 配置 =====================
API_KEY = "YOUR_CAPMONSTER_API_KEY"
TARGET_URL = "https://example.com/protected-page"
WEBSITE_KEY = "xxxxxxxxxx"
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36"
# 代理格式:protocol://user:pass@ip:port
PROXY = "http://proxy_login:proxy_password@proxy_ip:proxy_port"
CREATE_TASK_URL = "https://api.capmonster.cloud/createTask"
GET_RESULT_URL = "https://api.capmonster.cloud/getTaskResult"
# ===================== TLS 会话 =====================
session = tls_client.Session(
client_identifier="chrome_120",
random_tls_extension_order=True
)
session.headers.update({
"User-Agent": USER_AGENT,
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Connection": "keep-alive",
})
session.proxies = {
"http": PROXY,
"https": PROXY
}
# ===================== 代理解析器 =====================
def parse_proxy(proxy_url):
parsed = urlparse(proxy_url)
return {
"proxyType": parsed.scheme,
"proxyAddress": parsed.hostname,
"proxyPort": parsed.port,
"proxyLogin": parsed.username,
"proxyPassword": parsed.password
}
# ===================== 步骤 1 =====================
def get_html_base64():
try:
resp = session.get(TARGET_URL, timeout_seconds=30)
print(f"[INFO] Status: {resp.status_code}")
html_base64 = base64.b64encode(resp.content).decode()
print("[INFO] HTML Base64 received")
return html_base64
except Exception as e:
print("[ERROR] Fetch HTML:", e)
return None
# ===================== 步骤 2 =====================
def solve_captcha(html_base64):
proxy_data = parse_proxy(PROXY)
payload = {
"clientKey": API_KEY,
"task": {
"type": "TurnstileTask",
"websiteURL": TARGET_URL,
"websiteKey": WEBSITE_KEY,
"cloudflareTaskType": "cf_clearance",
"htmlPageBase64": html_base64,
"userAgent": USER_AGENT,
"proxyType": proxy_data["proxyType"],
"proxyAddress": proxy_data["proxyAddress"],
"proxyPort": proxy_data["proxyPort"],
"proxyLogin": proxy_data["proxyLogin"],
"proxyPassword": proxy_data["proxyPassword"]
}
}
create = requests.post(CREATE_TASK_URL, json=payload).json()
print("[INFO] CreateTask:", create)
if create.get("errorId") != 0:
raise Exception(create.get("errorDescription"))
task_id = create["taskId"]
print(f"[INFO] Task ID: {task_id}")
while True:
time.sleep(5)
result = requests.post(GET_RESULT_URL, json={
"clientKey": API_KEY,
"taskId": task_id
}).json()
if result.get("status") == "ready":
print("[INFO] Solution received")
return result["solution"]
print("[INFO] Waiting...")
# ===================== 步骤 3(应用 Cookies) =====================
def apply_cookies(solution):
"""
应用来自 CapMonster 求解结果的 cookies
"""
# 选项 1:cookie 列表
if "cookies" in solution:
for cookie in solution["cookies"]:
session.cookies.set(
cookie["name"],
cookie["value"],
domain=cookie.get("domain", ".example.com"),
path=cookie.get("path", "/")
)
print("[INFO] Cookies applied from list")
# 选项 2:单独的 cf_clearance
if "cf_clearance" in solution:
session.cookies.set(
"cf_clearance",
solution["cf_clearance"],
domain=".example.com",
path="/"
)
print("[INFO] cf_clearance applied")
# ===================== 步骤 4(访问受保护页面) =====================
def access_protected_page():
try:
resp = session.get(TARGET_URL, timeout_seconds=30)
print(f"[INFO] Final Status: {resp.status_code}")
if "cf-chl" in resp.text or resp.status_code in :
print("[WARNING] Still blocked by Cloudflare")
else:
print("[SUCCESS] Cloudflare bypass successful")
return resp.text
except Exception as e:
print("[ERROR] Final request:", e)
# ===================== 主程序 =====================
def main():
html_base64 = get_html_base64()
if not html_base64:
return
solution = solve_captcha(html_base64)
print("\\n=== CAPTCHA SOLUTION ===")
print(solution)
apply_cookies(solution)
access_protected_page()
if __name__ == "__main__":
main()
CapMonster Cloud 支持对需要代理的质询使用 基于代理 的任务(Cloudflare Bot Challenge、DataDome)。你提供的代理会影响验证过程中使用的 IP,但质询最终是否被接受,还取决于防护服务内部的其他逻辑。
构建完整的反机器人绕过技术栈
对于使用现代反机器人防护的网站,生产级绕过流水线应当分别处理每一层检测机制——不过在实践中,许多防护提供商会将这些信号组合起来并赋予不同权重:
- ✅ TLS 指纹 → tls-client 或 azuretls-client,配合当前的 Chrome 配置和随机化扩展顺序
- ✅ HTTP/2 指纹 → 文档表明同样可由这些客户端处理 HTTP/2;请根据该库的官方 README 核实对 HPACK 和流设置的支持情况
- ✅ 请求头一致性 → User-Agent、 Accept-Language、 Sec-CH-UA 以及其他请求头必须与所选浏览器配置保持一致
- ✅ CAPTCHA / JS 质询 → CapMonster Cloud API——支持 Cloudflare Turnstile、Cloudflare Bot Challenge、DataDome、Imperva、reCAPTCHA 等。请根据质询类型使用正确的任务类型:常规 Turnstile 与 Cloudflare Bot Challenge 的处理方式不同
- ✅ IP 信誉 → 对于 CapMonster Cloud 中的 Cloudflare Bot Challenge 和 DataDome 任务,需要住宅代理或移动代理;对于其他质询类型,请根据当前文档核实代理要求
只处理其中一层而忽略其他层,是绕过尝试在规模化场景下失败的常见原因。大多数提供商都会使用多种信号——要获得稳定结果,就需要一并处理这些信号。
投产前检查清单:用于无感知 Web 抓取
- 识别目标站点使用的反机器人提供商(Cloudflare、DataDome、Imperva 等)
- 使用最新的 Chrome 或 Firefox 配置初始化 tls-client;并根据 官方配置列表核实标识符字符串
- 启用 random_tls_extension_order(注意:这可以降低固定顺序的可预测性,但本身并不是完整的指纹对抗措施)
- 设置所有与浏览器一致的 HTTP 请求头(User-Agent、 Accept、 Sec-CH-UA 等)
- 检测响应中是否存在 CAPTCHA / 质询(HTTP 403、"Just a moment" HTML、通过 /cdn-cgi/ 的重定向)
- 使用针对各类质询的 正确任务类型 集成 CapMonster Cloud API:Turnstile 小组件使用 TurnstileTask;Cloudflare Bot Challenge(cf_clearance)使用带有 cloudflareTaskType: "cf_clearance" 的 TurnstileTask——并根据 当前文档核实所有必需字段
- 对所有 CapMonster API 响应添加 errorId / errorCode 检查
- 为所有出站 HTTP 调用添加 timeout;并显式处理异常
- 以显式的 domain 和 path 设置 cf_clearance cookie
- 提供住宅代理或移动代理——这是 Cloudflare Bot Challenge 和 DataDome 任务所必需的
- 在投入生产前,使用 tls.peet.ws 或 ja4db.com 测试你的 TLS 指纹