Một số trang web sử dụng reCAPTCHA trên trang đăng nhập và Turnstile trên trang thanh toán. Những người khác kiểm tra A/B giữa các nhà cung cấp - cùng một URL hiển thị reCAPTCHA cho một khách truy cập và Turnstile cho một khách truy cập khác. Mã hóa cứng một phương pháp giải duy nhất có nghĩa là quá trình tự động hóa của bạn bị gián đoạn bất cứ khi nào nó gặp loại khác.
Tại sao các trang web sử dụng nhiều nhà cung cấp CAPTCHA
| Kịch bản | Nó xuất hiện như thế nào |
|---|---|
| Các trang khác nhau, nhà cung cấp khác nhau | Đăng nhập = reCAPTCHA, thanh toán = Turnstile |
| Nhà cung cấp thử nghiệm A/B | Cùng một trang hiển thị ngẫu nhiên một trong hai loại |
| Đang di chuyển | Trang cũ có reCAPTCHA, trang mới có Turnstile |
| Dự phòng khi thất bại | Nhà cung cấp chính không thành công → quay trở lại nhà cung cấp phụ |
| Sự thay đổi khu vực | reCAPTCHA cho khách truy cập Hoa Kỳ, Turnstile cho EU (GDPR) |
Python: Tự động phát hiện và giải quyết
import requests
import time
import re
from dataclasses import dataclass
API_KEY = "YOUR_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
@dataclass
class CaptchaInfo:
provider: str # "recaptcha" or "turnstile"
method: str # API method name
sitekey: str
pageurl: str
response_field: str # Form field name for the token
def detect_captcha_type(html, pageurl):
"""
Detect which CAPTCHA provider is on the page.
Returns CaptchaInfo or None.
"""
# Check for Turnstile
turnstile_match = re.search(
r'class=["\'][^"\']*cf-turnstile[^"\']*["\'][^>]*data-sitekey=["\']([^"\']+)["\']',
html,
)
if not turnstile_match:
turnstile_match = re.search(
r'data-sitekey=["\']([^"\']+)["\'][^>]*class=["\'][^"\']*cf-turnstile',
html,
)
if turnstile_match:
return CaptchaInfo(
provider="turnstile",
method="turnstile",
sitekey=turnstile_match.group(1),
pageurl=pageurl,
response_field="cf-turnstile-response",
)
# Check for reCAPTCHA
recaptcha_match = re.search(
r'class=["\'][^"\']*g-recaptcha[^"\']*["\'][^>]*data-sitekey=["\']([^"\']+)["\']',
html,
)
if not recaptcha_match:
recaptcha_match = re.search(
r'data-sitekey=["\']([^"\']+)["\'][^>]*class=["\'][^"\']*g-recaptcha',
html,
)
# Also check for script-rendered reCAPTCHA
if not recaptcha_match:
recaptcha_match = re.search(
r'grecaptcha\.render\([^,]+,\s*\{[^}]*["\']sitekey["\']\s*:\s*["\']([^"\']+)["\']',
html,
)
if recaptcha_match:
return CaptchaInfo(
provider="recaptcha",
method="userrecaptcha",
sitekey=recaptcha_match.group(1),
pageurl=pageurl,
response_field="g-recaptcha-response",
)
return None
def solve_captcha(info):
"""Solve any detected CAPTCHA type via CaptchaAI."""
params = {
"key": API_KEY,
"method": info.method,
"json": 1,
}
if info.method == "userrecaptcha":
params["googlekey"] = info.sitekey
params["pageurl"] = info.pageurl
elif info.method == "turnstile":
params["sitekey"] = info.sitekey
params["pageurl"] = info.pageurl
resp = requests.post(SUBMIT_URL, data=params, timeout=30).json()
if resp.get("status") != 1:
raise RuntimeError(f"Submit failed: {resp.get('request')}")
task_id = resp["request"]
for _ in range(60):
time.sleep(5)
poll = requests.get(RESULT_URL, params={
"key": API_KEY, "action": "get",
"id": task_id, "json": 1,
}, timeout=15).json()
if poll.get("request") == "CAPCHA_NOT_READY":
continue
if poll.get("status") == 1:
return poll["request"]
raise RuntimeError(f"Solve failed: {poll.get('request')}")
raise RuntimeError("Timeout")
def process_page(session, url):
"""Fetch page, detect CAPTCHA type, solve, and return form-ready data."""
response = session.get(url)
captcha_info = detect_captcha_type(response.text, url)
if not captcha_info:
print(f"No CAPTCHA detected on {url}")
return None
print(f"Detected {captcha_info.provider} on {url}")
print(f" Sitekey: {captcha_info.sitekey[:30]}...")
token = solve_captcha(captcha_info)
print(f" Solved: {token[:30]}...")
return {
"provider": captcha_info.provider,
"response_field": captcha_info.response_field,
"token": token,
}
# Usage: Handle multiple pages with different providers
session = requests.Session()
pages = [
"https://staging.example.com/qa-login", # Might have reCAPTCHA
"https://example.com/checkout", # Might have Turnstile
]
for url in pages:
result = process_page(session, url)
if result:
form_data = {result["response_field"]: result["token"]}
# Add other form fields...
# session.post(url, data=form_data)
JavaScript: Phát hiện CAPTCHA động
const API_KEY = "YOUR_API_KEY";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
function detectCaptchaType(html, pageurl) {
// Turnstile
const turnstileMatch = html.match(/cf-turnstile[^>]*data-sitekey=["']([^"']+)["']/);
if (turnstileMatch) {
return { provider: "turnstile", method: "turnstile", sitekey: turnstileMatch[1], pageurl, field: "cf-turnstile-response" };
}
// reCAPTCHA
const recaptchaMatch = html.match(/g-recaptcha[^>]*data-sitekey=["']([^"']+)["']/);
if (recaptchaMatch) {
return { provider: "recaptcha", method: "userrecaptcha", sitekey: recaptchaMatch[1], pageurl, field: "g-recaptcha-response" };
}
// Script-rendered reCAPTCHA
const scriptMatch = html.match(/sitekey["']\s*:\s*["']([^"']+)["']/);
if (scriptMatch) {
return { provider: "recaptcha", method: "userrecaptcha", sitekey: scriptMatch[1], pageurl, field: "g-recaptcha-response" };
}
return null;
}
async function solveCaptcha(info) {
const body = new URLSearchParams({ key: API_KEY, method: info.method, json: "1" });
if (info.method === "userrecaptcha") { body.set("googlekey", info.sitekey); body.set("pageurl", info.pageurl); }
else if (info.method === "turnstile") { body.set("sitekey", info.sitekey); body.set("pageurl", info.pageurl); }
const resp = await (await fetch(SUBMIT_URL, { method: "POST", body })).json();
if (resp.status !== 1) throw new Error(`Submit: ${resp.request}`);
const taskId = resp.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
const poll = await (await fetch(url)).json();
if (poll.request === "CAPCHA_NOT_READY") continue;
if (poll.status === 1) return poll.request;
throw new Error(`Solve: ${poll.request}`);
}
throw new Error("Timeout");
}
async function processPage(url) {
const response = await fetch(url);
const html = await response.text();
const info = detectCaptchaType(html, url);
if (!info) { console.log(`No CAPTCHA on ${url}`); return null; }
console.log(`${info.provider} detected on ${url}`);
const token = await solveCaptcha(info);
return { provider: info.provider, field: info.field, token };
}
// Usage
const pages = ["https://staging.example.com/qa-login", "https://example.com/checkout"];
for (const url of pages) {
const result = await processPage(url);
if (result) {
console.log(`Solved ${result.provider}: ${result.token.substring(0, 30)}...`);
}
}
Tài liệu tham khảo phát hiện nhà cung cấp
| nhà cung cấp | Điểm đánh dấu HTML | URL tập lệnh | Trường phản hồi |
|---|---|---|---|
| reCAPTCHA v2 | class="g-recaptcha" |
google.com/recaptcha/api.js |
g-recaptcha-response |
| Cloudflare Turnstile | class="cf-turnstile" |
challenges.cloudflare.com/turnstile |
cf-turnstile-response |
| hCaptcha | class="h-captcha" |
js.hcaptcha.com/1/api.js |
h-captcha-response |
Khắc phục sự cố
| Vấn đề | Nguyên nhân | Cách xử lý |
|---|---|---|
| Đã phát hiện loại CAPTCHA sai | Regex khớp sai phần tử | Trước tiên, hãy kiểm tra tên lớp dành riêng cho nhà cung cấp, không chỉ data-sitekey |
| Mã thông báo bị từ chối sau khi giải quyết đúng | Đã sử dụng tên trường phản hồi sai | Khớp tên trường với nhà cung cấp: g-recaptcha-response vs cf-turnstile-response |
| Loại CAPTCHA thay đổi giữa các lần truy cập | Thử nghiệm A/B hoặc lựa chọn dựa trên địa lý | Luôn phát hiện động; không bao giờ mã hóa nhà cung cấp |
| Cả hai nhà cung cấp được phát hiện trên một trang | Một người có thể bị ẩn/inactive | Kiểm tra mức độ hiển thị của phần tử - chỉ giải quyết CAPTCHA hiển thị |
| Không phát hiện được CAPTCHA do tập lệnh hiển thị | Không có điểm đánh dấu HTML trong nguồn | Kiểm tra các lệnh gọi grecaptcha.render() hoặc turnstile.render() trong tập lệnh |
Câu hỏi thường gặp
Một trang có thể sử dụng đồng thời cả reCAPTCHA và Turnstile không?
Hiếm khi ở cùng một hình thức nhưng nó xảy ra trên các phần khác nhau của trang web. Nếu cả hai đều xuất hiện trên một trang, thường chỉ có một trang đang hoạt động — hãy kiểm tra xem tiện ích nào hiển thị và có data-sitekey không trống.
CaptchaAI có sử dụng cùng một API cho cả hai nhà cung cấp không?
Các điểm cuối giống nhau (in.php / res.php) nhưng có giá trị method khác nhau. reCAPTCHA sử dụng method=userrecaptcha với googlekey, trong khi Turnstile sử dụng method=turnstile với sitekey. Mẫu tự động phát hiện xử lý ánh xạ này.
Làm cách nào để xử lý chuyển đổi dự phòng của nhà cung cấp?
Nếu một trang web chuyển từ reCAPTCHA sang Turnstile giữa phiên (ví dụ: sau khi reCAPTCHA không tải được), hãy phát hiện lại loại CAPTCHA trên mỗi yêu cầu trang thay vì lưu vào bộ nhớ đệm nhà cung cấp từ lần truy cập đầu tiên.
bài viết liên quan
- Cách giải quyết cuộc gọi lại Recaptcha V2 bằng Api
- Cloudflare Challenge Vs Phát hiện cửa quay
- So sánh Geetest và Cloudflare Turnstile
Các bước tiếp theo
Xử lý các trang web có nhiều nhà cung cấp CAPTCHA —lấy khóa API CaptchaAI của bạnvà thực hiện tự động phát hiện.
Hướng dẫn liên quan: