Python 標準ライブラリで CAPTCHA API を連携
外部依存のない Python クライアント。タイムアウト、回数制限付き再試行、固定キー、再開可能なポーリング。
許可された QA 自動化とブラウザー連携向けです。テスト権限のあるサイトと業務フローでのみ使用してください。
前提条件
サーバーやテスト実行環境で Python 3.10+ を使用します。外部 HTTP ライブラリは不要です。tasks 権限のある有効な Key、十分な残高、テスト権限のあるサイトが必要です。登録・メール認証後、利用可能ならセルフサービスを有効化するか発行済み Key を紐付けます。料金を確認してください。
ダウンロードと実行
下のリンクから python-client.py を取得し、task.json に管理下のテストサイトの値を設定します。
{"type":"turnstile","task":{"websiteURL":"https://example.com/login","websiteKey":"REPLACE_WITH_SITE_KEY"}}
認証情報はリポジトリに保存せず環境変数で渡します。最初の送信前に論理タスク用の固定キーを保存してください。
curl -fsSLO https://www.tiam.codes/downloads/python-client.py
export SOLVEHUB_API_KEY='sh_REPLACE_ME'
export SOLVEHUB_IDEMPOTENCY_KEY='persisted-authorized-test-0001'
export SOLVEHUB_TASK_FILE='task.json'
python3 python-client.py
同じ流れを 1 ファイルにまとめた例です(標準ライブラリのみ)。タスクを作成し、終状態までポーリングし、SOLVEHUB_TASK_ID があればそのタスクから再開します。
import json, os, sys, time, urllib.request
BASE = os.environ.get("SOLVEHUB_URL", "https://www.tiam.codes")
KEY = os.environ["SOLVEHUB_API_KEY"]
DEADLINE = time.time() + 240
def call(method, path, payload=None, idem=None):
body = json.dumps(payload).encode() if payload is not None else None
request = urllib.request.Request(BASE + path, data=body, method=method)
request.add_header("Authorization", "Bearer " + KEY)
if body:
request.add_header("Content-Type", "application/json")
if idem:
request.add_header("Idempotency-Key", idem)
with urllib.request.urlopen(request, timeout=20) as response:
return json.load(response)
def wait(task_id):
while time.time() < DEADLINE:
task = call("GET", "/v1/tasks/" + task_id)
if task["status"] == "completed":
return task["solution"]
if task["status"] in {"failed", "cancelled"}:
raise SystemExit("task %s ended as %s; check failureReason" % (task_id, task["status"]))
time.sleep(3)
raise SystemExit("client deadline reached; keep taskId and resume later")
if os.environ.get("SOLVEHUB_TASK_ID"):
task_id = os.environ["SOLVEHUB_TASK_ID"]
else:
with open(os.environ["SOLVEHUB_TASK_FILE"]) as handle:
task_id = call("POST", "/v1/tasks", json.load(handle), os.environ["SOLVEHUB_IDEMPOTENCY_KEY"])["taskId"]
print("taskId=" + task_id, file=sys.stderr)
print(json.dumps(wait(task_id)))
The script prints only the solution to stdout and the task ID to stderr. A completed Turnstile task therefore prints:
{"value": "0.EXAMPLE_TOKEN"}
クライアントの期限に達してもスクリプトが終了するだけで、サーバー側のタスクは継続します。SOLVEHUB_TASK_ID を設定して再実行すれば同じタスクの照会を続けられ、新しい課金は発生しません。
taskId が分かると直ちに stderr に表示し、完了した solution のみ stdout に出力します。業務記録に taskId を保存してください。この例は有料タスクを作成する場合があり、プレースホルダーだけでは動作しません。
既存タスクの再開
クライアント期限や不確定な結果では再作成せず、保存した ID を使います。
export SOLVEHUB_TASK_ID='SAVED_TASK_ID'
python3 python-client.py
ID を取得できなかった場合は元のキーと本文を保持し、再送可能期間内に再試行します。別のタスクに古いキーを流用しないでください。
障害時の動作
リクエストのタイムアウトは 20 秒、全体 240 秒、照会間隔 3 秒です。再試行可能な障害は最大 3 回で、HTTP 日付を含む Retry-After に従います。待機が残りの予算を超える場合は停止します。これはクライアントの設定で処理時間の保証ではありません。
failed/cancelled で終了し、uncertain は照会を続けます。別の送信先に Key を渡さないよう HTTP リダイレクトを拒否します。タスク全文や認証情報は自動記録しません。実運用前に冪等性、エラー処理、API 仕様を確認してください。
クライアントのバージョンと失敗時の扱い
ダウンロードするクライアントはバージョン 1.0.0 で、Python 標準ライブラリ(3.10 以上)のみを使用します。挙動は固定で文書化されているため、失敗時もソースを読まずに切り分けできます。
- 1 リクエストあたり 20 秒のタイムアウト、全体で 240 秒の予算、1 リクエストにつき最大 3 回の試行。
429、500、502、503、504ではRetry-After(秒数または HTTP 日付)に従います。- HTTP リダイレクトを拒否し、API Key が別オリジンへ転送されないようにします。
taskIdは判明次第 stderr に出力し、stdout には結果のみを出力します。完了したタスクは 1 つの JSON 値だけを表示します。
| レスポンス | 意味 | 対応 |
|---|---|---|
400 INVALID_TASK |
タスク項目の欠落または不正。 | 項目を修正したうえで、新しい冪等キーを使う新しいタスクとして送信します。元の結果が不明な場合は、再送の前に元のタスクを確認してください。 |
401 UNAUTHORIZED |
Key が無効または失効。 | Key を差し替えます。同じリクエストの再試行では成功しません。 |
402 INSUFFICIENT_BALANCE |
残高不足でタスクは作成されていません。 | 入金後、同じ冪等キーで再試行します。 |
403 で Key 関連のエラーコード |
権限・有効期限・IP 許可リストで拒否。 | コンソールで Key の権限、期限、許可リストを確認します。 |
429 |
レート制限。 | Retry-After だけ待機します(クライアントは既に待機します)。 |
500、502、503、504 |
上流の一時的な障害。 | 回数制限付きの再試行を終えた後、同じ Key と本文で再試行します。 |
TASK_FAILED、TASK_TIMEOUT |
タスクは終了しましたが結果がありません。 | failureReason を確認し、同じタスクを自動で再投入しないでください。 |
TASK_UNCERTAIN |
結果が不明。 | 同じ taskId を照会し続け、代替タスクを作らないでください。 |
終了コードも仕様の一部です。0 は結果を出力したこと、1 は stderr にエラーを出したことを意味します。修正したリクエスト本文は別のリクエストなので新しい冪等キーが必要です。同じキーは常に同じ本文に対応させる必要があります(重複タスクを避ける)。
開発者向けダウンロード
python-client.py v1.0.0 — 標準ライブラリのみ。挙動とエラーコードは本ページに記載しています。
関連ドキュメント
最終更新: