Как решить капчу через cURL и сырой HTTP API

SDK вам не нужен. API CapSkip совместим с 2captcha, поэтому решить капчу через curl можно ровно двумя запросами: отправьте задачу POST-запросом на /in.php и получите ID, затем опрашивайте /res.php пока не появится ответ. Всё работает на 127.0.0.1:8080, так что удалённого эндпоинта нет и плата за каждое решение не взимается. В этом руководстве точные параметры для каждого типа капчи, форматы JSON-ответов и скрипт, который можно вставить прямо в терминал.
Что понадобится
- Запущенное приложение CapSkip с активным локальным сервисом. Настройки порта и ключа описаны в руководство по настройке.
curl. Он есть в macOS, в любом дистрибутиве Linux и в Windows 10 сборки 1803 и новее.jqесли хотите вытаскивать поля из JSON-ответов. Необязательно, но с ним примеры умещаются в одну строку.
Проверка ключа по умолчанию отключена, поэтому подойдёт любая непустая строка в поле key. Главное что-то передать: при пустом ключе возвращается ERROR_WRONG_USER_KEY.
На этом список зависимостей заканчивается, потому что весь API это два эндпоинта:
| Эндпоинт | Что делает | Возвращает |
|---|---|---|
/in.php | Отправляет задачу | Числовой ID капчи |
/res.php | Спрашивает, готов ли этот ID | Ответ или CAPCHA_NOT_READY |
Оба принимают GET и POST. POST привычка получше: URL страницы с query-параметрами незаметно обрежет GET-запрос на первом незакодированном амперсанде.
Шаг 1: отправьте задачу
reCAPTCHA v2 самый короткий пример. Задачу определяют два значения: sitekey со страницы и URL страницы, на которой она стоит.
# No install step. curl is already on your machine. curl -X POST http://127.0.0.1:8080/in.php \ -d "key=YOUR_API_KEY" \ -d "method=userrecaptcha" \ -d "googlekey=YOUR_SITEKEY" \ -d "pageurl=https://example.com/page-with-recaptcha" OK|2122988149 # the number after the pipe is your captcha ID
Обратите внимание на имя параметра. reCAPTCHA использует googlekey. Turnstile использует sitekey. Отправка sitekey в userrecaptcha самая частая причина ответа ERROR_GOOGLEKEY .
Шаг 2: опрашивайте результат
Сначала подождите, потом спрашивайте. Немедленный опрос просто тратит запрос и возвращает CAPCHA_NOT_READY.
sleep 15 curl -X POST http://127.0.0.1:8080/res.php \ -d "key=YOUR_API_KEY" \ -d "action=get" \ -d "id=2122988149" OK|03AGdBq26... # the token, ready to inject into the form
Две особенности /res.php , о которые спотыкаются. Он возвращает CAPCHA_NOT_READY пока задача ещё выполняется: это не ошибка, а сигнал продолжать опрос. И каждый результат читается только один раз, поэтому сохраняйте ответ сразу же. Повторное чтение того же ID вернёт пустоту.
Сколько ждать до первого опроса, зависит от типа:
| Тип | Первый опрос через |
|---|---|
| Картинка | 1 секунда |
| reCAPTCHA v2 | от 15 до 20 секунд |
| reCAPTCHA v3 | От 10 до 15 секунд |
| GeeTest v3 | около 5 секунд |
Добавьте json=1, чтобы разбирать ответ
Простой текстовый формат удобен человеку в терминале и неудобен скрипту. Добавьте json=1 к любому из эндпоинтов и вместо него получите стабильный объект.
// in.php with json=1
{"status": 1, "request": "2122988149"}
// res.php with json=1, once it is solved
{"status": 1, "request": "03AGdBq26..."}
// res.php with json=1, still working
{"status": 0, "request": "CAPCHA_NOT_READY"}status равен 1 при успехе и 0 во всех остальных случаях, а нужное значение всегда лежит в request. Так что всё сводится к двум выражениям jq .
Все методы в одной таблице
Девять типов капчи, пять значений method. Варианты это дополнительные параметры, а не новые эндпоинты.
| Тип | method | Обязательные параметры |
|---|---|---|
| Картинка, загруженный файл | post | file |
| Картинка, base64 | base64 | body |
| reCAPTCHA v2 | userrecaptcha | googlekey, pageurl |
| reCAPTCHA v2 Invisible | userrecaptcha | плюс invisible=1 |
| reCAPTCHA Enterprise | userrecaptcha | плюс enterprise=1 |
| reCAPTCHA v3 | userrecaptcha | плюс version=v3, action |
| Виджет Turnstile | turnstile | sitekey, pageurl |
| Страница-проверка Turnstile | turnstile | плюс data, pagedata |
| GeeTest v3 | geetest | gt, challenge, pageurl |
Картинка уходит либо как файл формы, либо как base64 в теле запроса:
# File upload. Note the @ in front of the path. Use -F for every # field here: curl refuses to mix -F and -d in one request. curl -X POST http://127.0.0.1:8080/in.php \ -F "key=YOUR_API_KEY" -F "method=post" -F "[email protected]" # Or send the bytes inline, already base64 encoded. curl -X POST http://127.0.0.1:8080/in.php \ -d "key=YOUR_API_KEY" \ -d "method=base64" \ --data-urlencode "body=$(base64 < captcha.png | tr -d '\n')"
Использовать --data-urlencode для всего, что содержит +, / или =. В base64-данных встречаются все три символа, а обычный -d их испортит.
Turnstile возвращает ещё и user agent
Cloudflare привязывает токен к отпечатку браузера, который его получил, поэтому токен, отправленный с другим user agent, отклоняется, даже если сам он полностью валиден. Сырой API отдаёт использованное значение в двух местах:
- С
json=1в виде поляuserAgentв ответе. - В текстовом режиме как HTTP-заголовок ответа
X-Turnstile-User-Agentзаголовок ответа.
# -i prints the headers, which is where the user agent lives # when you are not using json=1. curl -i -X POST http://127.0.0.1:8080/res.php \ -d "key=YOUR_API_KEY" -d "action=get" -d "id=2122988149" X-Turnstile-User-Agent: Mozilla/5.0 ... OK|0.abc123...
Полностраничным проверкам нужны ещё data (значение cData) и pagedata (chlPageData), считанные со страницы прямо перед отправкой. Режиму виджета не нужно ни то, ни другое. На странице Сервис распознавания Turnstile эта разница разобрана подробнее.
Ответ GeeTest это три поля, а не одно
GeeTest не возвращает один токен. Запросите JSON и получите три значения, которые отправил бы обратно собственный фронтенд сайта.
{
"status": 1,
"request": {
"geetest_challenge": "...",
"geetest_validate": "...",
"geetest_seccode": "..."
}
}The gt значение постоянно для сайта. А значение challenge значение одноразовое и живёт около минуты, поэтому получайте его непосредственно перед отправкой, а не в начале длинного скрипта.
Решение через прокси
Два параметра, добавленные к тому же /in.php запросу:
curl -X POST http://127.0.0.1:8080/in.php \ -d "key=YOUR_API_KEY" \ -d "method=userrecaptcha" \ -d "googlekey=YOUR_SITEKEY" \ -d "pageurl=https://example.com/page-with-recaptcha" \ -d "proxy=login:[email protected]:3128" \ -d "proxytype=HTTPS"
proxytype принимает HTTP, HTTPS, SOCKS5 или SOCKS5H. Прокси работают только для reCAPTCHA, Turnstile и GeeTest. Распознавание картинки читает пиксели, которые у вас уже есть, и целевой сайт вообще не трогает, поэтому прокси там ничего не даёт.
Готовый скрипт
Отправить, опросить с ограничением, вывести токен. Около двадцати строк, без зависимостей кроме curl.
#!/usr/bin/env bash
set -euo pipefail
API="http://127.0.0.1:8080"
KEY="YOUR_API_KEY"
# Submit and keep only the part after the pipe.
ID=$(curl -s -X POST "$API/in.php" \
-d "key=$KEY" -d "method=userrecaptcha" \
-d "googlekey=YOUR_SITEKEY" \
-d "pageurl=https://example.com/page-with-recaptcha" | cut -d'|' -f2)
sleep 15
# Poll every 5s, give up after 20 tries so this cannot hang forever.
for _ in $(seq 20); do
R=$(curl -s -X POST "$API/res.php" -d "key=$KEY" -d "action=get" -d "id=$ID")
[ "$R" = "CAPCHA_NOT_READY" ] || { echo "${R#OK|}"; exit 0; }
sleep 5
done
echo "timed out waiting for $ID" >&2; exit 1The || { ...; exit 0; } срабатывает на всём, что не равно CAPCHA_NOT_READY, включая коды ошибок. Так задумано: ошибка означает остановиться, а не продолжать опрос.
Ошибки, которые встречаются на этом уровне
| Код | Означает | Исправить |
|---|---|---|
ERROR_WRONG_USER_KEY | Ключ отсутствует или пуст | Передайте любой непустой key |
ERROR_WRONG_METHOD | Неверный method или action | Сверьте написание с таблицей выше |
ERROR_BAD_PARAMETERS | Не хватает обязательного параметра | Сравните со столбцом обязательных параметров выше |
ERROR_GOOGLEKEY | The googlekey значение отклонено | Скорее всего, вы отправили sitekey вместо него |
ERROR_PAGEURL | The pageurl значение отклонено | Укажите схему и используйте POST вместо GET |
CAPCHA_NOT_READY | Ещё выполняется | Не ошибка. Продолжайте опрашивать тот же ID |
| Пустой ответ | Уже прочитан либо такого ID нет | Результат читается один раз. Сохраняйте первый же |
Точные формулировки всех кодов, которые может вернуть API, есть в Документация по API.
Когда пора уходить с curl
Сырой HTTP отлично подходит для быстрой проверки, shell-конвейера или языка без официального клиента. Для прикладного кода CapSkip SDKs стоят добавленной зависимости прежде всего по одной причине: они не опрашивают с постоянным интервалом. Они начинают с 250 мс и увеличивают паузу до pollingInterval, поэтому решение обычно возвращается быстрее, чем в самописном цикле выше, который каждый раз честно выжидает свои 15 секунд.
Они же превращают строки ошибок в типизированные исключения и сами разбираются с user agent для Turnstile и трёхполевым ответом GeeTest. Официальные клиенты есть для Python, Node.js, PHP и .NET.
Часто задаваемые вопросы
Можно ли использовать GET вместо POST?
Да, оба эндпоинта его принимают. Загвоздка в том, что pageurl со своей собственной query-строкой обрежется на первом незакодированном амперсанде, и вы получите ERROR_PAGEURL или решение не той страницы. Если GET всё-таки нужен, прогоните URL через --data-urlencode заранее.
Какой API-ключ передавать?
Любую непустую строку. Проверка ключа по умолчанию отключена, потому что сервис слушает только localhost, поэтому key=capskip работает нормально. Но он должен присутствовать: без него вы получите ERROR_WRONG_USER_KEY , а не решение.
Работает ли это в Windows PowerShell?
Использовать curl.exe явно. В PowerShell curl это псевдоним для Invoke-WebRequest, который не понимает -d и выдаст ошибку параметра, похожую на проблему API. Запись curl.exe обходит псевдоним.
Можно ли решать несколько капч одновременно?
Да. Отправляйте сколько угодно задач и опрашивайте каждый ID независимо. Ничто их не сериализует, и поминутной квоты нет, потому что работа идёт на вашем железе, а не в общей очереди.
Сводка
Отправьте задачу POST-запросом на /in.php, сохраните ID, выждите подходящую типу паузу, затем опрашивайте /res.php пока не получите что-то кроме CAPCHA_NOT_READY. Добавьте json=1 если ответ читает скрипт. Помните про две ловушки в именах: googlekey для reCAPTCHA против sitekey для Turnstile, и про то, что результат читается лишь однажды.
Поскольку это распознавание капчи , работающий на вашей же машине, у цикла выше нет ни квоты, ни баланса для пополнения. Направьте его на localhost, и единственным пределом останется скорость, с которой ваш процессор разбирает очередь.
