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

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

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

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

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

Сайт iFood (ifood.com.br) использует защиту Cloudflare Turnstile для защиты форм входа и регистрации. Главная особенность этой реализации заключается в том, что параметры pagedata, data, action и userAgent являются строго динамическими и меняются при каждой загрузке страницы или попытке взаимодействия.

Использование устаревших или вручную скопированных параметров приведет к ошибке. Единственный надежный способ получить актуальные данные для API v2 это внедрить специальный скрипт перехвата в консоль браузера строго до того, как капча загрузится.

Параметры задачи (API v2)

Для отправки задачи через современный API v2 используется эндпоинт createTask. Объект task должен содержать следующие параметры в строгом соответствии с документацией:

Параметр Тип Обязательный Описание
type String Да Тип задачи: TurnstileTaskProxyless или TurnstileTask
websiteURL String Да Полный URL целевой веб-страницы, где загружается капча. Мы не открываем страницу, не проблема, если она доступна только авторизованным пользователям.
websiteKey String Да Ключ сайта Turnstile. Можно найти в свойстве data-sitekey элемента div Turnstile.
action String Нет* Требуется для страниц Cloudflare Challenge. Значение параметра action вызова turnstile.render.
data String Нет* Требуется для страниц Cloudflare Challenge. Значение параметра cData вызова turnstile.render.
pagedata String Нет* Требуется для страниц Cloudflare Challenge. Значение параметра chlPageData вызова turnstile.render.
userAgent String Нет User-Agent браузера. Должен байт-в-байт совпадать с тем, что используется в запросе.

* Для сайта iFood эти параметры являются обязательными, так как используется режим Cloudflare Challenge.

Как перехватить динамические параметры

ВАЖНО: Скрипт перехвата необходимо внедрять в консоль браузера ДО загрузки капчи. Если вы выполните его после того, как виджет уже появился на экране, он не сработает, так как метод render уже будет вызван и параметры будут упущены.

Эти параметры меняются при каждой загрузке страницы. Чтобы их получить, нужно внедрить специальный скрипт перехвата в консоль браузера (DevTools) сразу после открытия страницы, до любых действий, которые могут вызвать появление капчи.

Инструкция:

  1. Откройте страницу iFood (например, форму входа) в режиме инкогнито и нажмите F12 (Инструменты разработчика).
  2. Перейдите на вкладку Консоль (Console).
  3. Сразу же вставьте следующий скрипт и нажмите Enter. Не обновляйте страницу после этого!
javascript Copy
const i = setInterval(()=>{
    if (window.turnstile) {
        clearInterval(i)
        window.turnstile.render = (a, b) => {
            let p = {
                type: "TurnstileTaskProxyless",
                websiteKey: b.sitekey,
                websiteURL: window.location.href,
                data: b.cData,
                pagedata: b.chlPageData,
                action: b.action,
                userAgent: navigator.userAgent
            }
            console.log(JSON.stringify(p))
            window.tsCallback = b.callback
            return 'foo'
        }
    }
}, 10)
  1. В консоли мгновенно появится JSON-объект с актуальными параметрами, полностью готовый для вставки в поле task запроса API v2. Скопируйте его.
  2. Немедленно отправьте эти параметры в запросе на решение через API. Не обновляйте страницу, иначе параметры станут недействительными.

Обратите внимание: скрипт не только извлекает параметры, но и сохраняет оригинальный callback виджета в глобальную переменную window.tsCallback. Именно через эту функцию необходимо передать полученный токен.

Примеры кода

Python + requests (API v2)

Пример отправки задачи с параметрами, скопированными из консоли, через эндпоинты createTask и getTaskResult.

python Copy
import requests
import time
import json

API_KEY = 'ВАШ_API_КЛЮЧ'

# Вставьте сюда JSON, скопированный из консоли браузера (это будет содержимое объекта task)
captured_task = {
    "type": "TurnstileTaskProxyless",
    "websiteKey": "0x4AAAAAAADnPIDROrmt1Wwj",
    "websiteURL": "https://www.ifood.com.br/",
    "data": "a38db309fda75f1e",
    "pagedata": "oADARYQ6hLArqZoXAcJmO6SSgMjvU6JRVlBH5JUWCO0-1789035619-1.3.1.1-WNWYbaa9ayfIbODYlcw3BPl4m7mQdq98uS8D9vzDTVx0MgPQ67fqIoYfAZzp4xCEcGvu15C4xK4I6nr0z1epc4ghvP8CxUfpV4TrvegIcmQmn28GUWqeKg53o5yOUem0RF7Q0fqhZmCc8yk9tLWCDsEturQiDhSPG3MHc82qPTC2ONlTfeylYMHoM2urkfeCvbTPsbDltGeSU1F23Nu2uBL94LfHOkmLDNAoEf2YsYxlio7SArdaDjDYmDV3uplatKN59hXrr6GpQli7lWD2t.9TWkgL0e8n7hjPxVwbdGzKlpNyqYsr2scsdkXY_n0Hm7QPbvv7A5jLxjuhdLOJLeOhpT_D1jea35Er7z7IMAOqCipyceThlWFyiKTFcwWNe1c0uxr.XvaQtDcIHJCzrEcxSZPBk1k4pn_qfbH5cant4yh1FORgiOSEbm4v3dRUo0q8WZhIxAofnsOkgCEEWYfWkDDQMzVEvoepJOvmW9OIfSg6F51XjBt1bVOSVwvz",
    "action": "managed",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36"
}

# 1. Создание задачи через API v2
url = 'https://api.2captcha.com/createTask'
headers = {
    'Content-Type': 'application/json'
}
payload = {
    "clientKey": API_KEY,
    "task": captured_task
}

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. Получение результата через API v2
    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:
            # Статус processing - задача еще не готова
            continue
else:
    print(f"Ошибка создания задачи: {result.get('errorDescription')}")

Python + Playwright (Автоматический перехват)

Этот скрипт автоматически внедряет код перехвата сразу после загрузки страницы, ДО появления капчи, перехватывает вывод из консоли и отправляет задачу в API v2 без ручного копирования.

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

API_KEY = 'ВАШ_API_КЛЮЧ'
TARGET_URL = 'https://www.ifood.com.br/'

def solve_ifood_turnstile():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context()
        page = context.new_page()
        
        captured_task = {}

        # Слушаем сообщения консоли для перехвата данных от нашего скрипта
        page.on("console", lambda msg: captured_task.update(json.loads(msg.text)) if msg.text.startswith('{"type":') else None)

        try:
            page.goto(TARGET_URL)
            
            # 1. ВАЖНО: Внедряем скрипт перехвата СРАЗУ после загрузки страницы, ДО появления капчи
            page.evaluate("""
                const i = setInterval(()=>{
                    if (window.turnstile) {
                        clearInterval(i)
                        window.turnstile.render = (a, b) => {
                            let p = {
                                type: "TurnstileTaskProxyless",
                                websiteKey: b.sitekey,
                                websiteURL: window.location.href,
                                data: b.cData,
                                pagedata: b.chlPageData,
                                action: b.action,
                                userAgent: navigator.userAgent
                            }
                            console.log(JSON.stringify(p))
                            window.tsCallback = b.callback
                            return 'foo'
                        }
                    }
                }, 10)
            """)
            
            # 2. Только после внедрения скрипта выполняем действие, вызывающее капчу
            # page.fill('input[name="phone"]', '11999999999')
            # page.click('button[type="submit"]')
            
            # Ждем появления данных в консоли
            for _ in range(20):
                if captured_task:
                    break
                time.sleep(1)
                
            if not captured_task:
                raise Exception("Не удалось перехватить параметры капчи. Проверьте селекторы действий.")
            
            print("Параметры перехвачены. Отправка в API v2...")
            
            # 3. Отправка в API v2 через createTask
            api_url = 'https://api.2captcha.com/createTask'
            headers = {'Content-Type': 'application/json'}
            payload = {
                "clientKey": API_KEY,
                "task": captured_task
            }
            
            task_response = requests.post(api_url, headers=headers, json=payload).json()
            if task_response.get('errorId') != 0:
                raise Exception(f"Ошибка создания задачи: {task_response.get('errorDescription')}")
                
            task_id = task_response.get('taskId')
            
            # 4. Ожидание решения через getTaskResult
            res_url = 'https://api.2captcha.com/getTaskResult'
            token = None
            for _ in range(20):
                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}")
                
                # 5. ВАЖНО: Передаем токен ТОЛЬКО через callback
                page.evaluate(f"""
                    if (typeof window.tsCallback === 'function') {{
                        window.tsCallback("{token}");
                        console.log("Token passed via tsCallback successfully");
                    }} else {{
                        console.error("tsCallback function not found.");
                    }}
                """)
                print("Токен передан через callback.")
            else:
                print("Не удалось получить токен.")
                
        except Exception as e:
            print(f"Ошибка: {e}")
        finally:
            # browser.close()

if __name__ == '__main__':
    solve_ifood_turnstile()

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

Сайт iFood принимает токен Cloudflare Turnstile исключительно через callback-функцию. Внедрение токена в скрытые поля формы может не сработать, так как сайт ожидает именно вызова функции.

Скрипт перехвата, который мы внедряем в консоль, автоматически сохраняет оригинальный callback виджета в глобальную переменную window.tsCallback. После получения токена от API вам нужно вызвать эту функцию, передав токен в качестве аргумента:

window.tsCallback("ПОЛУЧЕННЫЙ_ТОКЕН");

Именно этот вызов сообщает сайту, что капча успешно решена, и разблокирует форму для отправки.

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

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

  1. Скопируйте JSON из консоли и отправьте задачу через API v2 (createTask), указав ваш clientKey.
  2. Перейдите в Песочницу: https://2captcha.com/setting#sandbox и переключитесь в режим Работник (Worker).
  3. Если вы увидите корректно загружающийся виджет Turnstile, значит, параметры собраны верно. Если виджет выдает ошибку, убедитесь, что вы отправили запрос мгновенно после появления JSON в консоли, не обновляя страницу.

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

Ошибка / Проблема Причина Решение
Ошибка валидации или истечения срока Параметры pagedata или data устарели. Эти параметры одноразовые. Перехватывайте их заново через консольный скрипт и отправляйте в API мгновенно, без обновления страницы.
Скрипт перехвата не сработал Скрипт был внедрен после того, как капча уже загрузилась. Внедряйте скрипт сразу после открытия страницы, до любых действий, которые могут вызвать появление виджета.
ERROR_MISSING_PARAMETER Отсутствует один из обязательных параметров (action, data или pagedata). Убедитесь, что вы скопировали весь JSON-объект из консоли целиком, без обрезаний.
Сайт не принимает токен Токен не был передан через callback. Обязательно вызывайте window.tsCallback(token) после получения токена.
window.tsCallback is not a function Скрипт перехвата не сохранил callback. Проверьте, что вы внедряли скрипт ДО появления капчи. Если виджет уже загрузился, перезагрузите страницу и внедрите скрипт заново.

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