将 Guzzle 与 CAPTCHA 任务 API 配合使用
使用 Guzzle 7 创建任务,然后按 ID 轮询,直到任务状态为 ready 或 failed。出现任何问题时都要保留 requestId:连接超时并不能证明任务创建失败。
这是 REST 集成,不是官方 PHP SDK。
本页内容
准备 reCAPTCHA 请求
- 使用 Composer 安装 Guzzle 7。安装命令位于示例顶部。
- 将 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 前缀。Guzzle 的 json 选项将任务输入作为 JSON 发送。
辅助程序发送一次用于创建任务的 POST。随后在状态为 pending 或 solving 时,轮询返回的任务 ID。创建和轮询共用 180 秒的时间预算;每次 HTTP 调用均受剩余时间限制,请求和连接超时上限分别为 25 秒和 10 秒。新一轮轮询不会重置总体时间预算。
重定向已禁用。将 http_errors 设为 false,可让辅助程序在解码成功响应载荷前显式检查非 2xx 响应;这不会屏蔽连接错误或超时。
- 非 2xx HTTP 响应会抛出 API HTTP 错误。请根据响应状态和响应体排查,而不要将其视为求解失败。
- 任务进入 failed 终态后会停止轮询。示例会抛出其 errorCode;同时还应检查任务的 error 字段,以获取诊断消息。求解失败会退款。
- 只有 ready 状态包含可用的求解结果。打印的“Ready task”行表示任务已就绪,并不表示目标网站已接受结果。
恢复超时请求,无需为另一个任务付费
发送 POST 前,先保存生成的 requestId 和完整、准确的任务输入。catch 块会打印 requestId,如果创建时返回了 taskId,也会一并打印。这些输出有助于恢复,但不能替代在发送前保存请求。
- 1.
如果已有任务 ID,则获取该任务
使用 GET /v1/tasks/:id 检查其状态。达到辅助程序的本地截止时间并不能证明远程任务失败。
- 2.
如果创建超时且未返回 ID,使用 requestId 恢复
使用已保存的 requestId 提交相同的任务请求。输入匹配时会返回现有任务;使用该 ID 提交不同输入会产生冲突。
- 3.
不要通过重新运行脚本来快速恢复
每次运行都会生成新的 requestId。不要添加会生成另一个 ID 的自动 POST 重试,也不要盲目地原样重试无效输入。
通过同一代理提交令牌
示例会在联系目标前停止。提交 solution.token,而不是任务 ID,并将返回的 solution.userAgent 和 solution.secChUa 用作目标请求的 User-Agent 和 Sec-CH-UA 请求头。
任务 JSON 中的 proxy 告诉 solvethree 求解时使用哪个代理。它不会配置 Guzzle 到 API 的连接,也不会配置之后发送到目标的请求。请单独配置目标请求,使其使用同一代理。
为目标请求使用独立客户端,以免将 API 客户端的默认 Authorization 请求头发送到网站。将令牌、返回的浏览器身份信息、代理和预期目标保持关联。如果后续请求不匹配,就绪的令牌仍可能被拒绝。
运行您的第一个任务。
使用 $5 工作区额度开始体验。