Playwright for PythonでCAPTCHAの解答を送信する
まず CAPTCHA の解答を生成し、次に同じプロキシと返されたブラウザ識別情報を使って Playwright コンテキストを作成します。アプリケーションが実際に送信するフィールドを通じて solution.token を送信してください。
以下の例は、管理下にあるページのフォームを送信します。アプリケーションの POST レスポンスを待機するもので、reCAPTCHA をインターセプトしたり、汎用的な CAPTCHA コールバックに依存したりはしません。
このページの内容
送信先と環境を準備する
Python 3.10+ を使用し、Playwright とその Chromium ブラウザ、および公式 solvethree Python SDK の wheel をインストールしてください。ワークスペースの API キーは、ブラウザの JavaScript ではなく Python プロセス内に保持してください。
TARGET_URL: フォームページの完全な URL。この例では、解答リクエスト用にホスト名を抽出します。SOLVETHREE_PROXY: プロキシ URL。必要な場合は認証情報も含めます。解答生成とブラウザ通信には、同じプロキシを使用します。SOLVETHREE_API_KEY: ワークスペースの API キー。
対象ホスト名には、ワークスペースで利用できる有効なプロファイルが必要です。例を実行する前に、サイトプロファイルを設定してください。例の login アクションは、連携に必要なアクションに変更してください。ホスト名とアクションを送信しても、プロファイルは作成されません。このリクエストは、デフォルトで reCAPTCHA Enterprise v3 を使用します。
解答を生成し、Chromium を設定して送信する
# Install playwright and the official Python SDK; run playwright install chromium.
import asyncio
import os
from urllib.parse import urlsplit, unquote
from playwright.async_api import async_playwright
from solvethree import Solvethree
async def main():
target = os.environ["TARGET_URL"]
proxy = urlsplit(os.environ["SOLVETHREE_PROXY"])
client = Solvethree(os.environ["SOLVETHREE_API_KEY"])
task = {"site": urlsplit(target).hostname, "action": "login", "proxy": os.environ["SOLVETHREE_PROXY"]}
result = await asyncio.to_thread(client.solve, task, timeout=180)
solution = result["solution"]
async with async_playwright() as playwright:
browser = await playwright.chromium.launch()
try:
netloc = proxy.netloc.rsplit("@", 1)[-1]
context = await browser.new_context(
proxy={"server": f"{proxy.scheme}://{netloc}", "username": unquote(proxy.username or ""), "password": unquote(proxy.password or "")},
user_agent=solution["userAgent"], extra_http_headers={"sec-ch-ua": solution["secChUa"]})
page = await context.new_page()
await page.goto(target)
field = page.locator('[name="g-recaptcha-response"]')
await field.wait_for(state="attached")
await field.evaluate("(field, token) => { field.value=token; field.dispatchEvent(new Event('input',{bubbles:true})); }", solution["token"])
async with page.expect_response(lambda r: r.request.method == "POST" and urlsplit(r.url).netloc == urlsplit(target).netloc) as outcome:
await page.get_by_role("button", name="Submit", exact=True).click()
print("Application HTTP status:", (await outcome.value).status)
# Check the application's actual response; adapt form/CSRF/session setup.
await context.close()
finally:
await browser.close()
asyncio.run(main())Solvethree は同期型です。asyncio.to_thread 経由で client.solve を呼び出すことで、作成とポーリングの処理が Playwright のイベントループをブロックするのを防ぎます。準備できた結果を返すか、例外を送出します。SDK にネイティブの非同期クライアントはありません。
ブラウザコンテキストは solution.userAgent と solution.secChUa を使用します。また、この例ではプロキシサーバーをユーザー名とパスワードから分離し、認証情報をデコードしてから Playwright に渡します。このタスクではプロキシを 1 つ使用するため、候補を選択する手順はありません。
- 1.
アプリケーションのトークン入力に合わせる
この例では、フィールドが DOM に追加されるのを待ち、solution.token を代入して input イベントを発行します。フィールドが表示されている必要はありません。アプリケーションが別のフィールドを送信する場合や、別の場所からトークンの状態を読み取る場合は、送信リクエストに合うようにこの受け渡し処理を調整してください。
- 2.
フォームに必要なセッション処理を追加する
この例は、新しいブラウザコンテキストで開始します。送信前に、アプリケーションに必要なセッション処理、フォームの準備、CSRF 処理を追加してください。
- 3.
正しい POST を待機する
レスポンスの待機は、Submit をクリックする前に登録します。その判定条件は、送信先 URL のネットワークロケーションへの POST に一致します。ページが同じ場所にほかの POST リクエストも送信する場合は、送信エンドポイントに絞り込んでください。
アプリケーションのレスポンスを確認する
出力された HTTP ステータスにより、条件に一致するレスポンスが届いたことを確認できます。送信が受理されたかどうかは、アプリケーションのレスポンス本文や、その後のページの状態を確認して判断してください。solvethree のタスクが ready になったことは、解答が生成されたことを意味するだけで、送信先に受理されたことを意味しません。
- アプリケーションが準備済みのトークンを拒否する。
別の解答生成に料金を支払う前に、送信されるフォームリクエストを確認してください。
試してみましょう: タスク ID や古い値ではなく、solution.token が含まれていることを確認してください。送信時に、解答生成で使用したプロキシ、返されたユーザーエージェントとクライアントヒント、および意図した送信先が使われていることを確認します。
- レスポンスの待機が無関係なリクエストを捕捉する。
捕捉した POST の URL と、実際のフォームのエンドポイントを比較してください。
試してみましょう: 同じネットワークロケーションへのすべての POST に一致させるのではなく、そのエンドポイントに限定したレスポンス判定条件にしてください。
- ブラウザから送信する前に、解答生成の呼び出しが例外を送出する。
HTTP リクエストエラーと、失敗で終了したタスクを区別してください。
試してみましょう: 成功以外の HTTP レスポンスは別途処理してください。タスクが失敗した場合は、入力を変えずに再試行するのではなく、errorCode と error を確認して原因を修正します。SDK の solve メソッドは、失敗時にはすでに処理を停止します。
参照元とAPIリファレンス
最初のタスクを実行しましょう。
$5のワークスペースクレジットで始められます。