Scarnox · Blog

captchaトークンの期限切れ:原因と対処方法

captchaトークンは、チャレンジを通過したことを示す短命の証明です。ScarnoxのPopularCaptchaのトークンは、発行から約2分で期限切れになります。その時間を過ぎてからトークンを送信すると、サイトはフォームを拒否します。多くの場合、captchaの期限が切れている、または無効だというメッセージが表示されます。解決策はほとんどいつもタイミングの問題です。captchaを送信のできるだけ直前に解決し、トークンは1回だけ使い、最初の試行が受け付けられなかったと確信できる場合にだけ再試行してください。

トークンが期限切れになる理由

トークンは永続的な資格情報ではありません。サイトは、人(または代わりに動くソルバー)が最近チャレンジを完了したことを確かめたいので、トークンに短い寿命を与えています。期限が始まるのは、APIを最初に呼び出した時点ではなく、トークンが発行された時点です。解決と送信の間に起きることはすべて、その2分を消費します。

よくある原因

対処:送信の直前に解決する

最も確実な方法は、解決と送信を1つのステップにすることです。トークンを取得し、フォームに入れ、フォームを投稿し、その間には遅い処理を入れません。

import requests

API_KEY = "scarnox_YOURAPIKEY"
CREATE_URL = "https://api.scarnox.com/api/tasks/create"

def fresh_token(sitekey: str, page_url: str) -> str:
    r = requests.post(
        CREATE_URL,
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "captcha_type": "PopularCaptchaTaskProxyless",
            "site_key": sitekey,
            "site_url": page_url,
        },
        timeout=185,  # 呼び出しはトークンの準備ができるまでブロックされる
    )
    data = r.json()
    if data.get("errorId") != 0:
        raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
    return data["solution"]["token"]

def submit_form(page_url: str, sitekey: str, form: dict) -> requests.Response:
    token = fresh_token(sitekey, page_url)  # 投稿の直前に解決する
    return requests.post(
        page_url,
        data={**form, "h-captcha-response": token, "g-recaptcha-response": token},
        timeout=30,
    )

submit_formは、トークンをキャッシュにもキューにも保持しないことに注意してください。トークンを要求し、投稿して、次に進みます。失敗した解決は課金されないので、失敗したリクエストは解決側の費用にはなりません。

安全にリトライする

サイトによっては、期限切れのトークンを明確なレスポンスで拒否します。一方で、ページ内にエラーメッセージを含む通常のページを返すサイトもあり、その場合はステータスコードだけでは分かりません。期限切れのトークンに対してサイトが実際に返すレスポンスを確認して、それに基づいてチェックを作ってください。リトライのループは次のようになります。

def submit_with_retry(page_url: str, sitekey: str, form: dict, attempts: int = 2):
    for _ in range(attempts):
        resp = submit_form(page_url, sitekey, form)
        if resp.status_code < 400 and "captcha" not in resp.text.lower():
            return resp  # このサイトのレスポンスから見て受け付けられた
    raise RuntimeError("captcha token rejected after retries")

何かを作成するフォームでのリトライには注意してください。最初の試行が実際には受け付けられていたのに、コードがレスポンスを読み誤ると、リトライで重複したアカウント、注文、メッセージが作られてしまいます。最初の投稿が受け付けられなかったと確信できる場合にだけ再試行し、そのチェックは扱っているサイトに固有のものにしてください。

タイミングを正直に保つ

よくある間違い

原因を突き止めるためのログ

送信が失敗したときは、トークンが発行された時刻、フォームを投稿した時刻、HTTPステータス、レスポンスの最初の数百文字を記録してください。この4つの値があれば、トークンが期限切れになったのか、それとも別の理由でサイトに拒否されたのかが一目で分かります。共有されるログには、トークン全体を記録しないでください。有効なトークンは、そのチャレンジに対する資格情報だからです。

それでも失敗する場合の確認事項

  1. トークンが返ってから、フォームを投稿するまでの時間を出力する。
  2. site_urlが、captchaを表示しているページと一致しているか確認する。
  3. サイトキーが、古いコピーではなく、現在のページから読み取られたものか確認する。
  4. フォームのフィールド名を確認する。PopularCaptchaのトークンはh-captcha-responseに入り、g-recaptcha-responseにも入ることが多いです。

エラーレスポンスの一覧と、それぞれの対処方法は、captcha解決のエラー処理にまとめています。

次のステップ