Некоторые страницы отображают две или более CAPTCHA — форму входа с reCAPTCHA и подписку на информационный бюллетень со второй reCAPTCHA или многоэтапную форму, где каждый шаг запускает свою собственную задачу. Каждая CAPTCHA имеет уникальный ключ сайта и целевой элемент, поэтому вам необходимо обнаружить их все, решить их параллельно и внедрить каждый токен в правильный обратный вызов.
Обнаружение нескольких CAPTCHA
Питон с селеном
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com/multi-captcha-page")
# Find all reCAPTCHA iframes
captcha_iframes = driver.find_elements(
By.CSS_SELECTOR, 'iframe[src*="recaptcha/api2/anchor"]'
)
# Extract sitekeys from each iframe's src
import re
captchas = []
for i, iframe in enumerate(captcha_iframes):
src = iframe.get_attribute("src")
match = re.search(r"k=([A-Za-z0-9_-]+)", src)
if match:
captchas.append({
"index": i,
"sitekey": match.group(1),
"iframe": iframe
})
print(f"Found {len(captchas)} CAPTCHAs on page")
for c in captchas:
print(f" [{c['index']}] sitekey: {c['sitekey']}")
Ожидаемый результат:
Found 2 CAPTCHAs on page
[0] sitekey: 6LcXyzABCDEF-login
[1] sitekey: 6LcAbcDEFGHI-signup
JavaScript с Puppeteer
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/multi-captcha-page', {
waitUntil: 'networkidle2'
});
// Extract all reCAPTCHA widgets from the page
const captchas = await page.evaluate(() => {
const widgets = document.querySelectorAll('.g-recaptcha');
return Array.from(widgets).map((el, i) => ({
index: i,
sitekey: el.getAttribute('data-sitekey'),
elementId: el.id || `captcha-${i}`,
callbackName: el.getAttribute('data-callback') || null
}));
});
console.log(`Found ${captchas.length} CAPTCHAs`);
captchas.forEach(c => console.log(` [${c.index}] ${c.sitekey}`));
})();
Параллельное решение всех CAPTCHA
Отправьте все CAPTCHA на CaptchaAI одновременно, а затем опрашивайте, пока каждый из них не будет решен.
Питон
import requests
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
API_KEY = "YOUR_API_KEY"
PAGE_URL = "https://example.com/multi-captcha-page"
def submit_captcha(sitekey):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": PAGE_URL,
"json": "1"
})
result = resp.json()
if result["status"] != 1:
raise Exception(f"Submit error: {result['request']}")
return result["request"]
def poll_result(task_id, timeout=120):
deadline = time.time() + timeout
while time.time() < deadline:
time.sleep(5)
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": "1"
})
result = resp.json()
if result["status"] == 1:
return result["request"]
if result["request"] != "CAPCHA_NOT_READY":
raise Exception(f"Poll error: {result['request']}")
raise TimeoutError(f"Task {task_id} timed out")
def solve_all(captchas):
# Submit all in parallel
task_ids = {}
with ThreadPoolExecutor(max_workers=len(captchas)) as pool:
futures = {
pool.submit(submit_captcha, c["sitekey"]): c["index"]
for c in captchas
}
for future in as_completed(futures):
idx = futures[future]
task_ids[idx] = future.result()
print(f"[captcha-{idx}] Submitted → task {task_ids[idx]}")
# Poll all in parallel
tokens = {}
with ThreadPoolExecutor(max_workers=len(task_ids)) as pool:
futures = {
pool.submit(poll_result, tid): idx
for idx, tid in task_ids.items()
}
for future in as_completed(futures):
idx = futures[future]
tokens[idx] = future.result()
print(f"[captcha-{idx}] Solved")
return tokens
# Example usage
captchas = [
{"index": 0, "sitekey": "6LcXyzABCDEF-login"},
{"index": 1, "sitekey": "6LcAbcDEFGHI-signup"}
]
tokens = solve_all(captchas)
Ожидаемый результат:
[captcha-0] Submitted → task 71823456
[captcha-1] Submitted → task 71823457
[captcha-1] Solved
[captcha-0] Solved
передача токена во внутренний QA endpoint в правильный виджет
Каждый виджет reCAPTCHA имеет собственное текстовое поле g-recaptcha-response. Если существует несколько виджетов, каждая текстовая область вложена в свой контейнер виджетов.
Питон (селен)
def inject_tokens(driver, captchas, tokens):
for c in captchas:
idx = c["index"]
token = tokens[idx]
# Find the textarea within the widget's container
container = driver.find_elements(By.CSS_SELECTOR, ".g-recaptcha")[idx]
textarea = container.find_element(
By.CSS_SELECTOR, 'textarea[name="g-recaptcha-response"]'
)
driver.execute_script(
"arguments[0].value = arguments[1];", textarea, token
)
# Trigger the callback if defined
callback = c.get("callback")
if callback:
driver.execute_script(f"{callback}('{token}');")
print(f"[captcha-{idx}] Token injected")
inject_tokens(driver, captchas, tokens)
JavaScript (Puppeteer)
async function injectTokens(page, captchas, tokens) {
for (const captcha of captchas) {
const token = tokens[captcha.index];
await page.evaluate((idx, tkn, callbackName) => {
const widgets = document.querySelectorAll('.g-recaptcha');
const textarea = widgets[idx].querySelector(
'textarea[name="g-recaptcha-response"]'
);
textarea.value = tkn;
if (callbackName && typeof window[callbackName] === 'function') {
window[callbackName](tkn);
}
}, captcha.index, token, captcha.callbackName);
console.log(`[captcha-${captcha.index}] Token injected`);
}
}
await injectTokens(page, captchas, tokens);
Смешанные типы CAPTCHA
Если на странице присутствуют разные типы CAPTCHA (например, reCAPTCHA + Turnstile), распознавайте каждый тип отдельно:
def detect_all_captchas(driver):
detected = []
# reCAPTCHA
recaptchas = driver.find_elements(By.CSS_SELECTOR, ".g-recaptcha")
for i, el in enumerate(recaptchas):
detected.append({
"type": "userrecaptcha",
"sitekey": el.get_attribute("data-sitekey"),
"label": f"recaptcha-{i}"
})
# Turnstile
turnstiles = driver.find_elements(By.CSS_SELECTOR, ".cf-turnstile")
for i, el in enumerate(turnstiles):
detected.append({
"type": "turnstile",
"sitekey": el.get_attribute("data-sitekey"),
"label": f"turnstile-{i}"
})
return detected
Отправьте каждый из них с соответствующим параметром method — userrecaptcha для reCAPTCHA, turnstile для Turnstile.
Поиск неисправностей
| Проблема | Причина | Исправить |
|---|---|---|
| Токен введен, но форма все еще заблокирована | Обратный звонок не запущен | Проверьте data-callback и вызовите его с помощью токена. |
| Обнаружена только первая капча | Вторая капча загружается лениво | Перед сканированием дождитесь появления всех iframe/widgets. |
| Неправильный токен в неправильном виджете | Несоответствие индекса | Сопоставьте токены с ключами сайта, а не с позиционным индексом |
ERROR_WRONG_GOOGLEKEY |
Sitekey извлечен неправильно | Проверьте ключ сайта из атрибута iframe src или data-sitekey. |
Часто задаваемые вопросы
Может ли страница иметь разные ключи сайта для каждой CAPTCHA?
Да. Каждый виджет может использовать отдельный ключ сайта. Всегда извлекайте ключ сайта для каждого виджета, а не предполагайте, что они используют один и тот же ключ.
Должен ли я решать их последовательно или параллельно?
Параллельно. Каждое решение занимает 15-30 секунд. Параллельное решение двух CAPTCHA занимает столько же времени, сколько и решение одной.
Что, если вторая капча появится только после отправки первой формы?
Повторно сканируйте страницу после каждой отправки формы, чтобы обнаружить вновь отображаемые CAPTCHA. Используйте WebDriverWait (Selenium) или page.waitForSelector (Puppeteer), чтобы дождаться нового виджета.
Решите любое количество CAPTCHA на странице с помощью CaptchaAI
Получите ключ API по адресуcaptchaai.com.
Связанные руководства
- Извлечение CAPTCHA из iframe: решение CAPTCHA во вложенных фреймах
- Извлечение параметров reCAPTCHA из исходного кода страницы
- Параллельное решение CAPTCHA