Как исправить ERROR_CAPTCHA_UNSOLVABLE и безопасно повторить попытку

error_captcha_unsolvable - How to Fix ERROR_CAPTCHA_UNSOLVABLE and Retry Safely

Короткий ответ: ERROR_CAPTCHA_UNSOLVABLE означает, что сервис принял вашу задачу, попытался её решить и не смог получить ответ. С ключом всё в порядке, с настройкой тоже, просто эта конкретная попытка не удалась. Документированное решение — отправить новую задачу и повторить попытку, а не опрашивать тот же captcha ID снова. В этом руководстве — почему повторный опрос никогда не работает, что на самом деле вызывает сбой для каждого типа капчи и как построить цикл повторов, который не крутится вечно.

Что означает эта ошибка и откуда она берётся

В отличие от ошибки ключа или параметра, эта не появляется в момент отправки. Ваш вызов /in.php прошёл успешно и вернул ID. Сбой всплывает позже, когда вы опрашиваете /res.php за результатом.

# Submit: this part worked, you got an ID back
curl "http://127.0.0.1:8080/in.php?key=YOUR_API_KEY&method=userrecaptcha&googlekey=YOUR_SITEKEY&pageurl=https://example.com/page-with-recaptcha"
OK|2122988149

# Poll: the attempt finished, and it finished badly
curl "http://127.0.0.1:8080/res.php?key=YOUR_API_KEY&action=get&id=2122988149"
ERROR_CAPTCHA_UNSOLVABLE

Поэтому сама последовательность говорит о многом: всё вплоть до отправки было правильным. Проблема в том, что вы отправили, а не в том, как вы это сделали.

Почему повтор с тем же ID никогда не помогает

Две причины, и обе структурные.

Во-первых, попытка окончена. Результат для этого ID окончателен, и повторный опрос не запускает вторую попытку. Во-вторых, результаты читаются только один раз. Как только вы прочитали результат из /res.php, этому ID больше нечего вам дать.

Если ваша обработка ошибок продолжает опрашивать тот же ID после сбоя, она будет крутиться до срабатывания таймаута, а затем сообщит о таймауте — и отправит вас отлаживать совсем не то. Повтор означает новый вызов /in.php и получение нового ID. Это противоположно случаю CAPCHA_NOT_READY, где правильный ход — продолжать опрашивать имеющийся ID.

Что вызывает это на самом деле, по типам капчи

Графические капчи: обычно проблема во входных данных

Графическое распознавание — тот тип, где действительно нерешаемый вход встречается часто, потому что пиксели предоставляете вы. Проверьте файл, прежде чем винить сервис.

  • Ограничения размера. Больше 600 кБ или больше 1000 px по любой стороне вернёт ERROR_TOO_BIG_CAPTCHA_FILESIZE , а не эту ошибку, но изображения, близкие к этим пределам, часто оказываются скриншотами целой страницы.
  • Вы обрезали не ту область. Обрезка, захватывающая подпись, рамку или половину следующего поля, — гораздо более трудное изображение, чем капча сама по себе.
  • Вы сохранили заглушку. Отдельный запрос к URL изображения часто возвращает новую, другую капчу, или уже истёкшую, или пиксель 1×1. Забирайте те байты, которые браузер уже получил.
  • Формат. Повреждённый или неожиданный формат даёт ERROR_INVALID_IMAGE, а некорректный data URI даёт ERROR_INVALID_BASE64.

Сохраните на диск ровно те байты, которые отправляете, и откройте их. Половина всех сбоев с изображениями видна за две секунды. Страница решатель картиночных капч перечисляет допустимые формы ввода: путь к файлу, удалённый URL или data:image/png;base64, URI.

reCAPTCHA: устаревший sitekey или неверный URL страницы

Sitekey, прочитанный из закэшированного исходника страницы или скопированный из тестового окружения, отправляется без ошибок, а потом приводит к сбою. То же самое с pageurl , который не соответствует странице, где на самом деле находится виджет, включая пропущенную схему или неотслеженный редирект.

Enterprise — вторая частая причина. Если на сайте работает reCAPTCHA Enterprise, а вы отправляете задачу без флага enterprise , она решается против неверной конфигурации. То же и для v3: передавайте versionи передавайте настоящее значение action этого сайта, а не значение по умолчанию verify.

В CapSkip нет параметра минимального балла, поэтому, если вы переносите код из другого сервиса, уберите любой параметр min_score или minScore . Он не является причиной этой ошибки, но и того, чего вы ждёте, тоже не сделает.

Turnstile: страницам-проверкам нужен не только sitekey

Виджету Turnstile достаточно sitekey и URL. Полной странице-проверке нужны ещё data (значение cData) и pagedata (chlPageData), оба считываются со страницы в тот же момент. Отправьте страницу-проверку так, будто это виджет, и получите задачу, которую сервис не сможет выполнить. Оба значения живут недолго, поэтому забирайте их непосредственно перед отправкой.

GeeTest: обычно ответ — истёкшая задача

The gt значение постоянно для сайта. А значение challenge одноразовое и истекает примерно за минуту. Если вы получили задачу, занялись чем-то другим и только потом отправили её, она уже может быть мертва. Получайте её непосредственно перед решением. Подробности на странице Решение для GeeTest .

Цикл повторов, который действительно повторяет

Отправляйте заново, ограничьте число попыток и делайте паузу между ними. Три попытки — разумный потолок: если цель провалила три свежие отправки, значит, входные данные неверны, и четвёртая ничего не исправит.

# pip install capskip
import time
from capskip import CapSkip, ApiException

solver = CapSkip(host="127.0.0.1", port=8080)

def solve_with_retry(sitekey, url, attempts=3):
    for n in range(attempts):
        try:
            # A fresh call means a fresh task, which is the fix.
            return solver.recaptcha(sitekey=sitekey, url=url)
        except ApiException as e:
            if "UNSOLVABLE" not in str(e) or n == attempts - 1:
                raise
            time.sleep(2 ** n)   # 1s, then 2s

token = solve_with_retry("YOUR_SITEKEY", "https://example.com/page-with-recaptcha")
print(token["code"][:40])

Обратите внимание, чего он не делает: он не повторяет ValidationException, потому что неверные параметры дают сбой одинаково каждый раз, и не повторяет NetworkException, потому что это означает, что приложение недоступно и все остальные цели вот-вот тоже упадут.

Та же схема на Node.js:

// npm install capskip
const { CapSkip } = require('capskip');

const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });

async function solveWithRetry(sitekey, url, attempts = 3) {
  for (let n = 0; n < attempts; n++) {
    try {
      return await solver.recaptcha(sitekey, url);
    } catch (e) {
      const last = n === attempts - 1;
      if (last || !String(e).includes('UNSOLVABLE')) throw e;
      await new Promise(r => setTimeout(r, 1000 * 2 ** n));
    }
  }
}

Как сделать так, чтобы это случалось реже

  • Читайте sitekey из живого DOM, а не из константы в коде. Сайты меняют их.
  • Отправляйте тот URL, на котором вы действительно находитесь, после редиректов и со схемой.
  • Короткоживущие значения получайте в последнюю очередь. Задачи GeeTest и cData у Turnstile устаревают меньше чем за минуту.
  • Обрезайте изображения плотно и отправляйте байты, которые страница уже загрузила.
  • Логируйте captcha ID при каждом сбое. Это делает закономерность видимой: одна плохая цель или общая проблема.
  • Сначала протестируйте на заведомо рабочей странице. Если страница, которая обычно работает, тоже даёт сбой, проблема в вашем окружении, а не в цели.

Соседние коды ошибок

Вот те, что путают с нерешаемой задачей. Они означают разное и требуют разных действий.

КодОзначаетЧто делать
CAPCHA_NOT_READYЕщё в работеПродолжайте опрашивать тот же ID
ERROR_INVALID_IMAGEНеверный формат или повреждённые данныеПересохраните изображение и проверьте байты
ERROR_TOO_BIG_CAPTCHA_FILESIZEБольше 600 кБ или больше 1000 pxОбрежьте до самой капчи
ERROR_INVALID_BASE64Полезная нагрузка base64 не декодируетсяУберите префикс data URI или исправьте выравнивание
ERROR_UPLOADДанные изображения не пришлиПроверьте имя поля и тело запроса
ERROR_GOOGLEKEYSitekey отклонён сразуПеречитайте его с живой страницы
ERROR_PAGEURLURL страницы отсутствует или составлен неверноОтправляйте полный URL вместе со схемой

Каждый код, который может вернуть API, с его точным значением, есть на странице Документация по API.

Часто задаваемые вопросы

Стоит ли мне что-нибудь неудачное решение?

Нет. Ни платы за решение, ни баланса, потому что работа идёт на вашей собственной машине. Повтор стоит вам времени и процессора, и больше ничего — именно поэтому цикл из трёх попыток здесь уместен.

Можно ли получить результат снова после первого прочтения?

Нет. Результаты читаются один раз. Сохраняйте токен в тот момент, когда получили его, и считайте повторное чтение того же ID ошибкой в вашем коде, а не способом восстановления.

Поможет ли прокси с нерешаемой графической капчей?

Нет. Прокси применимы только к reCAPTCHA, Turnstile и GeeTest, но не к графическому распознаванию. Задача с изображением оценивается исключительно по присланным вами пикселям, поэтому исправляйте обрезку.

Все задачи на одном сайте падают. Это тоже эта ошибка?

Обычно это одна неверная константа, применённая везде: устаревший sitekey, отсутствующий флаг enterprise или страница-проверка, отправленная как виджет. Исправьте цель один раз — и весь набор начнёт проходить.

Сводка

Относитесь к error_captcha_unsolvable как к вердикту по той задаче, которую вы отправили. Не опрашивайте старый ID. Отправьте новый, ограничьте число попыток тремя и потратьте время отладки на входные данные: sitekey, URL страницы, обрезку и всё недолговечное, что вы получили слишком рано.

Приятная сторона локального локальный сервис распознавания капчи в том, что это дешёвый сбой. Не сгорает ни кредит, ни лимит запросов, и вы можете воспроизводить одну и ту же задачу столько раз, сколько нужно, чтобы понять, какое значение было неверным.