Токен капчи истёк: причины и как это исправить
Токен капчи — это короткоживущее доказательство того, что проверка пройдена. Токены PopularCaptcha от Scarnox истекают примерно через две минуты после выдачи. Если отправить токен после этого окна, сайт отклонит форму, часто с сообщением, что капча истекла или недействительна. Исправление почти всегда связано с таймингом: решайте капчу как можно ближе к отправке, используйте каждый токен один раз и повторяйте только тогда, когда точно знаете, что первая попытка не была принята.
Почему токены истекают
Токен — не постоянное учётное данные. Сайт хочет знать, что человек (или решатель, действующий за человека) недавно прошёл проверку, поэтому токен живёт недолго. Отсчёт начинается с выдачи токена, а не с первого вызова API. Всё, что происходит между решением и отправкой, съедает эти две минуты.
Частые причины
- Решение слишком рано. Заранее набранный пакет токенов, который хранится до использования, — самая частая причина. К моменту использования токен уже устарел.
- Медленный код между решением и отправкой. Долгая запись в базу, очередь или
time.sleep, поставленный перед отправкой формы, может вытолкнуть токен за окно. - Повторное использование токена. Токен, который уже был принят или который использовала неудачная попытка, больше не сработает. Считайте каждый токен одноразовым.
- Перезагрузка страницы. Если страницу обновили после решения, форма может выдать новую проверку и аннулировать токен, который у вас есть.
Исправление: решайте прямо перед отправкой
Самый надёжный шаблон — сделать решение и отправку одним шагом. Запросите токен, положите его в форму, отправьте форму и не делайте ничего медленного между этими действиями:
import requests
API_KEY = "scarnox_YOURAPIKEY"
CREATE_URL = "https://api.scarnox.com/api/tasks/create"
def fresh_token(sitekey: str, page_url: str) -> str:
r = requests.post(
CREATE_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
},
timeout=185, # вызов блокируется, пока токен не готов
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
def submit_form(page_url: str, sitekey: str, form: dict) -> requests.Response:
token = fresh_token(sitekey, page_url) # решаем прямо перед отправкой
return requests.post(
page_url,
data={**form, "h-captcha-response": token, "g-recaptcha-response": token},
timeout=30,
)
Обратите внимание, что submit_form не держит токен в кеше или очереди. Он запрашивает токен, отправляет его и идёт дальше. Неудачные решения не списываются, поэтому неудачный запрос ничего не стоит на стороне решения.
Безопасные повторы
Некоторые сайты отклоняют истёкший токен понятным ответом. Другие возвращают обычную страницу с сообщением об ошибке внутри, поэтому один только код статуса ничего не скажет. Посмотрите, что сайт реально возвращает для истёкшего токена, и постройте проверку вокруг этого ответа. Цикл повторов может выглядеть так:
def submit_with_retry(page_url: str, sitekey: str, form: dict, attempts: int = 2):
for _ in range(attempts):
resp = submit_form(page_url, sitekey, form)
if resp.status_code < 400 and "captcha" not in resp.text.lower():
return resp # принято, судя по ответу этого сайта
raise RuntimeError("captcha token rejected after retries")
Будьте осторожны с повторами на формах, которые что-то создают. Если первая попытка была фактически принята, а ваш код неправильно прочитал ответ, повтор может создать дубликат аккаунта, заказа или сообщения. Повторяйте только тогда, когда уверены, что первая отправка не была принята, и делайте проверку конкретной для сайта, с которым работаете.
Держите тайминг честным
- Не решайте циклом токены, которые собираетесь использовать позже. Решайте на каждую отправку.
- Держите работу между решением и отправкой на минимуме.
- Используйте таймаут около 185 секунд для запроса решения, потому что вызов блокируется до готовности токена. Отдельный таймер на вашу отправку формы должен быть намного короче времени жизни токена.
- Если нужен более быстрый конвейер, см. скорость решения капчи, где описаны параллельные решения без хранения токенов.
Частые ошибки
- Кеширование токенов в словаре или Redis на потом. Кеш выглядит безобидно, пока токен не используется после окна и каждая отправка не падает.
- Решение один раз на сессию. Долгоживущая сессия всё равно нуждается в новом токене на каждую отправку формы, потому что каждая отправка может проходить собственную проверку.
- Пауза между решением и отправкой. Лимитер частоты или намеренная пауза после решения расходуют время жизни токена. Любые паузы ставьте до решения.
- Одинаковая обработка всех сбоев. Таймаут на вашей стороне, отклонённый токен и ошибка сайта требуют разной обработки. Логируйте их по отдельности.
Логируйте достаточно, чтобы понять причину
Когда отправка не удалась, записывайте время выдачи токена, время отправки формы, HTTP-статус и первые несколько сотен символов ответа. По этим четырём значениям сразу видно, истёк ли токен или сайт отклонил его по другой причине. Не логируйте полный токен в общих логах: действительный токен — это учётные данные для одной конкретной проверки.
Что проверить, если всё ещё не работает
- Выведите время между получением токена и отправкой формы.
- Убедитесь, что
site_urlсовпадает со страницей, на которой показана капча. - Убедитесь, что sitekey считан с текущей страницы, а не из старой копии.
- Проверьте имена полей формы. Токены PopularCaptcha идут в
h-captcha-response, и часто также вg-recaptcha-response.
Полный список ответов об ошибках и способов их обработки — в обработке ошибок решателя капчи.