API — 验证码识别

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

这是什么

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 之前,空主机表示仅回环地址。
allow_lan是否接受来自其他机器的请求。这是独立设置,与面板的同名设置无关;在 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 只有在挂载自有配置替代镜像配置时才需要。

密钥与访问

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

  • 密钥按协议要求放在请求体中,而不是请求头。
  • 密钥爆破受到限制:连续失败后,无论下一个密钥是否正确,该地址都会被拒绝。
  • 在未开启 allow_lan 之前,来自其他机器的请求会被拒绝——包括 getQueueStats 和 test。

支持的任务类型

类型作用
ImageToTextTask使用本地模型识别图片上的文字。
AntiGateTask通过站点防护并返回访问 Cookie。
RecaptchaV2Task根据页面地址和站点密钥求解 reCAPTCHA v2,并通过您的代理。
RecaptchaV2TaskProxyless同样的功能,但不使用您的代理——直接出口。

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

工作方式

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

图片识别

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

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

访问 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 设定的空闲时间。

reCAPTCHA v2

该任务需要页面地址和站点公钥。不使用您代理的变体名为 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
  }
}

您发送的 userAgent 会怎样

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

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

方法

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

reCAPTCHA 的同类接口。

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求解失败。可以重试,但在端口因空闲关闭之前配置不会改变;若反复失败,请检查页面地址和站点密钥。
16ERROR_NO_SUCH_CAPCHA_ID不存在该 taskId 的任务:它已完成并在 task_ttl 到期后被清除,或属于其他密钥。
23ERROR_TASK_NOT_SUPPORTED任务类型不受支持,或所需模型未安装。
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 字段会被接受但忽略,结果需通过轮询获取。
  • 同一站点、同一代理的任务会依次执行——这是防重放机制的特性,而非配置上限。

后续阅读