PythonとNode.jsで複数のCAPTCHAを解く
開始するリクエスト数だけでなく、実行中の解答生成数を制限してください。以下の例では、独立した 8 件の reCAPTCHA Enterprise タスクを、同時に実行中の解答生成が最大 4 件になるように実行し、完了した結果から順に処理します。
4 は同時実行数の設定例であり、solvethree のキャパシティ上限ではありません。アプリケーションが返された解答をどの程度の速さで使用できるかに合わせて、上限を選んでください。
このページの内容
SDK とタスク入力を準備する
Python 3.10+ または Node.js 22+ を使用してください。ドキュメントにあるダウンロード URL から公式 SDK をインストールしてください。パッケージを直接ダウンロードする方式を使用します。ワークスペースの API キーはサーバー側で管理してください。
- サーバーの環境変数に
SOLVETHREE_API_KEYとSOLVETHREE_PROXYを設定してください。 accounts.example.comとloginを、対象のホスト名とアクションに置き換えてください。そのサイトには、ワークスペースで利用可能な有効なプロファイルがすでに存在している必要があります。ホスト名を送信してもプロファイルは作成されません。jobsの各エントリを、個別の論理タスクとして扱ってください。例ではバッチを読みやすくするために同じサイト、アクション、プロキシを繰り返し使用していますが、各タスクには異なるrequestIdを割り当てています。- 復旧中は、各タスクの入力を変更しないでください。独立した新しい解答生成には新しい ID が必要です。中断された解答生成の復旧には、元の ID と同一の入力が必要です。
同時実行数を制限したバッチを実行する
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
from uuid import uuid4
from solvethree import Solvethree
# Each worker gets its own synchronous client.
def solve_one(job):
client = Solvethree(os.environ["SOLVETHREE_API_KEY"])
return client.solve({**job, "requestId": str(uuid4())}, timeout=180)
jobs = [
{"site": "accounts.example.com", "action": "login", "proxy": os.environ["SOLVETHREE_PROXY"]}
for _ in range(8)
]
with ThreadPoolExecutor(max_workers=4) as pool:
futures = [pool.submit(solve_one, job) for job in jobs]
for future in as_completed(futures):
try:
result = future.result()
print("Ready task:", result["id"])
# Submit this solution promptly; don't wait for the whole batch.
except Exception as error:
print("One task failed:", type(error).__name__)import { randomUUID } from 'node:crypto';
import { Solvethree } from '@solvethree/sdk';
const client = new Solvethree({ apiKey: process.env.SOLVETHREE_API_KEY });
const jobs = Array.from({ length: 8 }, () => ({
site: 'accounts.example.com', action: 'login',
proxy: process.env.SOLVETHREE_PROXY, requestId: randomUUID(),
}));
let next = 0;
async function worker() {
while (next < jobs.length) {
const job = jobs[next++];
try {
const result = await client.solve(job, { timeoutMs: 180_000 });
console.log('Ready task:', result.id);
// Submit this solution promptly, before taking another job.
} catch (error) {
console.error('One task failed:', error.constructor.name);
}
}
}
await Promise.all(Array.from({ length: Math.min(4, jobs.length) }, worker));`Solvethree` は同期型のため、ここでは Python にスレッドが必要です。 各 solve 呼び出しはタスクを作成し、解答が使用可能になるまで待機するか、例外を送出します。ネイティブの非同期クライアントはないため、非同期関数内で直接呼び出しても、その関数のイベントループスレッドをブロックします。この例では、それぞれ専用のクライアントを持つ 4 つのスレッドプールワーカーを使用し、バッチ全体を待たずに完了した Future を処理します。
Node.js では、4 つのワーカー Promise によって同時実行数を制限します。 各ワーカーは、1 件の解答生成を待ってから次のジョブを取得します。Promise.all はそれらのワーカーを待機するもので、すべてのジョブを一度に開始するわけではありません。一方、件数を制限していないジョブ一覧をそのまま solve 呼び出しにマッピングすると、一覧全体が即座に開始され、実用的な同時実行数の上限を設けられません。
どちらの例もタスクごとにエラーを捕捉するため、1 件の解答生成が失敗しても残りのジョブは停止しません。180 秒のタイムアウトは各 solve 呼び出しに適用され、バッチ全体に適用されるものではありません。
使用可能になった結果をすぐに使う
実際のバッチを実行する前に、成功時の処理にあるコメントを、対象サイトへの送信処理に置き換えてください。出力される ID はタスクを識別するものであり、reCAPTCHA トークンではありません。そのタスクに指定したものと同じプロキシを使い、返された userAgent と secChUa とともに solution.token を送信してください。
すべてのトークンを集め、最も遅い解答生成が終わるまで待ってから使用するのは避けてください。各結果が使用可能になった時点で、その場で処理してください。SDK は CAPTCHA を解きますが、対象サイトへの解答送信は行いません。また、タスクの解答が使用可能になっても、その後のリクエストを対象サイトが受け入れたことの証明にはなりません。
バッチ全体ではなく、中断された 1 件のタスクを復旧する
例では、ワーカーのパターンを短く示すためにエラーのクラス名を出力しています。実際の組み込みでは、影響を受けたジョブと、SDK エラーが公開する復旧用 ID を保持してください。Python では request_id と task_id、JavaScript では requestId と taskId を使用します。
- 解答生成がタイムアウトする、または接続が失われる。
エラーにタスク ID またはリクエスト ID が含まれているか確認してください。リモート側のタスクはまだ存在する可能性があります。
試してみましょう: タスク ID がわかる場合は、GET ポーリングを再開してください。そうでなければ、同一の入力を同じリクエスト ID で再送し、作成処理を復旧してください。
- SDK が TaskFailedError を送出する。
終端状態に達したタスクの errorCode と error を確認してください。
試してみましょう: そのタスクのポーリングを停止し、別の解答生成を開始する前に、報告された原因に対処してください。無効な入力を変更せず、むやみに再試行しないでください。
どちらの例も、再実行すると新しいリクエスト ID が生成され、新しい論理タスクが開始されます。復旧ではありません。どちらの SDK もタスクの作成を自動では再試行しないため、成功済みの処理を再送信せず、中断されたジョブだけを復旧できるよう、十分な情報を保持してください。
参照元とAPIリファレンス
最初のタスクを実行しましょう。
$5のワークスペースクレジットで始められます。