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は、その対象が要求するアクションに置き換えます。リクエストでは1つのproxyを使用します。proxyCandidatesも追加しないでください。typeとurlは含めないでください。recaptchaTypeを省略すると、デフォルトのenterprise-v3が選択されます。
例をsolve.rbとして保存し、これらの変数を設定してからRubyで実行してください。net/http、json、securerandomが読み込まれ、JSONがリクエストボディとAPIレスポンスを処理します。
1回だけ作成し、タスク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このスクリプトは作成リクエストを1回送信し、返されたタスク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のワークスペースクレジットで始められます。