Cloudflare Turnstile 附带三种小部件模式,用于控制挑战的呈现方式:托管(Cloudflare 决定)、非交互式(仅工作证明,从不显示 UI)和 不可见(无小部件容器,静默运行)。该模式决定了用户看到的内容、挑战需要多长时间以及小部件是否变得可见。对于自动化,所有三种模式都会产生相同的输出 - cf-turnstile-response 令牌 - 但检测和解决它们需要了解差异。
模式对比
| 特征 | 托管 | 非交互式 | 无形的 |
|---|---|---|---|
| 小部件可见? | 有时 | 从不(仅限旋转器) | 绝不 |
| 需要容器元素吗? | 是的 | 是的 | 是(隐藏) |
| 需要用户交互吗? | 有时(复选框) | 不 | 不 |
| 工作量证明挑战? | 是(可能会升级) | 是(总是) | 是(总是) |
| 交互式复选框后备? | 是的 | 否(反而失败) | 否(反而失败) |
| 令牌输出 | cf-turnstile-response |
cf-turnstile-response |
cf-turnstile-response |
| CaptchaAI方法 | turnstile |
turnstile |
turnstile |
| 推荐用于 | 登录、注册 | 低摩擦形式 | 背景核查 |
托管模式(默认)
托管模式让 Cloudflare 决定每个访问者的挑战级别。大多数用户都是无形地通过的。可疑流量会看到一个复选框。高度可疑的流量可能会面临更复杂的挑战。
执行
<!-- Managed mode (default) -->
<div class="cf-turnstile"
data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
data-theme="light">
</div>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
自动化看到了什么
托管模式根据请求者的信号进行调整:
| 名声 | 小部件呈现为 |
|---|---|
| 高信任度 | 隐形通行证(没有可见的UI) |
| 中等信任度 | 复选框小部件(点击验证) |
| 信任度低 | 互动挑战或阻止 |
对于自动化来说,托管模式是最常见且变化最大的。根据浏览器信号,小部件可能可见也可能不可见。
HTML 中的检测
def is_managed_mode(html):
"""Check if Turnstile is using managed mode (default)."""
# Managed mode is the default — no explicit mode attribute
has_turnstile = "cf-turnstile" in html
has_explicit_mode = 'data-appearance="interaction-only"' in html or \
'data-appearance="always"' in html or \
'appearance: "interaction-only"' in html
return has_turnstile and not has_explicit_mode
非交互模式
非交互模式从不显示复选框或交互元素。它在后台运行工作证明挑战,并且仅显示加载旋转器。如果挑战无法以非交互方式完成,则挑战会失败而不是升级。
执行
<!-- Non-interactive mode -->
<div class="cf-turnstile"
data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
data-appearance="interaction-only">
</div>
或者通过 JavaScript API:
turnstile.render('#turnstile-container', {
sitekey: '0x4AAAAAAAC3DHQhMMQ_Rxrg',
appearance: 'interaction-only',
callback: function(token) {
document.getElementById('cf-turnstile-response').value = token;
},
});
行为
Page loads → Widget initializes
↓
Background proof-of-work runs
↓
Success → Token generated (no visible UI)
OR
Failure → Widget reports error (no fallback to checkbox)
当网站使用非交互式
- 评论表单和反馈小部件
- 时事通讯注册
- 摩擦必须最小化的低价值行动
- 具有浏览器端保护的 API 端点
隐形模式
不可见模式是真正不可见的——视口中不会出现任何容器元素。该小部件在页面加载(或编程触发)时运行,并生成一个没有任何视觉指示的令牌。
执行
<!-- Invisible mode — container is hidden -->
<div id="turnstile-invisible"
class="cf-turnstile"
data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
data-size="invisible">
</div>
或者完全通过 JavaScript:
// Programmatic invisible Turnstile
turnstile.render('#hidden-container', {
sitekey: '0x4AAAAAAAC3DHQhMMQ_Rxrg',
size: 'invisible',
callback: function(token) {
// Token ready — submit form automatically
submitForm(token);
},
'error-callback': function() {
// Challenge failed
console.error('Invisible Turnstile failed');
},
});
检测挑战
隐形旋转门更难检测,因为容器没有可见的尺寸:
import re
def detect_invisible_turnstile(html):
"""Detect invisible Turnstile on a page."""
indicators = {
"script_loaded": "challenges.cloudflare.com/turnstile" in html,
"size_invisible": 'data-size="invisible"' in html or
"size: 'invisible'" in html or
'size: "invisible"' in html,
"api_render_call": "turnstile.render" in html,
"response_field": "cf-turnstile-response" in html,
}
if indicators["script_loaded"] and indicators["size_invisible"]:
return {"mode": "invisible", "confidence": "high"}
elif indicators["script_loaded"] and indicators["api_render_call"]:
return {"mode": "invisible_or_programmatic", "confidence": "medium"}
elif indicators["response_field"]:
return {"mode": "turnstile_present", "confidence": "low"}
return {"mode": "none", "confidence": "high"}
跨所有模式提取站点密钥
无论哪种模式,解决问题都需要sitekey。从任何模式中提取它:
import re
def extract_turnstile_sitekey(html):
"""Extract Turnstile sitekey from page HTML (works for all modes)."""
# Pattern 1: data-sitekey attribute in HTML
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', html)
if match:
return match.group(1)
# Pattern 2: JavaScript render call
match = re.search(r"sitekey:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
if match:
return match.group(1)
# Pattern 3: Turnstile config object
match = re.search(r"siteKey['\"]?\s*[:=]\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
if match:
return match.group(1)
return None
使用 CaptchaAI 解决所有三种模式
所有三种 Turnstile 模式的解决方法均与 CaptchaAI 相同。该模式不影响API调用:
Python
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_turnstile(sitekey, page_url):
"""Solve any Turnstile mode — managed, non-interactive, or invisible."""
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile",
"sitekey": sitekey,
"pageurl": page_url,
"json": 1,
})
task_id = submit.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
return result["request"]
raise TimeoutError("Turnstile solve timed out")
# Use with any mode
token = solve_turnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://staging.example.com/qa-login")
print(f"Token: {token[:50]}...")
Node.js
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
async function solveTurnstile(sitekey, pageUrl) {
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: {
key: API_KEY,
method: "turnstile",
sitekey,
pageurl: pageUrl,
json: 1,
},
});
const taskId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId, json: 1 },
});
if (result.data.status === 1) {
return result.data.request;
}
}
throw new Error("Turnstile solve timed out");
}
// Same function works for all Turnstile modes
solveTurnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://staging.example.com/qa-login")
.then((token) => console.log("Token:", token.substring(0, 50)));
故障排除
| 症状 | 原因 | 处理方式 |
|---|---|---|
| 令牌有效,但表单拒绝它 | 错误的站点密钥(与可见小部件不同) | 检查 JavaScript 渲染的 sitekey |
| 在 HTML 中找不到小部件 | 初始渲染后加载不可见模式 | 等待整页加载,检查 XHR 响应 |
| 页面上有多个Turnstile小部件 | 不同形式的不同站点密钥 | 将 sitekey 与特定形式匹配 |
data-size="compact" 混淆检测 |
紧凑是一种尺寸变体,而不是一种模式 | Compact默认使用托管模式 |
data-action 属性存在 |
用于分析的操作标签,而不是模式 | 如果需要验证,请在解决中包含操作 |
| 令牌在提交前过期 | Turnstile 令牌将在 300 秒后过期 | 提交前解决 |
常见问题
Turnstile 模式会影响 CaptchaAI 的解算吗?
不会。CaptchaAI 对所有三种模式使用相同的 turnstile 方法。 sitekey 和页面 URL 是唯一必需的参数。模式不会更改令牌格式或验证流程。
我如何知道网站使用哪种模式?
检查 HTML 中的 data-appearance 或 data-size 属性。如果存在data-size="invisible",则为隐形模式。如果 data-appearance="interaction-only" 存在,则它是非交互式的。如果两者均未设置,则为托管模式(默认)。
站点可以动态切换模式吗?
是的。某些站点默认使用托管模式,并针对特定页面或用户段切换为非交互模式。站点密钥通常保持不变。始终重新检测导航模式。
不同模式的成功率有何差异?
CaptchaAI 在所有旋转门模式下均实现 100% 的成功率。该模式仅影响面向用户的行为——API 级别的挑战是相同的。
概括
Cloudflare Turnstile 的三种小部件模式 - 托管、非交互式和隐形 - 控制用户体验,但生成相同的 cf-turnstile-response 令牌。对于自动化,所有模式都使用相同的方式求解CaptchaAI 的旋转门求解器成功率100%。对于开发人员来说,主要区别在于检测:托管模式显示可见的 HTML,而不可见模式则需要更深入的页面分析才能找到 sitekey。