Как исправить CAPCHA_NOT_READY при опросе результата

Короткий ответ: CAPCHA_NOT_READY — это не ошибка. Так API сообщает, что капча ещё решается, а вы запросили результат слишком рано. В вашем запросе исправлять нечего. Вам просто нужен правильный ритм опроса и цикл, который знает, когда остановиться. В этом руководстве рассматривается и то, и другое, а также поведение «чтение один раз», из-за которого рабочий скрипт начинает сбивать с толку.
Что на самом деле означает CAPCHA_NOT_READY
Когда вы отправляете капчу в /in.php вы получаете обратно ID, а не ответ. Распознавание происходит в фоне. Затем вы опрашиваете /res.php с этим ID, пока ответ не будет готов.
Пока это не так, каждый опрос возвращает одну и ту же строку:
# Poll for the result. Note action=get and the id from /in.php. curl "http://127.0.0.1:8080/res.php?key=YOUR_API_KEY&action=get&id=CAPTCHA_ID" # Still working: CAPCHA_NOT_READY # Done: OK|03AGdBq26Sxo...
И да, это пишется CAPCHA, а не CAPTCHA. Эта опечатка присутствует в API 2captcha с самого начала. CapSkip полностью совместим с этим API, поэтому ошибка в написании сохранена намеренно. Если её исправить, сломается каждая существующая клиентская библиотека, которая проверяет точную строку. Указывайте её в коде в точности так же.
Опрашивайте по правильному графику
Большинство сталкивается с этим постоянно, потому что запрашивают результат сразу после отправки. Разные типы капч требуют очень разного времени, поэтому первая проверка не должна происходить в один и тот же момент для всех них.
| Тип | Ожидание перед первой проверкой | Затем повторяйте каждые |
|---|---|---|
| Изображение / текст | 1 секунда | 5 секунд |
| reCAPTCHA v2 | от 15 до 20 секунд | 5 секунд |
| reCAPTCHA v3 | От 10 до 15 секунд | 5 секунд |
| GeeTest | около 5 секунд | 5 секунд |
| Cloudflare Turnstile | около 5 секунд | 5 секунд |
Опрос чаще, чем раз в 5 секунд, не ускоряет решение. Он лишь впустую расходует запросы.
Цикл опроса, который завершается
Версия для shell, наглядно показывающая структуру:
# Submit, capture the id, give it a head start, then poll. ID=$(curl -s "http://127.0.0.1:8080/in.php?key=YOUR_API_KEY&method=userrecaptcha&googlekey=YOUR_SITEKEY&pageurl=https://example.com" | cut -d'|' -f2) sleep 15 while :; do RES=$(curl -s "http://127.0.0.1:8080/res.php?key=YOUR_API_KEY&action=get&id=$ID") [ "$RES" = "CAPCHA_NOT_READY" ] || break sleep 5 done echo "$RES"
У этого цикла есть недостаток, о котором стоит сказать: он выполняется бесконечно, если что-то пошло не так выше по цепочке. В реальном коде ограничьте его.
# pip install requests
import time
import requests
BASE = "http://127.0.0.1:8080"
def solve_recaptcha(sitekey, page_url, api_key="YOUR_API_KEY", timeout=180):
task = requests.get(BASE + "/in.php", params={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": 1,
}).json()
task_id = task["request"]
time.sleep(15) # reCAPTCHA needs a head start
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
res = requests.get(BASE + "/res.php", params={
"key": api_key,
"action": "get",
"id": task_id,
}).text.strip()
if res.startswith("OK|"):
return res.split("|", 1)[1]
# Anything that is not the pending string is terminal.
if res != "CAPCHA_NOT_READY":
raise RuntimeError(res or "empty response: already read, or bad id")
time.sleep(5)
raise TimeoutError("gave up after %ss" % timeout)Три вещи делают это безопасным: дедлайн, чтобы избежать зависания, обработка любой строки, отличной от pending, как финальной, чтобы реальные ошибки проявлялись сразу, и однократное чтение ответа.
Или полностью пропустите цикл
Если вы используете один из официальных SDK, ничего из вышеперечисленного вас не касается. Опрос происходит внутри вызова, и вы получаете токен напрямую, поэтому CAPCHA_NOT_READY никогда не доходит до вашего кода.
# pip install capskip
from capskip import CapSkip
solver = CapSkip(host="127.0.0.1", port=8080)
# Submit and poll happen inside this one call.
result = solver.recaptcha(
sitekey="YOUR_SITEKEY",
url="https://example.com/page-with-recaptcha",
)
print(result["code"]) # token, ready to inject// npm install capskip
const { CapSkip } = require('capskip');
const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
const result = await solver.recaptcha('YOUR_SITEKEY', 'https://example.com/page-with-recaptcha');
console.log(result.code);// composer require capskip/capskip
use CapSkip\CapSkip;
$solver = new CapSkip(['host' => '127.0.0.1', 'port' => 8080]);
$result = $solver->recaptcha('YOUR_SITEKEY', 'https://example.com/page-with-recaptcha');
echo $result['code'];// dotnet add package CapSkip
using CapSkip;
var solver = new CapSkipClient(host: "127.0.0.1", port: 8080);
var result = await solver.RecaptchaAsync("YOUR_SITEKEY", "https://example.com/page-with-recaptcha");
Console.WriteLine(result.Code);Полные сигнатуры методов для всех четырёх языков находятся на SDK для распознавания капчи странице. Приведённый выше «сырой» цикл — это по-прежнему то, что вам нужно для Go, Java, Ruby или чего-либо без официального пакета.
Ловушка одноразового чтения
Именно эта отнимает полдня. Каждый результат можно прочитать только один раз. Запросите результат снова после успешного чтения — и вы получите пустой ответ, а не токен, который у вас уже был.
Поэтому пустое тело не означает “ещё в процессе”. Оно означает одно из двух:
- Вы уже получили этот результат и отбросили его
- ID не существует — обычно это искажённый или обрезанный ID, полученный при парсинге
OK|ID
Сохраняйте токен сразу, как только получите его. Не опрашивайте повторно, чтобы “подтвердить” его.
Когда это действительно проблема
Если CAPCHA_NOT_READY никогда не разрешается, строка pending — это симптом, а не причина. Проверьте следующее по порядку:
| Ответ | Что это значит | Исправить |
|---|---|---|
ERROR_CAPTCHA_UNSOLVABLE | Попытка решения была предпринята и не удалась | Убедитесь, что sitekey и pageurl актуальны, затем отправьте повторно |
ERROR_WRONG_ID_FORMAT | ID не является допустимым целым числом | Вы разбираете OK|ID неверно. Разделите по вертикальной черте, возьмите поле 2 |
ERROR_GOOGLEKEY | sitekey был отклонён при отправке | Считайте его заново с «живой» страницы, а не из кешированного источника |
| Пустое тело | Уже прочитано или неизвестный ID | Сохраняйте результат при первом чтении |
| Pending дольше 3 минут | Решатель не запущен или недоступен | Убедитесь, что сервис запущен на настроенном порту. См. руководство по настройке |
Полный список строк ошибок находится в Документация по API.
Часто задаваемые вопросы
Является ли CAPCHA_NOT_READY ошибкой, которую нужно логировать?
Не как ошибку. Это нормальное промежуточное состояние, и вы будете видеть его несколько раз за одно решение. Логируйте его на уровне debug, если вообще логируете, иначе реальные сбои утонут в шуме.
Вернётся ли ответ быстрее при более частом опросе?
Нет. Время решения не зависит от того, как часто вы спрашиваете. 5 секунд — это задокументированный интервал, и всё, что чаще, — это впустую потраченные запросы.
Почему пишут CAPCHA, а не CAPTCHA?
Это старая опечатка в оригинальном API 2captcha, ставшая частью контракта. CapSkip полностью совместим с этим API по принципу drop-in, поэтому строка сохраняется в точности. Исправление написания сломало бы каждый клиент, который её проверяет.
Могу ли я получить состояние ожидания в формате JSON?
Да. Добавьте json=1 к запросу, и ответы возвращаются в виде объекта с status и request поля вместо обычного текста. Сама строка pending остаётся неизменной.
Сводка
Дайте решению фору перед первой проверкой, повторяйте попытку каждые 5 секунд, расценивайте всё, кроме CAPCHA_NOT_READY как терминальное, ограничьте цикл дедлайном и считайте результат ровно один раз. В этом весь шаблон.
Если вы вообще предпочли бы не писать цикл, CapSkip — это распознавание капчи который работает локально и поставляется с SDK для Python, Node.js, PHP и .NET, берущими опрос на себя.
