Эта статья была полезной?
Как обойти 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) сразу после открытия страницы, до любых действий, которые могут вызвать появление капчи.
Инструкция:
- Откройте страницу iFood (например, форму входа) в режиме инкогнито и нажмите F12 (Инструменты разработчика).
- Перейдите на вкладку Консоль (Console).
- Сразу же вставьте следующий скрипт и нажмите Enter. Не обновляйте страницу после этого!
javascript
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)
- В консоли мгновенно появится JSON-объект с актуальными параметрами, полностью готовый для вставки в поле task запроса API v2. Скопируйте его.
- Немедленно отправьте эти параметры в запросе на решение через API. Не обновляйте страницу, иначе параметры станут недействительными.
Обратите внимание: скрипт не только извлекает параметры, но и сохраняет оригинальный callback виджета в глобальную переменную window.tsCallback. Именно через эту функцию необходимо передать полученный токен.
Примеры кода
Python + requests (API v2)
Пример отправки задачи с параметрами, скопированными из консоли, через эндпоинты createTask и getTaskResult.
python
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
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.
- Скопируйте JSON из консоли и отправьте задачу через API v2 (createTask), указав ваш clientKey.
- Перейдите в Песочницу: https://2captcha.com/setting#sandbox и переключитесь в режим Работник (Worker).
- Если вы увидите корректно загружающийся виджет Turnstile, значит, параметры собраны верно. Если виджет выдает ошибку, убедитесь, что вы отправили запрос мгновенно после появления JSON в консоли, не обновляя страницу.
Частые ошибки и решения
| Ошибка / Проблема | Причина | Решение |
|---|---|---|
| Ошибка валидации или истечения срока | Параметры pagedata или data устарели. | Эти параметры одноразовые. Перехватывайте их заново через консольный скрипт и отправляйте в API мгновенно, без обновления страницы. |
| Скрипт перехвата не сработал | Скрипт был внедрен после того, как капча уже загрузилась. | Внедряйте скрипт сразу после открытия страницы, до любых действий, которые могут вызвать появление виджета. |
| ERROR_MISSING_PARAMETER | Отсутствует один из обязательных параметров (action, data или pagedata). | Убедитесь, что вы скопировали весь JSON-объект из консоли целиком, без обрезаний. |
| Сайт не принимает токен | Токен не был передан через callback. | Обязательно вызывайте window.tsCallback(token) после получения токена. |
| window.tsCallback is not a function | Скрипт перехвата не сохранил callback. | Проверьте, что вы внедряли скрипт ДО появления капчи. Если виджет уже загрузился, перезагрузите страницу и внедрите скрипт заново. |
Полезные ссылки
- Песочница для тестирования API: https://2captcha.com/setting#sandbox
- Документация API по Cloudflare Turnstile: https://2captcha.com/api-docs/cloudflare-turnstile
- Python SDK на GitHub: https://github.com/2captcha/2captcha-python
- Другие примеры обхода капч на сайтах: https://2captcha.com/h?category=sites