如何用 CapSkip SDK 在 Python 中识别 reCAPTCHA v2

solve recaptcha v2 in python - How to Solve reCAPTCHA v2 in Python With the CapSkip SDK

reCAPTCHA v2 有三种变体,在 Python 中它们是同一个函数,只是使用不同的关键字参数。Checkbox 是最基本的调用,Invisible 和 Enterprise 是标志参数,两者也可同时设置。Python 还是唯一拥有真正独立异步客户端的 CapSkip SDK,一旦你需要同时识别多个验证码,这一点就很重要。

设置

# Python 3.10 or newer.
pip install capskip

CapSkip 在本地识别,因此请先启动桌面应用,然后将客户端指向其设置中显示的端口:

from capskip import CapSkip

solver = CapSkip(
    apiKey="capskip",        # any string when key validation is off
    host="127.0.0.1",
    port=8080,
    recaptchaTimeout=300,    # seconds
)

在生产环境中,改为从环境变量读取这些值:

import os
from capskip import CapSkip

solver = CapSkip(
    apiKey=os.getenv("CAPSKIP_API_KEY", "capskip"),
    host=os.getenv("CAPSKIP_HOST", "127.0.0.1"),
    port=int(os.getenv("CAPSKIP_PORT", "8080")),
)

三种变体

变体需添加的关键字
复选框无
隐形invisible=1
Enterpriseenterprise=1
隐形 Enterprise两者
# Checkbox: the baseline call.
result = solver.recaptcha(
    sitekey="6Lc...YOUR_SITEKEY",
    url="https://example.com/login",
)

print(result["code"])   # g-recaptcha-response token

# Invisible.
result = solver.recaptcha(sitekey=sitekey, url=page_url, invisible=1)

# Enterprise, and both together.
result = solver.recaptcha(sitekey=sitekey, url=page_url, enterprise=1)
result = solver.recaptcha(sitekey=sitekey, url=page_url, enterprise=1, invisible=1)

返回值是一个普通的 dict,因此 result["code"] 就是 token。还有 result["captchaId"] 如果你想记录是哪次内部识别产生了它。

正确获取 sitekey 和 URL

sitekey 是 data-sitekey 小组件容器上的属性,或者是传给 grecaptcha.render 在没有容器时。它始终以 6L 开头,且是公开的。

URL 必须是小组件实际渲染所在的页面。传入你的表单处理程序或登录后的重定向,是 token 识别顺利却随后验证失败的最常见原因。

提交 token

import requests

response = requests.post(
    "https://example.com/login",
    data={
        "g-recaptcha-response": result["code"],
        "username": "...",
        "password": "...",
    },
)

token 有效期约两分钟且只能使用一次,因此请在流程中尽可能晚地识别。如果网站把 token 交给 JavaScript 回调而不是表单字段,识别相同但提交方式不同,这一点我们的 reCAPTCHA v2 回调识别工具 页面有说明。

同时识别多个

这就是 Python 与其他 CapSkip SDK 不同之处。 AsyncCapSkip 是真正的异步实现,而非别名,因此它能真正地并行识别:

import asyncio
from capskip import AsyncCapSkip

async def main():
    solver = AsyncCapSkip()
    r1, r2 = await asyncio.gather(
        solver.recaptcha(sitekey=key_a, url="https://a.example.com"),
        solver.recaptcha(sitekey=key_b, url="https://b.example.com"),
    )
    print(r1["code"], r2["code"])

asyncio.run(main())

在 Node.js 和 .NET SDK 中 AsyncCapSkip 只是一个别名,而在 PHP 中它的存在纯粹是为了让移植的代码能编译。Python 是唯一切换到它会真正改变行为的语言。

错误

from capskip import (
    CapSkip, ValidationException, NetworkException,
    ApiException, TimeoutException,
)

try:
    result = solver.recaptcha(sitekey=sitekey, url=page_url)
except ValidationException:
    pass   # missing or malformed arguments
except NetworkException:
    pass   # CapSkip is not running
except ApiException:
    pass   # bad sitekey or pageurl
except TimeoutException:
    pass   # exceeded recaptchaTimeout

这四个都派生自同一个基类,因此 except CapSkipError 如果你更愿意在一处处理失败,它会捕获全部情况。

使用代理

result = solver.recaptcha(
    sitekey=sitekey,
    url=page_url,
    proxy={"type": "HTTPS", "uri": "user:[email protected]:3128"},
)

Proxies work for reCAPTCHA, Turnstile, GeeTest and CaptchaFox. They are not supported for image CAPTCHAs, which are solved from the image bytes and never reach the target site.

常见问题

我需要轮询结果吗?

不需要。SDK 会在内部轮询并返回完成的 token,因此 CAPCHA_NOT_READY 永远不会出现在你的代码里。它在 250 毫秒后开始检查并逐步退避,这通常比手写的循环更快。

对于单次识别,AsyncCapSkip 值得使用吗?

不太需要。它在多个识别相互重叠时才重要,或者当你已经处于事件循环内、阻塞调用会拖住它时才重要。如果只是脚本中的一次识别,同步客户端更简单。

支持哪些 Python 版本?

3.10 及更新版本。该包没有繁重的依赖,因此可以直接接入现有的爬虫或自动化项目,而不会拉入一大堆额外的包。

小结

一个函数、三种变体,通过 invisible 和 enterprise选择。读取 result["code"],将其作为 g-recaptcha-response,并在 AsyncCapSkip 批量识别时使用它。

更完整的 Python 接口见 Python 验证码识别工具 页面,其他语言见 reCAPTCHA v2 识别 页面,还有一个 在线 v2 演示 可供测试。CapSkip 采用 验证码识别工具 在你自己的机器上运行。