API Tutorials

如何使用 API 解决 Cloudflare Turnstile

自动化脚本卡在 Cloudflare Turnstile 上,页面却看不到验证码图案——这是常见场景。Turnstile 在后台静默校验,仅在信号不足时弹出小组件,最终产出 cf-turnstile-response token 交给后端。

拿到 token 是唯一的通关条件。本文用 CaptchaAI API 演示提取 sitekey、提交任务、轮询、回填 token 四步,代码以 Python 与 Node.js 为主。先看 CaptchaAI 快速入门 了解通用 4 步模型更顺。

开始前要准备好三样东西

  • CaptchaAI API key:在 captchaai.com 仪表盘获取。
  • Turnstile sitekey:从目标页面提取,固定以 0x 开头。
  • 页面 URL:Turnstile 组件实际出现的完整地址。
  • 运行环境:Python 3.7+ 或 Node.js 14+。

国内网络装 Python 依赖较慢时,可加镜像加速:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests

第 1 步:从页面里挖出 sitekey

sitekey 一般写死在 HTML 的 divscript 标签里:

<div class="cf-turnstile" data-sitekey="0x4AAAAAAAC3DHQFLr1GavNl"></div>

也可能是 JavaScript 动态渲染出来的:

turnstile.render('#widget', {
  sitekey: '0x4AAAAAAAC3DHQFLr1GavNl',
  callback: function(token) { /* ... */ }
});

定位 sitekey 有三种常见办法:

  • DevTools:打开 Elements,搜索 data-sitekeycf-turnstile
  • 查看源代码Ctrl+U,直接搜 0x 前缀字符串。
  • Network 面板:过滤 challenges.cloudflare.com,参数含 sitekey。

sitekey 固定以 0x 开头,长度约 22 字符,与 reCAPTCHA 的 6L... 前缀不同——认错 sitekey 是常见报错原因。


第 2 步:把任务提交给 CaptchaAI 解决 Turnstile

https://ocr.captchaai.com/in.php 发 POST 请求,methodturnstile

import requests

API_KEY = "YOUR_CAPTCHAAI_KEY"
SITEKEY = "0x4AAAAAAAC3DHQFLr1GavNl"
PAGEURL = "https://staging.example.com/qa-login"

r = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": SITEKEY,
    "pageurl": PAGEURL,
    "json": 1,
})
data = r.json()
if data["status"] != 1:
    raise RuntimeError(f"submit failed: {data}")
task_id = data["request"]
print("task id:", task_id)

Node.js 版本:

const axios = require("axios");

const { data } = await axios.post("https://ocr.captchaai.com/in.php", null, {
  params: {
    key: process.env.CAPTCHAAI_KEY,
    method: "turnstile",
    sitekey: "0x4AAAAAAAC3DHQFLr1GavNl",
    pageurl: "https://staging.example.com/qa-login",
    json: 1,
  },
});
if (data.status !== 1) throw new Error(`submit failed: ${JSON.stringify(data)}`);
const taskId = data.request;

成功返回 {"status": 1, "request": "<task_id>"},存好 task_id 供下一步轮询用。


第 3 步:轮询拿到 token

通常 10–25 秒出结果:先睡 10 秒,之后每 5 秒轮询一次,最多 40 次(约 200 秒上限):

import time

time.sleep(10)
for _ in range(40):
    r = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "get",
        "id": task_id,
        "json": 1,
    })
    res = r.json()
    if res["status"] == 1:
        token = res["request"]
        break
    if res["request"] != "CAPCHA_NOT_READY":
        raise RuntimeError(f"solver error: {res}")
    time.sleep(5)
else:
    raise TimeoutError("turnstile solving timed out")

print("token (前 60 字符):", token[:60])

token 是一段 Base64 字符串,以 0. 开头,长度约 400–600 字符,比 reCAPTCHA token 更长,属正常现象。


第 4 步:把 token 写回页面并提交表单

把 token 塞进表单隐藏字段 cf-turnstile-response,再提交表单。

Selenium:

driver.execute_script(
    "document.querySelector('[name=cf-turnstile-response]').value = arguments[0];",
    token,
)
driver.find_element("css selector", "form").submit()

Playwright:

page.evaluate(
    "(t) => document.querySelector('[name=cf-turnstile-response]').value = t",
    token,
)
page.click("button[type=submit]")

纯 HTTP 提交: 不跑浏览器时,把 token 放进请求体的 cf-turnstile-response 字段一起 POST。

token 有效期约 120–300 秒,拿到立刻用;超时后端会返回 timeout-or-duplicate,需回第 2 步重来。


完整 Python 示例

import os, time, requests

API = "https://ocr.captchaai.com"
KEY = os.environ["CAPTCHAAI_KEY"]

def solve_turnstile(sitekey: str, pageurl: str) -> str:
    r = requests.post(f"{API}/in.php", data={
        "key": KEY, "method": "turnstile",
        "sitekey": sitekey, "pageurl": pageurl, "json": 1,
    }, timeout=30)
    j = r.json()
    if j["status"] != 1:
        raise RuntimeError(f"submit: {j}")
    tid = j["request"]

    time.sleep(10)
    for _ in range(40):
        r = requests.get(f"{API}/res.php", params={
            "key": KEY, "action": "get", "id": tid, "json": 1,
        }, timeout=30)
        j = r.json()
        if j["status"] == 1:
            return j["request"]
        if j["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(f"poll: {j}")
        time.sleep(5)
    raise TimeoutError("timeout")

if __name__ == "__main__":
    print(solve_turnstile("0x4AAAAAAAC3DHQFLr1GavNl", "https://staging.example.com/qa-login"))

常见错误码怎么处理

  • ERROR_WRONG_USER_KEY(key 格式不对):确认 CAPTCHAAI_KEY 完整、无多余空格。
  • ERROR_KEY_DOES_NOT_EXIST(key 不存在):回仪表盘核对 key,勿用截断版本。
  • ERROR_ZERO_BALANCE(余额为零):先充值再重试。
  • ERROR_PAGEURL(缺少 pageurl):确认传入完整 URL,含 https://
  • ERROR_CAPTCHA_UNSOLVABLE(多次失败):核对 sitekey 与 pageurl 是否配对,再重试一次。

更多错误码见 reCAPTCHA v2 教程,两者共用同一套错误体系。


跑不通时按这个顺序排查

  • sitekey 动态变化:部分站点每次访问签发新 sitekey,需先抓页面再提取。
  • pageurl 不精确:须与实际页面完全一致(含路径,不含 query)。
  • TLS 特征被拦截:建议用真实浏览器、curl_cffi 或 Playwright 提交,而非裸 requests
  • token 已过期:超过 2 分钟未用需回第 2 步重提交。
  • 出口 IP 质量差:数据中心 IP 段易触发额外挑战,优先用自有服务器基础设施。

常见问题

一直返回 CAPCHA_NOT_READY,是代码写错了吗?

不是,这是正常中间状态,任务还在队列里,按 5 秒间隔继续轮询即可;超过 40 次仍如此才需检查 sitekey/pageurl。

token 能保留下来下次复用吗?

不能。token 与本次请求绑定,有效期约 120–300 秒,过期或用过即失效,每次都要重新提交加轮询。

隐形 Turnstile(看不到小部件)也能这样解决吗?

可以,流程完全一样,依然只需要 sitekey 和 pageurl。

高频调用会被限流或额外收费吗?

CaptchaAI 按线程数计费,套餐内单线程求解次数不设上限,不按次数扣费;超出并发线程数的请求会排队而非直接失败。


下一步

  1. 阅读 CaptchaAI 快速入门,掌握通用的 4 步调用模型。
  2. 遇到相似场景可参考 reCAPTCHA v2 解决方案
  3. captchaai.com 注册拿 API key,接入上面的代码。

免费注册 CaptchaAI,5 分钟内拿到你的第一个 Turnstile token。

该文章已禁用评论。