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

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

Как обойти Cloudflare Turnstile на сайте StockX

Грегори Фишер
Грегори Фишер

Технический специалист

Страница входа и регистрации на StockX (accounts.stockx.com) защищена капчей Cloudflare Turnstile. Главная особенность реализации Turnstile на этом сайте заключается в том, что URL страницы содержит длинный динамический параметр state, который меняется при каждой новой сессии или попытке входа.

Для успешного решения критически важно передавать в API точный URL, на котором была инициирована капча, вместе со статическим websiteKey. В этом руководстве разберём, как извлечь параметры, отправить задачу и внедрить полученный токен.

Параметры задачи

Для решения Cloudflare Turnstile используется тип задачи TurnstileTaskProxyless.

Параметр Тип Обязательный Описание
type String Да Должен быть установлен в TurnstileTaskProxyless
websiteURL String Да Полный URL страницы, где находится капча (включая динамический параметр state)
websiteKey String Да Статический ключ сайта (начинается с 0x4...)
action String Нет Необязательный параметр действия (если используется на сайте)

Как найти параметры

  1. Откройте страницу входа StockX: https://accounts.stockx.com/u/login/identifier
  2. Нажмите F12, чтобы открыть инструменты разработчика (DevTools), и перейдите на вкладку Сеть (Network)
  3. Включите сохранение логов (Preserve log), так как страница может перезагружаться или обновлять URL
  4. Введите любые данные в форму и нажмите кнопку продолжения (например, Continue), чтобы спровоцировать появление капчи
  5. В фильтре вкладки Сеть введите turnstile или challenges.cloudflare.com
  6. Найдите запрос к API Cloudflare. В параметрах этого запроса или в исходном коде страницы (поиск по data-sitekey) вы найдёте значение websiteKey (например, 0x4AAAAAACg7RNT7No-kJ-Ms)
  7. Важно: скопируйте полный URL из адресной строки браузера в тот момент, когда капча активна. Он будет выглядеть примерно так:
Copy
https://accounts.stockx.com/u/login/identifier?state=hKFo2SBwV1NKQThCSU1MbHd1bTJRODdkYm03NkFjaTluMWY2cKFur3VuaXZlcnNhbC1sb2dpbqN0aWTZIHFvRmxVcGN6Sk52RmNqbmQxS3JHUEk3d2ZwaGdhZWR3o2NpZNkgT1Z4cnQ0VkpxVHg3TElVS2Q2NjFXMER1Vk1wY0ZCeUQ&ui_locales=en

Внимание: использование URL без параметра state или с устаревшим state приведёт к ошибке решения, так как Turnstile строго проверяет соответствие URL и сессии.

Примеры кода

Python + requests

Пример отправки задачи и опроса результата с использованием библиотеки requests.

python Copy
import requests
import time

API_KEY = 'ВАШ_API_КЛЮЧ'
# URL должен быть скопирован целиком, включая длинный параметр state
WEBSITE_URL = 'https://accounts.stockx.com/u/login/identifier?state=hKFo2SBwV1NKQThCSU1MbHd1bTJRODdkYm03NkFjaTluMWY2cKFur3VuaXZlcnNhbC1sb2dpbqN0aWTZIHFvRmxVcGN6Sk52RmNqbmQxS3JHUEk3d2ZwaGdhZWR3o2NpZNkgT1Z4cnQ0VkpxVHg3TElVS2Q2NjFXMER1Vk1wY0ZCeUQ&ui_locales=en'
WEBSITE_KEY = '0x4AAAAAACg7RNT7No-kJ-Ms'

# 1. Отправка задачи
url = 'https://api.2captcha.com/createTask'
headers = {
    'Content-Type': 'application/json',
    'X-API-Key': API_KEY
}
payload = {
    "clientKey": API_KEY,
    "task": {
        "type": "TurnstileTaskProxyless",
        "websiteURL": WEBSITE_URL,
        "websiteKey": WEBSITE_KEY
    }
}

response = requests.post(url, headers=headers, json=payload)
result = response.json()

if result.get('errorId') == 0:
    task_id = result.get('taskId')
    print(f"Задача создана, ID: {task_id}")

    # 2. Ожидание решения
    res_url = 'https://api.2captcha.com/getTaskResult'
    while True:
        time.sleep(5)  # Пауза между запросами

        res_payload = {
            "clientKey": API_KEY,
            "taskId": task_id
        }

        res_response = requests.post(res_url, headers=headers, json=res_payload).json()

        if res_response.get('errorId') == 0 and res_response.get('status') == 'ready':
            print("Капча успешно решена!")
            token = res_response['solution']['token']
            print(f"Токен: {token}")
            break
        elif res_response.get('errorId') != 0:
            print(f"Ошибка при получении результата: {res_response.get('errorDescription')}")
            break
else:
    print(f"Ошибка создания задачи: {result.get('errorDescription')}")

Python + Playwright

Пример автоматизации, который динамически извлекает текущий URL и ключ, отправляет задачу и получает токен.

python Copy
from playwright.sync_api import sync_playwright
import requests
import time

API_KEY = 'ВАШ_API_КЛЮЧ'
TARGET_URL = 'https://accounts.stockx.com/u/login/identifier'

def solve_stockx_turnstile():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()

        try:
            page.goto(TARGET_URL)

            # Здесь необходимо выполнить действие, вызывающее капчу
            # Например, ввести email и нажать Continue
            # page.fill('input[type="email"]', 'test@example.com')
            # page.click('button[type="submit"]')

            # Ожидаем появления виджета Turnstile или обновления URL
            page.wait_for_selector('iframe[src*="challenges.cloudflare.com"]', timeout=10000)

            # Извлекаем актуальный URL (с динамическим state) и websiteKey
            current_url = page.url
            website_key = page.evaluate("""
                () => {
                    const iframe = document.querySelector('iframe[src*="challenges.cloudflare.com"]');
                    if (iframe) {
                        const src = new URL(iframe.src);
                        return src.searchParams.get('sitekey');
                    }
                    return null;
                }
            """)

            if not website_key:
                # Альтернативный поиск в data-sitekey
                website_key = page.evaluate("document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')")

            print(f"URL: {current_url}")
            print(f"Key: {website_key}")

            # Отправка в API
            api_url = 'https://api.2captcha.com/createTask'
            headers = {'Content-Type': 'application/json', 'X-API-Key': API_KEY}
            payload = {
                "clientKey": API_KEY,
                "task": {
                    "type": "TurnstileTaskProxyless",
                    "websiteURL": current_url,
                    "websiteKey": website_key
                }
            }

            task_response = requests.post(api_url, headers=headers, json=payload).json()
            task_id = task_response.get('taskId')

            # Ожидание решения
            res_url = 'https://api.2captcha.com/getTaskResult'
            token = None
            for _ in range(20):  # Максимум ~100 секунд ожидания
                time.sleep(5)
                res = requests.post(res_url, headers=headers, json={"clientKey": API_KEY, "taskId": task_id}).json()
                if res.get('status') == 'ready':
                    token = res['solution']['token']
                    break
                if res.get('errorId') != 0:
                    print(f"Ошибка API: {res.get('errorDescription')}")
                    break

            if token:
                print(f"Токен получен: {token[:30]}...")
                # Переходим к внедрению токена (см. раздел ниже)
            else:
                print("Не удалось получить токен.")

        except Exception as e:
            print(f"Ошибка: {e}")
        finally:
            pass  # browser.close() — раскомментируйте для закрытия браузера

if __name__ == '__main__':
    solve_stockx_turnstile()

Как использовать полученный токен (варианты внедрения)

Поскольку точный механизм обработки токена на StockX может обновляться, ниже приведены наиболее распространённые варианты внедрения токена Turnstile. Потребуется проверить исходный код страницы (вкладка Elements), чтобы определить, какой из них используется.

Вариант 1: скрытое поле формы (наиболее частый). Сайт ожидает токен в скрытом input с именем cf-turnstile-response (или похожим) внутри формы.

python Copy
page.evaluate(f"""
    let input = document.querySelector('input[name="cf-turnstile-response"]');
    if (!input) {{
        input = document.createElement('input');
        input.type = 'hidden';
        input.name = 'cf-turnstile-response';
        document.querySelector('form').appendChild(input);
    }}
    input.value = "{token}";
""")

Вариант 2: JavaScript callback. Виджет инициализирован с параметром data-callback. В этом случае нужно вызвать эту функцию вручную, передав ей токен.

python Copy
# Замените 'turnstileCallback' на реальное имя функции из атрибута data-callback
page.evaluate(f"""
    if (typeof turnstileCallback === 'function') {{
        turnstileCallback("{token}");
    }}
""")

Вариант 3: глобальный объект Turnstile. Иногда сайт читает токен из глобального объекта или требует явного обновления состояния виджета.

python Copy
page.evaluate(f"""
    // Попытка найти экземпляр виджета и установить токен
    if (window.turnstile) {{
        // В некоторых реализациях требуется вызвать метод reset или установить значение вручную
        console.log("Turnstile instance found, token ready for injection");
    }}
    // Принудительное изменение значения, если сайт использует кастомную логику
    window.CF_TURNSTILE_TOKEN = "{token}";
""")

Тестирование в режиме песочницы

Перед запуском автоматизации проверьте корректность извлечённых параметров в песочнице 2Captcha.

  1. Отправьте задачу через API, используя ваш websiteURL и websiteKey
  2. Перейдите в песочницу и переключитесь в режим Работник (Worker)
  3. Если вы получите эту задачу и увидите корректно загружающийся виджет Turnstile, который можно решить, значит, параметры собраны верно. Если виджет выдаёт ошибку (например, Invalid domain), проверьте, что websiteURL скопирован полностью, вместе с параметром state

Частые ошибки и решения

Ошибка / проблема Причина Решение
ERROR_INVALID_SITE_KEY Неверный websiteKey или несоответствие домена Убедитесь, что ключ начинается с 0x4 и скопирован без лишних пробелов
Решение не приходит, CAPCHA_NOT_READY бесконечно Неверный или устаревший websiteURL Убедитесь, что вы передаёте URL вместе с длинным параметром state, который был актуален в момент запроса
Форма не отправляется после внедрения токена Токен вставлен не в то поле или не вызван callback Изучите вкладку Network при ручной отправке формы. Найдите запрос, уходящий на сервер, и посмотрите, в каком именно поле (или заголовке) передаётся токен Turnstile
ERROR_PROXY_* (если используется не Proxyless) Turnstile на StockX обычно не требует прокси, если вы решаете его в том же окружении, где и работаете Используйте TurnstileTaskProxyless. Если сайт блокирует ваш IP, настраивайте прокси на уровне Playwright/Selenium, а не в задаче API

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