Используйте Guzzle с API задач CAPTCHA
Используйте Guzzle 7, чтобы создать задачу, а затем опрашивайте её по ID, пока она не перейдёт в ready или failed. Сохраняйте requestId на случай ошибок: тайм-аут соединения не доказывает, что создание задачи завершилось неудачей.
Это REST-интеграция, а не официальный PHP SDK.
На этой странице
Подготовьте запрос reCAPTCHA
- Установите Guzzle 7 через Composer. Команда установки приведена в начале примера.
- Задайте для SOLVETHREE_API_KEY API-ключ рабочего пространства, а для SOLVETHREE_PROXY — URL прокси. Храните ключ на сервере.
- Перед запросом решения создайте в консоли активный профиль для целевого сайта. См. настройку профиля сайта.
- Замените accounts.example.com и login на целевое имя хоста и действие. Поле site принимает имя хоста, а не полный URL.
Пример запрашивает reCAPTCHA Enterprise v3 — значение recaptchaType по умолчанию. Не добавляйте поля type и url. Пример передаёт один proxy; если вместо него вы используете proxyCandidates, полностью исключите proxy.
Создайте задачу один раз, затем опрашивайте её в пределах фиксированного времени
<?php
// composer require guzzlehttp/guzzle:^7
require __DIR__.'/vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => 'https://api.solvethree.com/v1/',
'headers' => ['Authorization' => 'Bearer '.getenv('SOLVETHREE_API_KEY'), 'Accept' => 'application/json'],
'allow_redirects' => false,
'http_errors' => false,
]);
$input = ['site' => 'accounts.example.com', 'action' => 'login',
'proxy' => getenv('SOLVETHREE_PROXY'), 'requestId' => bin2hex(random_bytes(16))];
$deadline = microtime(true) + 180;
$call = function (string $method, string $path, array $options = []) use ($client, $deadline): array {
$remaining = $deadline - microtime(true);
if ($remaining <= 0) throw new RuntimeException('Local deadline reached');
$response = $client->request($method, $path, $options + ['timeout' => min(25, $remaining), 'connect_timeout' => min(10, $remaining)]);
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
throw new RuntimeException('API HTTP '.$response->getStatusCode());
}
return json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
};
$id = null;
try {
$result = $call('POST', 'tasks?waitMs=0', ['json' => $input]);
$id = $result['id'];
while (in_array($result['status'], ['pending', 'solving'], true)) {
$result = $call('GET', 'tasks/'.rawurlencode($id).'?waitMs=15000');
if (in_array($result['status'], ['pending', 'solving'], true)) usleep(1000000);
}
if ($result['status'] !== 'ready') {
throw new RuntimeException('Task failed: '.($result['errorCode'] ?? 'unknown'));
}
echo 'Ready task: '.$id.PHP_EOL;
// Submit $result['solution']['token'] with userAgent/secChUa and the same proxy.
} catch (Throwable $error) {
fwrite(STDERR, 'Recovery requestId='.$input['requestId'].' taskId='.($id ?? 'unknown').PHP_EOL);
throw $error;
}Клиент аутентифицируется с помощью Bearer-ключа. Его base_uri заканчивается на /v1/, а пути запросов относительные, поэтому этот префикс API сохраняется. Параметр json в Guzzle отправляет входные данные задачи в формате JSON.
Вспомогательный код выполняет один POST для создания задачи. Затем он опрашивает возвращённый ID задачи, пока статус — pending или solving. На создание и опрос отводится общий лимит 180 секунд; каждый HTTP-вызов ограничен оставшимся временем, при этом максимальные тайм-ауты запроса и соединения составляют 25 и 10 секунд соответственно. Новый опрос не запускает общий отсчёт заново.
Перенаправления отключены. Значение false для http_errors позволяет вспомогательному коду явно проверять ответы за пределами 2xx перед декодированием успешного ответа; оно не подавляет ошибки соединения или тайм-ауты.
- HTTP-ответ за пределами 2xx вызывает исключение HTTP-ошибки API. Анализируйте статус и тело ответа, а не считайте его неудачным решением.
- Конечный статус задачи failed останавливает опрос. Пример выбрасывает исключение с её errorCode; также проверьте поле error задачи, содержащее диагностическое сообщение. Средства за неудачные решения возвращаются.
- Только ready содержит пригодное для использования решение. Выводимая строка «Ready task» сообщает о готовности задачи, а не о принятии решения целевым сайтом.
Восстановите запрос после тайм-аута без оплаты ещё одной задачи
Сохраните сгенерированный requestId и точные входные данные задачи перед отправкой POST. Блок catch выводит requestId и taskId, если он был возвращён при создании. Этот вывод помогает восстановлению, но не заменяет сохранение запроса перед отправкой.
- 1.
Если у вас есть ID задачи, запросите эту задачу
Используйте GET /v1/tasks/:id для проверки её статуса. Достижение локального предельного времени вспомогательного кода не означает, что удалённая задача завершилась неудачей.
- 2.
Если создание завершилось тайм-аутом без возврата ID, восстановите его с помощью requestId
Отправьте тот же запрос задачи с сохранённым requestId. При совпадении входных данных возвращается существующая задача; другие входные данные с этим ID приводят к конфликту.
- 3.
Не пытайтесь восстановить задачу простым повторным запуском скрипта
Каждый запуск генерирует новый requestId. Не добавляйте автоматический повтор POST, который генерирует другой ID, и не повторяйте вслепую запрос с неизменными некорректными данными.
Отправляйте токен через тот же прокси
Пример останавливается до обращения к целевому сайту. Отправляйте solution.token, а не ID задачи, и используйте возвращённые solution.userAgent и solution.secChUa в качестве заголовков User-Agent и Sec-CH-UA целевого запроса.
Прокси в JSON задачи указывает solvethree, какой прокси использовать для решения. Он не настраивает подключение Guzzle к API или ваш последующий запрос к целевому сайту. Отдельно настройте целевой запрос на использование того же прокси.
Используйте отдельный клиент для целевого запроса, чтобы стандартный заголовок Authorization клиента API не отправлялся на сайт. Сохраняйте вместе токен, возвращённые данные идентификации браузера, прокси и назначенный целевой сайт. Готовый токен всё равно может быть отклонён, если последующий запрос не соответствует этим данным.
Источники и справочник API
Запустите первую задачу.
Начните с $5 на балансе рабочего пространства.