Scarnox · Blog

验证码 token 已过期:原因与解决方法

验证码 token 是一种短期有效的凭证,用于证明挑战已经通过。Scarnox 的 PopularCaptcha token 在签发后约两分钟过期。如果你在这一时间窗口之后提交 token,网站会拒绝表单,通常会提示验证码已过期或无效。问题的修复几乎总是与时机有关:尽量靠近提交时再求解验证码,每个 token 只使用一次,并且只有在确认第一次尝试未被接受时才重试。

为什么 token 会过期

token 并不是永久有效的凭证。网站希望确认是一个人(或代表其行事的求解器)最近完成了挑战,因此给 token 设定了较短的有效期。计时从 token 签发时开始,而不是从你首次调用 API 时开始。在求解与提交之间发生的任何事情,都会消耗这两分钟。

常见原因

解决办法:在提交前立即求解

最简单可靠的做法,是把求解和提交合并为一步:请求一个 token,把它放入表单,提交表单,并且在两者之间不做任何耗时的操作:

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,  # 调用会阻塞直到 token 准备好
    )
    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 并不会把 token 保存在缓存或队列中。它请求一个 token,提交它,然后继续。失败的求解不收费,因此失败的请求在求解这一侧不会产生费用。

安全地重试

有些网站会以明确的响应拒绝过期的 token。另一些网站则会返回一个正常的页面,其中包含错误提示,因此仅凭状态码无法判断。请查看网站对过期 token 实际返回的响应,并据此编写检查逻辑。重试循环可以像这样:

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")

对于会创建内容的表单,重试时要格外小心。如果第一次尝试实际上已被接受,而你的代码误读了响应,那么重试就可能创建重复的账户、订单或消息。只有在你确定第一次 POST 未被接受时才重试,并且针对你所处理的网站编写具体的检查逻辑。

保持时间安排合理

常见错误

记录足够的日志以便诊断

当提交失败时,请记录 token 的签发时间、表单的提交时间、HTTP 状态码,以及响应的前几百个字符。有了这四项信息,你就能一眼看出是 token 过期了,还是网站因其他原因拒绝了它。不要在共享日志中记录完整的 token,因为一个有效的 token 就是一次挑战的凭证。

如果仍然失败,请检查以下几点

  1. 打印 token 返回与表单提交之间的时间间隔。
  2. 确认 site_url 与显示验证码的页面一致。
  3. 确认 sitekey 是从当前页面读取的,而不是旧副本。
  4. 确认表单字段名称。PopularCaptcha 的 token 应放入 h-captcha-response,通常也应放入 g-recaptcha-response。

完整的错误响应列表以及每种错误的处理方式,请参阅验证码求解器错误处理。

下一步