使用 Ruby 求解 reCAPTCHA Enterprise
使用 Ruby 的 Net::HTTP 创建 reCAPTCHA Enterprise 任务,并轮询至就绪或失败。以下示例直接调用 solvethree 的 REST API,无需 Ruby SDK。
本页内容
配置站点和环境
- 1.
启用站点配置文件
在 solvethree 控制台中设置目标主机名,并确保其配置在你的工作区中处于启用状态。发送主机名和操作不会创建配置。请参阅站点配置设置。
- 2.
设置环境变量
将
SOLVETHREE_API_KEY设置为工作区 API 密钥,将SOLVETHREE_PROXY设置为 HTTP 或 HTTPS 代理 URL;向目标提交令牌时也要使用此代理。请将密钥保存在服务器端。 - 3.
修改示例输入
将
accounts.example.com替换为目标主机名,而不是完整 URL,并将login替换为该目标要求的操作。请求使用一个proxy,不要再添加proxyCandidates。不要包含type和url。省略recaptchaType时会选择默认值enterprise-v3。
将示例保存为 solve.rb,设置上述变量后使用 Ruby 运行。它会加载 net/http、json 和 securerandom;JSON 用于处理请求正文和 API 响应。
创建一次,然后按任务 ID 轮询
require 'net/http'
require 'json'
require 'securerandom'
api = 'https://api.solvethree.com/v1'
input = {site: 'accounts.example.com', action: 'login', proxy: ENV.fetch('SOLVETHREE_PROXY'), requestId: SecureRandom.uuid}
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + 180
call = lambda do |method, path, body = nil|
remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
raise 'Local deadline reached' if remaining <= 0
uri = URI(api + path)
request = method == :post ? Net::HTTP::Post.new(uri) : Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer ' + ENV.fetch('SOLVETHREE_API_KEY')
request['Accept'] = 'application/json'
if body
request['Content-Type'] = 'application/json'
request.body = JSON.generate(body)
end
# Net::HTTP's own proxy configuration is separate from input[:proxy].
http = Net::HTTP.new(uri.hostname, uri.port, nil)
http.use_ssl = uri.scheme == 'https'
http.open_timeout = [10, remaining].min
http.read_timeout = [25, remaining].min
http.write_timeout = [25, remaining].min
http.max_retries = 0
response = http.request(request)
raise "API HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body)
end
task_id = nil
begin
result = call.call(:post, '/tasks?waitMs=0', input)
task_id = result.fetch('id')
while %w[pending solving].include?(result.fetch('status'))
result = call.call(:get, '/tasks/' + URI.encode_www_form_component(task_id) + '?waitMs=15000')
sleep(1) if %w[pending solving].include?(result.fetch('status'))
end
raise "Task failed: #{result['errorCode']}" unless result['status'] == 'ready'
puts "Ready task: #{task_id}"
# Submit result['solution']['token'] with its userAgent/secChUa and original proxy.
rescue StandardError => error
warn "Recovery requestId=#{input[:requestId]} taskId=#{task_id || 'unknown'}"
raise error
end脚本发送一次创建请求,保存返回的任务 ID,并在任务状态为 pending 或 solving 时持续获取该任务。只有 ready 才提供可用的求解结果。每个响应都必须具有成功的 HTTP 状态,才能将其正文解析为成功响应数据。
HTTPS 已显式启用。自动重试已禁用;重定向会被 HTTP 状态检查拒绝,而不会被跟随。任务正文中的代理用于求解,不会配置 Ruby 到 solvethree API 的连接。
共享的单调时钟截止时间为轮询提供 180 秒的本地时间预算。连接、读取和写入超时均以每次请求开始时的剩余时间为上限。应将该预算视为轮询限制,而不是对正在进行的请求强制取消的计时器。Ruby Net::HTTP 文档介绍了各项超时设置。
使用令牌对应的浏览器身份信息提交令牌
示例打印的是已就绪任务的 ID,而不是令牌。从就绪结果中读取 solution.token,并将其放入目标请求所要求的令牌字段。不要改为发送任务 ID。
将返回的 solution.userAgent 用于 User-Agent 请求头,将 solution.secChUa 用于 Sec-CH-UA。通过提供给此任务的同一代理,向预期目标提交。不要用无关浏览器的请求头替换返回的身份信息。
任务就绪表示 solvethree 已生成求解结果。请单独检查目标的响应,以确定它是否接受了你的应用请求。
处理失败,避免创建重复任务
- 脚本抛出 API HTTP 错误。
检查非成功 HTTP 响应。这是请求级错误,而不是任务的终态结果。
试试这样做: 重试前先诊断该响应。不要反复提交未经修改的无效输入。
- 任务进入
failed状态。 检查结果中的
errorCode和error。示例抛出的消息仅包含errorCode。试试这样做: 停止轮询该任务,并处理报告的原因。求解失败会退款;失败不一定意味着余额不足。
- 在收到任务 ID 前创建请求超时。
保留写入标准错误输出的恢复用
requestId。超时并不能证明创建失败。试试这样做: 使用相同的请求 ID 提交完全相同的任务请求来恢复。不要直接重新运行脚本:重新运行会生成新的 ID,可能创建另一个任务。
- 轮询达到本地截止时间或连接中断。
保留日志中记录的任务 ID 和请求 ID。
试试这样做: 创建另一个任务前,先获取已知任务 ID 对应的任务。本地异常并不代表任务已进入终态。
要支持跨进程重启恢复,请在发送 POST 前保留请求 ID 和原始任务输入,并在任务 ID 返回后将其保存。使用相同输入复用请求 ID 会返回现有任务;保留该 ID 但更改输入会导致冲突。有关下一步诊断,请参阅 API 错误处理。
运行您的第一个任务。
使用 $5 工作区额度开始体验。