Токен капчі прострочено: причини і як це виправити
Токен капчі — це короткоживуче підтвердження, що виклик пройдено. Токени 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.
Повний перелік відповідей про помилки і способи їх обробки дивіться в обробці помилок солвера капчі.