Эта статья была полезной?
Как решить Turnstile на сайте poczta.o2.pl
Технический специалист
poczta.o2.pl — веб-почта o2.pl. Форму входа защищает Cloudflare Turnstile: пока капча не решена, войти не получится.
Виджет подключается скриптом Cloudflare в режиме explicit — то есть страница сама решает, когда его отрисовать, и делает это уже на форме входа. Токен возвращается в скрытое поле формы. У этого сайта есть одна особенность: поле для токена называется не как обычно. Стандартное имя у Turnstile — cf-turnstile-response, а здесь форма ждёт токен в поле с именем X-Recaptcha. Это не самодеятельность сайта: у Turnstile есть штатная опция response-field-name, и o2.pl через неё переименовывает поле. Само поле создаёт виджет, и его идентификатор меняется при каждой отрисовке, поэтому обращаться к полю нужно по имени.
Ещё до формы входа сайт показывает окно согласия на обработку данных. К Turnstile оно отношения не имеет. Поля формы уже лежат в разметке за этим окном, но кликнуть по ним и заполнить нельзя, пока окно согласия не закрыто.
Параметры задачи
Задача создаётся запросом createTask. Внутри него передаётся объект task с такими параметрами:
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
| type | String | Да | TurnstileTaskProxyless или TurnstileTask |
| websiteURL | String | Да | Полный адрес страницы входа: https://poczta.o2.pl/login/login.html |
| websiteKey | String | Да | Sitekey Turnstile. На этой странице это 0x4AAAAAAAgDIEpfeVYsWUsz |
| action | String | Нет | Значение параметра action вызова turnstile.render, если он задан. На этом сайте не требуется |
| data | String | Нет | Значение параметра cData вызова turnstile.render, если он задан. На этом сайте не требуется |
| pagedata | String | Нет | Значение параметра chlPageData. Нужно для страниц Cloudflare Challenge. На этом сайте не требуется |
| userAgent | String | Нет | User-Agent браузера. Для TurnstileTaskProxyless сервис использует User-Agent своего работника и возвращает его в ответе |
Если нужно решать капчу с вашего IP-адреса, возьмите тип задачи TurnstileTask и добавьте данные прокси: proxyType, proxyAddress, proxyPort, proxyLogin и proxyPassword.
Как найти параметры
Откройте страницу входа и закройте окно согласия, чтобы увидеть форму. Нажмите F12 и на вкладке Elements найдите скрытые поля формы. Виджет здесь отрисовывается вызовом turnstile.render() с объектом настроек, поэтому привычного атрибута data-sitekey на странице нет. Ключ лежит в двух местах: в конфиге в исходнике страницы (TURNSTILE_SITEKEY) и в скрытом поле формы X_Recaptcha-SiteKey:
html
<input type="hidden" name="X_Recaptcha-SiteKey" value="0x4AAAAAAAgDIEpfeVYsWUsz">
<input type="hidden" name="X-Recaptcha" id="cf-chl-widget-qm825_response">
Sitekey у o2.pl на момент написания статьи - 0x4AAAAAAAgDIEpfeVYsWUsz.
Обратите внимание на поле X-Recaptcha — именно в него уходит токен. Идентификатор id у него вида cf-chl-widget-XXXXX_response и меняется при каждой отрисовке, поэтому в скрипте ищите поле по имени X-Recaptcha, а не по id.
Примеры кода
Python + requests
Отправка задачи и опрос результата без дополнительных библиотек.
python
import time
import requests
API_KEY = "ВАШ_API_КЛЮЧ"
task = {
"type": "TurnstileTaskProxyless",
"websiteURL": "https://poczta.o2.pl/login/login.html",
"websiteKey": "0x4AAAAAAAgDIEpfeVYsWUsz",
}
created = requests.post(
"https://api.rucaptcha.com/createTask",
json={"clientKey": API_KEY, "task": task},
timeout=30,
).json()
if created.get("errorId") != 0:
raise SystemExit(f"Ошибка createTask: {created.get('errorDescription')}")
task_id = created["taskId"]
print(f"Задача создана, id {task_id}")
for _ in range(24):
time.sleep(5)
result = requests.post(
"https://api.rucaptcha.com/getTaskResult",
json={"clientKey": API_KEY, "taskId": task_id},
timeout=30,
).json()
if result.get("errorId") != 0:
raise SystemExit(f"Ошибка getTaskResult: {result.get('errorDescription')}")
if result.get("status") == "ready":
print("Токен:", result["solution"]["token"])
break
else:
raise SystemExit("Задача не была решена за отведённое время")
Токен Turnstile — длинная строка, которая начинается с 1. Его нужно записать в поле X-Recaptcha, как показано ниже.
Python + Playwright
Пример открывает страницу, закрывает окно согласия, читает sitekey со страницы, отправляет задачу и записывает токен в поле X-Recaptcha. Логин и пароль подставьте свои.
python
import os
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = os.getenv("APIKEY_RUCAPTCHA", "ВАШ_API_КЛЮЧ")
TARGET_URL = "https://poczta.o2.pl/login/login.html"
LOGIN = "ВАШ_ЛОГИН"
PASSWORD = "ВАШ_ПАРОЛЬ"
def solve(task):
created = requests.post(
"https://api.rucaptcha.com/createTask",
json={"clientKey": API_KEY, "task": task},
timeout=30,
).json()
if created.get("errorId") != 0:
raise RuntimeError(f"Ошибка createTask: {created.get('errorDescription')}")
task_id = created["taskId"]
print(f"Задача создана, id {task_id}")
for _ in range(24):
time.sleep(5)
result = requests.post(
"https://api.rucaptcha.com/getTaskResult",
json={"clientKey": API_KEY, "taskId": task_id},
timeout=30,
).json()
if result.get("errorId") != 0:
raise RuntimeError(f"Ошибка getTaskResult: {result.get('errorDescription')}")
if result.get("status") == "ready":
return result["solution"]["token"]
raise RuntimeError("Задача не была решена за отведённое время")
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
try:
page.goto(TARGET_URL)
# Закрыть окно согласия, если оно появилось
consent = page.get_by_role("button", name="Akceptuję i przechodzę do serwisu")
if consent.count() > 0:
consent.first.click()
# Поля скрытые (type=hidden), поэтому ждём состояние attached, а не visible
page.wait_for_selector('input[name="X-Recaptcha"]', state="attached", timeout=30000)
website_key = page.get_attribute('input[name="X_Recaptcha-SiteKey"]', "value")
print("Sitekey со страницы:", website_key)
token = solve({
"type": "TurnstileTaskProxyless",
"websiteURL": TARGET_URL,
"websiteKey": website_key,
})
print("Токен получен:", token[:30], "…")
page.fill("#login", LOGIN)
page.fill("#password", PASSWORD)
page.evaluate("""(token) => {
const field = document.querySelector('input[name="X-Recaptcha"]');
if (!field) {
throw new Error('Поля X-Recaptcha на странице нет');
}
field.value = token;
// Форму отправляем напрямую, а не кликом по кнопке «Zaloguj się»:
// кнопка проверяет состояние виджета, а form.submit() отправляет поля как есть
field.form.submit();
}""", token)
print("Токен подставлен, форма отправлена")
except Exception as e:
print(f"Ошибка: {e}")
finally:
browser.close()
Два скрытых поля этой формы, X-Recaptcha и X_Recaptcha-SiteKey, имеют тип hidden и видимыми не станут. Если ждать их через page.wait_for_selector без state="attached", вызов всегда упрётся в таймаут: по умолчанию Playwright ждёт видимый элемент. Поэтому в примере указано state="attached".
Как использовать полученный токен
Токен из solution.token записывается в значение скрытого поля с именем X-Recaptcha. Стандартного поля cf-turnstile-response на этой странице нет, поэтому запись токена туда ничего не даст — нужно именно поле X-Recaptcha.
Но одной записи в поле мало. Кнопка «Zaloguj się» перед отправкой проверяет не значение поля, а внутреннее состояние виджета: если просто вписать токен и нажать кнопку, форма выдаст ошибку «Musisz potwierdzić, że jesteś człowiekiem» и не отправится. Обход — отправить форму напрямую, минуя обработчик кнопки:
javascript
document.querySelector('input[name="X-Recaptcha"]').value = "ПОЛУЧЕННЫЙ_ТОКЕН";
document.querySelector('form').submit();
Нативный form.submit() отправляет поля как есть, вместе с X-Recaptcha, — это то же самое, что сайт делает внутри себя после прохождения проверки. Форма уходит POST-запросом на /login/v2/sso/preauth.
Вместе с токеном сервис возвращает поле solution.userAgent — User-Agent, под которым токен был выпущен. Turnstile привязывает токен к браузеру, поэтому запрос на вход надёжнее слать с тем же User-Agent, что пришёл в ответе. Для типа TurnstileTaskProxyless задать свой User-Agent в задаче нельзя: сервис решает капчу под User-Agent своего работника и его же возвращает — используйте именно это значение.
Тестирование в режиме песочницы
Прежде чем встраивать вызов в скрипт, параметры удобно проверить в режиме песочницы. Капча при этом не уходит работникам сервиса, а возвращается вам.
- Прочитайте со страницы sitekey и сразу отправьте задачу через createTask.
- Откройте настройки песочницы, переключите роль на работника и войдите в приложение с ключом этой роли.
- Если виджет Turnstile открылся и решается, sitekey прочитан верно.
После проверки режим нужно выключить, иначе новые задачи так и будут приходить вам, а не работникам.
Частые ошибки и решения
| Ошибка или проблема | Причина | Решение |
|---|---|---|
| Токен получен, но форма его не принимает | Токен записан в стандартное поле cf-turnstile-response, которого здесь нет | Записывайте токен в поле с именем X-Recaptcha |
| Скрипт не находит поле по id | id поля вида cf-chl-widget-XXXXX_response меняется при каждой отрисовке | Ищите поле по имени X-Recaptcha, а не по id |
| Скрипт зависает на ожидании поля X-Recaptcha | Поле скрытое, а Playwright по умолчанию ждёт видимый элемент | Добавьте state="attached" в wait_for_selector |
| Клик по кнопке входа даёт «Musisz potwierdzić, że jesteś człowiekiem» | Форма проверяет внутреннее состояние виджета, а не значение поля | Отправляйте форму напрямую: form.submit() |
| Страница входа не открывается, висит окно согласия | Не закрыто окно согласия на обработку данных | Закройте окно согласия, после этого станут доступны поля формы входа |
Полный список кодов ошибок находится на странице «Коды ошибок», ссылка на неё ниже.
Полезные ссылки
- Документация API по Cloudflare Turnstile: https://rucaptcha.com/api-docs/cloudflare-turnstile
- Сервис обхода Cloudflare Turnstile: https://rucaptcha.com/p/cloudflare-turnstile
- Песочница для тестирования API: https://rucaptcha.com/setting#sandbox
- Коды ошибок: https://rucaptcha.com/api-docs/error-codes
- Работа с прокси: https://rucaptcha.com/api-docs/proxy
- Python SDK на GitHub: https://github.com/2captcha/2captcha-python
- Другие примеры обхода капч на сайтах: https://rucaptcha.com/h?category=sites