每种验证码类型都有不同的解决时间。对所有类型使用单一超时要么会在快速验证码上浪费时间,要么在较慢的验证码上过早超时。配置每种类型的超时以获得最佳性能。
按类型推荐的超时
| 验证码类型 | 平均求解时间 | 初始等待 | 轮询间隔 | 最大超时 |
|---|---|---|---|---|
| 图片/OCR | 2-5秒 | 3秒 | 3秒 | 30秒 |
| reCAPTCHA v2 | 10-20秒 | 10秒 | 5秒 | 90年代 |
| reCAPTCHA v3 | 5-15秒 | 5秒 | 5秒 | 60年代 |
| reCAPTCHA 企业版 | 10-25秒 | 10秒 | 5秒 | 120秒 |
| 隐形验证码 | 10-20秒 | 10秒 | 5秒 | 90年代 |
| 旋转门 | 3-10秒 | 3秒 | 3秒 | 45秒 |
| Cloudflare 验证流程 | 10-30秒 | 10秒 | 5秒 | 120秒 |
| GeeTest v3 | 5-15秒 | 5秒 | 5秒 | 60年代 |
| 劳工统计局 | 3-10秒 | 3秒 | 5秒 | 45秒 |
类型感知解算器
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://ocr.captchaai.com"
# Per-type timeout configuration
TIMEOUT_CONFIG = {
"base64": {
"initial_wait": 3,
"poll_interval": 3,
"max_timeout": 30,
},
"userrecaptcha": {
"initial_wait": 10,
"poll_interval": 5,
"max_timeout": 90,
},
"userrecaptcha_v3": {
"initial_wait": 5,
"poll_interval": 5,
"max_timeout": 60,
},
"turnstile": {
"initial_wait": 3,
"poll_interval": 3,
"max_timeout": 45,
},
"cloudflare_challenge": {
"initial_wait": 10,
"poll_interval": 5,
"max_timeout": 120,
},
"geetest": {
"initial_wait": 5,
"poll_interval": 5,
"max_timeout": 60,
},
"bls": {
"initial_wait": 3,
"poll_interval": 5,
"max_timeout": 45,
},
"default": {
"initial_wait": 10,
"poll_interval": 5,
"max_timeout": 120,
},
}
def get_config_key(method, **params):
"""Determine config key from method and parameters."""
if method == "userrecaptcha" and params.get("version") == "v3":
return "userrecaptcha_v3"
return method
def solve(method, **params):
"""Solve CAPTCHA with type-appropriate timeouts."""
config_key = get_config_key(method, **params)
config = TIMEOUT_CONFIG.get(config_key, TIMEOUT_CONFIG["default"])
# Submit task
data = {"key": API_KEY, "method": method, "json": 1}
data.update(params)
resp = requests.post(f"{BASE_URL}/in.php", data=data, timeout=30)
result = resp.json()
if result.get("status") != 1:
raise RuntimeError(f"Submit error: {result.get('request')}")
task_id = result["request"]
# Wait before first poll
time.sleep(config["initial_wait"])
# Poll with type-specific interval and timeout
start = time.time()
while time.time() - start < config["max_timeout"]:
resp = requests.get(f"{BASE_URL}/res.php", params={
"key": API_KEY, "action": "get",
"id": task_id, "json": 1,
}, timeout=15)
data = resp.json()
if data["request"] != "CAPCHA_NOT_READY":
elapsed = time.time() - start + config["initial_wait"]
print(f"Solved {method} in {elapsed:.1f}s")
return data["request"]
time.sleep(config["poll_interval"])
raise TimeoutError(
f"{method} timeout after {config['max_timeout']}s"
)
# Usage — each type uses optimal timeouts automatically
# Image (fast: 3s wait, 3s poll, 30s max)
token = solve("base64", body=base64_image)
# reCAPTCHA v2 (medium: 10s wait, 5s poll, 90s max)
token = solve("userrecaptcha", googlekey="KEY", pageurl="https://example.com")
# Turnstile (fast: 3s wait, 3s poll, 45s max)
token = solve("turnstile", sitekey="KEY", pageurl="https://example.com")
动态超时调整
根据观察到的求解时间调整超时:
import statistics
class AdaptiveTimeoutSolver:
"""Adjusts timeouts based on historical solve times."""
def __init__(self, api_key):
self.api_key = api_key
self.base = "https://ocr.captchaai.com"
self.history = {} # method -> [solve_times]
def solve(self, method, **params):
config = self._get_config(method)
# Submit
data = {"key": self.api_key, "method": method, "json": 1}
data.update(params)
resp = requests.post(f"{self.base}/in.php", data=data, timeout=30)
task_id = resp.json()["request"]
time.sleep(config["initial_wait"])
start = time.time()
# Poll with adaptive timeout
while time.time() - start < config["max_timeout"]:
resp = requests.get(f"{self.base}/res.php", params={
"key": self.api_key, "action": "get",
"id": task_id, "json": 1,
})
data = resp.json()
if data["request"] != "CAPCHA_NOT_READY":
elapsed = time.time() - start + config["initial_wait"]
self._record(method, elapsed)
return data["request"]
time.sleep(config["poll_interval"])
raise TimeoutError(f"Timeout after {config['max_timeout']}s")
def _get_config(self, method):
"""Get timeout config, adjusted by history."""
base = TIMEOUT_CONFIG.get(method, TIMEOUT_CONFIG["default"])
# If we have history, adjust max_timeout
times = self.history.get(method, [])
if len(times) >= 5:
p95 = sorted(times)[int(len(times) * 0.95)]
adjusted_timeout = max(p95 * 2, base["max_timeout"])
return {**base, "max_timeout": adjusted_timeout}
return base
def _record(self, method, elapsed):
if method not in self.history:
self.history[method] = []
self.history[method].append(elapsed)
# Keep last 100 entries
if len(self.history[method]) > 100:
self.history[method] = self.history[method][-100:]
def get_stats(self, method):
times = self.history.get(method, [])
if not times:
return None
return {
"count": len(times),
"mean": statistics.mean(times),
"median": statistics.median(times),
"p95": sorted(times)[int(len(times) * 0.95)],
"max": max(times),
}
# Usage
solver = AdaptiveTimeoutSolver("YOUR_API_KEY")
token = solver.solve("turnstile", sitekey="KEY", pageurl="https://example.com")
print(solver.get_stats("turnstile"))
提交超时与轮询超时
要配置两种不同的超时:
Submit timeout: How long to wait for the API to accept your task
→ Set to 30s (network issues only)
Poll timeout: How long to wait for the solve result
→ Varies by CAPTCHA type (30s to 120s)
# Submit timeout (fixed, short)
resp = requests.post(
f"{BASE_URL}/in.php", data=data,
timeout=30, # 30s is plenty for submission
)
# Poll timeout (varies by type)
resp = requests.get(
f"{BASE_URL}/res.php", params=params,
timeout=15, # 15s per individual poll request
)
# Overall polling loop timeout: 30-120s depending on type
故障排除
| 问题 | 原因 | 处理方式 |
|---|---|---|
| 图像验证码在 120 秒时超时 | 超时太长,浪费时间 | 图像时间缩短至 30 秒 |
| reCAPTCHA v2 超时 | 最大超时时间太短 | reCAPTCHA v2 至少使用 90 秒 |
| 第一次轮询总是返回“未准备好” | 初始等待时间太短 | 增加每个类型表的初始等待 |
| 过多的轮询请求 | 轮询间隔太短 | 对于令牌类型使用 5 秒,对于图像使用 3 秒 |
常问问题
为什么不对所有事情使用相同的超时?
图像验证码的 120 秒超时(在 3 秒内解决)会在失败时浪费 117 秒。 reCAPTCHA Enterprise 的 30 秒超时可能会导致有效解决超时。每个类型的超时优化这两种情况。
如果我将超时设置得太低会发生什么?
您将收到错误的超时错误。 CaptchaAI 方面仍可能完成任务,但您不会收到结果。将超时设置至少为平均求解时间的 2 倍。
我应该在高峰时段增加超时吗?
一般不会。 CaptchaAI 基于人工智能的求解保持一致的速度。如果您发现求解时间增加,请首先检查您的网络延迟。
相关指南
- 速率限制和 429 响应
- 重试逻辑实现
优化每一毫秒——尝试CaptchaAI具有类型调整的超时。