API — 验证码识别

一个使用 anti-captcha.com 协议的独立监听器:将第三方软件指向它,即可通过您自己的代理求解图片、访问 Cookie、RCv2、CFt、GT 和 AW。

这是什么

BlankTrail Proxy 可以通过 anti-captcha.com 协议接收验证码识别任务。它是一个独立端口上的独立监听器:已经支持该协议的第三方软件,只需把地址指向您的服务器,而不是识别服务的地址。

之所以采用独立监听器而非面板端口上的路由,有两个原因。协议的官方客户端请求主机根路径,即完全占用根路径。而且验证码 API 可能需要在局域网中使用,但管理面板不应对任何人可见。

默认关闭在您启用之前,验证码 API 不会启动,端口也完全不会被监听。这是有意为之:您不使用的功能不应该打开任何端口。

如何开启

配置文件 captcha_api 段中的三个字段。开关和地址也可以在面板中修改:设置 → “验证码 API”卡片。

captcha_api:
  enabled: true
  addr: ":8892"
  allow_lan: false
  max_concurrent: 10
  task_ttl: "5m"
  port_idle_timeout: "10m"
字段作用
enabled是否启动监听器。默认关闭。
addr监听地址。在允许局域网访问之前,空主机表示仅回环地址。
allow_lan即使面板通用的“允许局域网”关闭,也接受来自其他机器的请求。验证码 API 遵循面板的这一通用设置,本字段在其基础上额外开放它——与代理端口分开。在 Docker 镜像中已开启。
max_concurrent并发任务上限。零表示完全没有上限。
task_ttl任务完成后保留结果的时长。
port_idle_timeout为任务代理打开的端口在空闲多久后关闭。
立即生效面板中的开关和地址立即生效:保存后监听器就地启动或停止,地址被占用时会直接在面板中报错。“允许局域网”开关同样无需重启即可生效。直接修改配置文件仍然只在启动时读取——那种改动需要重启应用。

在容器中

除开关外,镜像中的其余部分都已配置妥当:8892 端口已声明,随镜像提供的 compose 文件将其发布到 127.0.0.1,镜像配置也已允许监听器绑定到回环地址以外。剩下的只是开启——用环境变量,或直接在面板中操作。覆盖是单向的:变量只能开启和设置,不能关闭配置中已启用的项。

docker run -d \
  -e BT_CAPTCHA_API_ENABLED=1 \
  -p 127.0.0.1:8892:8892 \
  ... blanktrail-proxy
镜像中为何开启 allow_lan在容器中,请求来自 Docker 网桥地址而非回环地址:若 allow_lan 关闭,空主机 :8892 会被替换为 127.0.0.1,已发布的端口只会返回连接被拒绝。BT_ALLOW_LAN 会在创建数据卷时开启通用的“允许局域网”(与代理密码一起),验证码 API 遵循该设置。BT_CAPTCHA_API_ALLOW_LAN 与代理端口分开、单独为验证码 API 开放局域网访问,只有在挂载自有配置替代镜像配置时才需要。

密钥与访问

clientKey 就是您面板的 API 密钥,完全相同。验证码 API 没有独立密钥:为一个接口引入另一个需要独立存储和轮换的密钥并不值得。

  • 密钥按协议要求放在请求体中,而不是请求头。
  • 密钥爆破受到限制:连续失败后,无论下一个密钥是否正确,该地址都会被拒绝。
  • 在允许局域网访问之前(通过通用的“允许局域网”设置或 allow_lan 字段),来自其他机器的请求会被拒绝——包括 getQueueStats 和 test。

支持的任务类型

类型作用
ImageToTextTask使用本地模型识别图片上的文字。
AntiGateTask通过站点防护并返回访问 Cookie。
RecaptchaV2Task根据页面地址和站点密钥求解 RCv2,并通过您的代理。
RecaptchaV2TaskProxyless同样的功能,但不使用您的代理——直接出口。
TurnstileTask根据页面地址和站点密钥获取 CFt 令牌,并通过您的代理。
TurnstileTaskProxyless同样的功能,但不使用您的代理。
GeeTestTask根据站点参数求解 GTv3 或 GTv4,并通过您的代理。
GeeTestTaskProxyless同样的功能,但不使用您的代理。
AmazonTask通过 AW 拦截页并返回其令牌,并通过您的代理。
AmazonTaskProxyless同样的功能,但不使用您的代理。

其他协议类型会返回 ERROR_TASK_NOT_SUPPORTED。这是正常响应而非故障:客户端在创建任务时立即看到它,可以直接改用其他服务,无需等待。

Proxyless 变体从安装本身的出口求解——即运行 BlankTrail Proxy 的机器的直接地址。即使发送了代理字段,这类任务也不会使用。

工作方式

  1. 通过 createTask 创建任务,获得数字 taskId。
  2. 轮询 getTaskResult,直到响应不再是 processing。
  3. 收到 ready 和解答对象——其内容取决于任务类型。
始终返回 HTTP 200错误通过响应体中的 errorId 和 errorCode 字段报告,而不是 HTTP 状态码——协议就是这样设计的。客户端若收到非 200,会认为服务已宕机并进入自己的重试逻辑。

出口与配置

除 ImageToTextTask 外,所有任务都由求解器的浏览器完成,它通过为任务代理打开的产品端口访问网络。这与代理端口上的自动求解是同一条路径:浏览器的请求从您代理的出口发出(Proxyless 变体则从安装本身的出口发出),使用该端口配置的 TLS 与 HTTP/2 指纹和 user-agent。令牌或 Cookie 是在端口向站点呈现的同一身份下获得的。

端口按“代理 + 配置”组合打开,并持续到 port_idle_timeout 设定的空闲时间。之后使用相同代理和相同配置的任务会通过同一个端口。

如何选择配置

您发送的 userAgent 不会出现在网络流量中。它按浏览器系列、主版本号和操作系统选择最接近的配置,实际发送的是该配置自身的 user-agent——以及与之匹配的 TLS 和 HTTP/2 指纹。

如果未发送 userAgent 或无法识别(Opera、Yandex 浏览器、不带 Version/ 标记的 Safari),端口将使用配置库中最新版本的 Windows 版 Chrome——与未指定版本的 Chrome 配置端口相同。AntiGateTask 和 AmazonTask 没有 userAgent 字段,始终使用该配置。

请使用响应中的 userAgent解答中的 userAgent 字段包含获取令牌或 Cookie 时实际使用的 user-agent。请在您的请求中使用它。在我们的流量之上叠加外来请求头,正是本产品要消除的那种不一致:若返回它,验证码 API 就会成为特征来源,而不是隐藏特征。

每个此类任务都会计入仪表盘 Challenge Breaker 卡片的一次尝试,与代理端口上的求解一并统计。

图片识别

图片以 base64 传递。响应在 text 字段中携带识别出的文字。

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "ImageToTextTask",
    "body": "iVBORw0KGgoAAAANSUhEUg..."
  }
}
模型基于特定数据训练该识别模型基于 RC 供应商的文字验证码训练。对于其他样式的验证码,准确率明显更低,这是模型本身的特性而非可调设置:在据此搭建流程前,请先在您自己的素材上测量正确率。

访问 Cookie

AntiGateTask 通过站点防护并返回 Cookie。响应中还会带回一个端口地址,这些 Cookie 必须通过该端口出示。

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "AntiGateTask",
    "websiteURL": "https://example.com/",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080,
    "proxyLogin": "user",
    "proxyPassword": "pass"
  }
}
Cookie 只能通过指定端口使用解答中包含带有 blanktrail.replayProxy 地址的 fingerprint 字段。访问 Cookie 绑定到“出口 + 指纹”这一组合,若从其他地址或其他客户端出示,将被站点拒绝。请通过该端口发送请求——它已为您的代理打开,并会持续到 port_idle_timeout 设定的空闲时间。

RCv2

该任务需要页面地址和站点公钥。不使用您代理的变体名为 RecaptchaV2TaskProxyless,无需代理字段。

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "RecaptchaV2Task",
    "websiteURL": "https://example.com/login",
    "websiteKey": "6Lc_aCMTAAAAA...",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080
  }
}

响应为 gRecaptchaResponse 和 userAgent(示例见下方 getTaskResult 方法)。

CFt

该任务需要页面地址和站点密钥(websiteKey,形如 0x4AAAA… 的字符串)。可选的 action、cData 和 chlPageData 会原样传给组件。不使用您代理的变体为 TurnstileTaskProxyless。

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "TurnstileTaskProxyless",
    "websiteURL": "https://example.com/login",
    "websiteKey": "0x4AAAAAAA...",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
  }
}

响应为 token 和 userAgent。令牌放入表单的 cf-turnstile-response 字段,或交给组件的回调;携带它的请求请使用响应中的 userAgent。

{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "token": "0.Zk3bE8...",
    "userAgent": "Mozilla/5.0 ..."
  }
}
CF 验证页不是组件如果站点显示“Just a moment…”中间页并等待 cf_clearance Cookie,需要解决的是拦截页而不是组件:请使用返回 Cookie 的 AntiGateTask。TurnstileTask 返回嵌入在页面或表单中的组件令牌。如果组件没有给出令牌,任务会在一分半钟内以 ERROR_CAPTCHA_UNSOLVABLE 结束。

GT

支持 GTv3 和 GTv4;version 字段指定版本(3 或 4,默认 3)。不使用您代理的变体为 GeeTestTaskProxyless。

  • v3:需要站点的 gt 和 challenge。challenge 只能使用一次——请在创建任务前立即从站点获取。可选的 geetestApiServerSubdomain 用于在站点不使用 GT 默认服务器时指定 API 服务器。
  • v4:需要 captchaId——放在 gt 字段或 initParameters.captcha_id 中。其余 initParameters 会原样传给 initGeetest4。
{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "GeeTestTaskProxyless",
    "websiteURL": "https://example.com/login",
    "gt": "0f1e2d3c4b5a69788796a5b4c3d2e1f0",
    "version": 4,
    "initParameters": {"riskType": "slide"},
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
  }
}

v3 的响应为 challenge、validate 和 seccode;v4 的响应为 captcha_id、lot_number、pass_token、gen_time 和 captcha_output,并附带 userAgent。您的请求把这些字段发送给站点,站点再向 GT 校验。

{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "captcha_id": "0f1e2d3c4b5a69788796a5b4c3d2e1f0",
    "lot_number": "7c1b2a...",
    "pass_token": "a8d9...",
    "gen_time": "1790770800",
    "captcha_output": "Qx3k...",
    "userAgent": "Mozilla/5.0 ..."
  }
}
只求解滑块求解器通过滑块验证——拖动拼图块。遇到其他类型的 GT 验证时,任务会以 ERROR_CAPTCHA_UNSOLVABLE 结束。

AW

该任务需要站点显示 AW 拦截页的页面地址。websiteKey、iv、context、challengeScript 和 captchaScript 字段为兼容性而接受,但并不需要:求解器会自行从页面获取这些信息。不使用您代理的变体为 AmazonTaskProxyless。

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "AmazonTask",
    "websiteURL": "https://example.com/",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080,
    "proxyLogin": "user",
    "proxyPassword": "pass"
  }
}

响应为 token 和 userAgent。token 是 aws-waf-token Cookie 的值:在您的请求中以该名称设置它,并使用响应中的 userAgent 发送请求。getTaskResult 响应中的 ip 字段是获取令牌时使用的出口地址。

{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "token": "a1b2c3d4-...:AAABk...",
    "userAgent": "Mozilla/5.0 ..."
  },
  "ip": "203.0.113.7"
}
只有出现拦截页时才有令牌求解器通过站点在该出口上显示的拦截页。如果没有出现拦截页,就没有 Cookie,任务会以 ERROR_CAPTCHA_UNSOLVABLE 结束。表单内的 AWS 验证码(wafType: widget)不是拦截页:它在用户操作时才出现,因此这类任务会立即收到 ERROR_TASK_NOT_SUPPORTED。

方法

POST/createTask需要 clientKey

创建任务并返回数字 taskId。

响应
{
  "errorId": 0,
  "taskId": 12
}
POST/getTaskResult需要 clientKey

返回任务状态,就绪后返回解答对象。

请求
{
  "clientKey": "YOUR_API_KEY",
  "taskId": 12
}
响应
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "gRecaptchaResponse": "03AGdBq26...",
    "userAgent": "Mozilla/5.0 ..."
  }
}
POST/getBalance需要 clientKey

返回余额。本产品没有计费,因此该值是固定的;为零表示许可证未激活。

POST/getQueueStats无需密钥

负载情况:有多少任务在执行,求解器池的繁忙程度。

POST/reportIncorrectImageCaptcha需要 clientKey

为兼容性而接受:本产品无法根据反馈进行学习。

POST/reportIncorrectRecaptcha需要 clientKey

RC 的同类接口。

POST/reportCorrectRecaptcha需要 clientKey

用于确认正确解答的同类接口。

POST/test无需密钥

返回解析后的请求体。当第三方客户端发送的内容有误时很有用。

错误码

错误码及其名称遵循协议:客户端库比较的正是 errorCode 字符串。下面是本服务会返回的错误码。

errorIderrorCode何时出现
1ERROR_KEY_DOES_NOT_EXIST密钥错误,或该地址因爆破尝试被临时封锁。
2ERROR_NO_SLOT_AVAILABLE当前没有空闲的求解器,或已达到 max_concurrent 上限。
10ERROR_ZERO_BALANCE许可证未激活:请续期,任务不会被受理。
11ERROR_IP_NOT_ALLOWED请求来自其他机器,而局域网访问未被允许——通用的“允许局域网”和 allow_lan 均未开启。
12ERROR_CAPTCHA_UNSOLVABLE求解失败。可以重试,但在端口因空闲关闭之前配置不会改变;若反复失败,请检查页面地址和站点参数:密钥、gt、challenge。
16ERROR_NO_SUCH_CAPCHA_ID不存在该 taskId 的任务:它已完成并在 task_ttl 到期后被清除,或属于其他密钥。
23ERROR_TASK_NOT_SUPPORTED任务类型不受支持、所需模型未安装,或任务种类不对——例如表单内的 AWS 验证码(wafType: widget)。
25ERROR_PROXY_CONNECT_REFUSED您的代理拒绝了连接。请修复代理,重试任务没有意义。
26ERROR_PROXY_CONNECT_TIMEOUT在规定时间内无法连接到您的代理。
27ERROR_PROXY_READ_TIMEOUT您的代理接受了连接但没有响应。
49ERROR_PROXY_NOT_AUTHORISED您的代理拒绝了用户名或密码。
代理相关错误码指的是您的代理25、26、27 和 49 这四个错误码指的是您在任务中提供的代理,而不是我们的出口。如果您的代理响应正常但求解失败,您会收到 ERROR_CAPTCHA_UNSOLVABLE:我们不会把自己的失败归咎于您的代理。

限制

  • 任务保存在内存中,重启后不会保留:重启后旧的 taskId 会返回 ERROR_NO_SUCH_CAPCHA_ID。
  • 在预算时间内未完成的任务会被判定为失败,并释放其在上限中的名额。
  • 不支持回调:callbackUrl 字段会被接受但忽略,结果需通过轮询获取。
  • 同一站点、同一代理的任务会依次执行——这是防重放机制的特性,而非配置上限。

后续阅读