Логотип «2Captcha»Перейти на главную страницу
Туториалы по обходу капчи

Эта статья была полезной?

Как решить 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 Copy
<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 Copy
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 Copy
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 Copy
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()
Страница входа не открывается, висит окно согласия Не закрыто окно согласия на обработку данных Закройте окно согласия, после этого станут доступны поля формы входа

Полный список кодов ошибок находится на странице «Коды ошибок», ссылка на неё ниже.

Полезные ссылки