Comparisons

BLS CAPTCHA 与 reCAPTCHA Grid — 比较

同样是点选图片,BLS CAPTCHA 和 reCAPTCHA 九宫格的识别路径却完全不同:BLS 必须把每张图片抠出来、编码成 base64 再发给接口,reCAPTCHA 只要拿一个 token 回填即可。BLS CAPTCHA 是 BLS International 签证系统专用的定制实现,reCAPTCHA 则是 Google 全球通用的方案。先把两条路径的核心区别摆出来:

  • BLS: 图片直接嵌在页面 DOM 里,必须逐张抠图、编码成 base64 上传,离不开浏览器,走 method=bls
  • reCAPTCHA 九宫格: 走 token 路线,拿 sitekey 换到 g-recaptcha-response 回填即可,可纯 HTTP,走 method=userrecaptcha

如何选型:先决定用哪种方法

看到图片验证码,先判断它是 BLS 品牌还是 reCAPTCHA,再决定走哪条路径。

场景 建议方法
BLS 签证预约 method=bls,走图片提取
任意带 reCAPTCHA 的站点 method=userrecaptcha,带上 sitekey
BLS 页面内嵌 reCAPTCHA 先判断是哪一个在拦截提交——BLS 站点有时两者都用
不确定的图片验证码 先看是不是 BLS 品牌;不是就试 reCAPTCHA 或 OCR 方法

在中国申请申根、英国等签证时,BLS International 是常见的签证代传中心,其预约页面用的就是这套自定义图片验证码;国际站点和表单里遇到的则多半是 reCAPTCHA。批量处理 reCAPTCHA 时,token 请求无状态、可并发,配合线程套餐更划算——CaptchaAI 按并发线程计费,从 BASIC($15/月,5 线程)到 ADVANCE($90/月,50 线程),线程内不限识别次数。


并排对比

对比项 BLS CAPTCHA reCAPTCHA 九宫格
提供方 BLS International(定制实现) Google
图片形式 3–9 张独立图片 一整张图切成 3×3 或 4×4 网格
动态图块 无,图片集固定 有,选中后会淡入新图块
行为分析 很少 广泛(鼠标轨迹、计时、IP)
风险评分 每次请求都做风险分析
API 方法 method=bls method=userrecaptcha
必填参数 instructionsimage_base64_1..9 googlekeypageurl
返回内容 图片索引(如 1,3,5 token 字符串
是否 token 化 否,必须直接识别图片 是,token 方法内部处理网格
是否需要浏览器 需要(要从 DOM 抠图) 可选(token 方法无需浏览器)
出现场景 仅 BLS 签证预约站点 全球数百万站点
典型识别耗时 5–15 秒 10–30 秒

用 CaptchaAI 识别 BLS CAPTCHA

  1. 用浏览器读取验证码的指令文本(如“选出所有摩托车”)。
  2. 逐张抠出图片,编码成 base64。
  3. 带上 method=bls 和指令,把所有图片一起提交到接口。
  4. 每 5 秒轮询一次结果,拿到图片索引(如 1,3,5)。
  5. 按返回的索引在页面上依次点选。

Python:

import requests
import base64
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example-bls-site.com/appointment")

# Step 1: Extract instruction text
instruction = driver.find_element(By.CSS_SELECTOR, ".captcha-instruction").text
# Example: "Select all images with a motorcycle"

# Step 2: Extract and encode each image
images = driver.find_elements(By.CSS_SELECTOR, ".captcha-image img")
image_data = {}
for i, img in enumerate(images, 1):
    # Get image source and convert to base64
    src = img.get_attribute("src")
    if src.startswith("data:image"):
        b64 = src.split(",")[1]
    else:
        img_bytes = requests.get(src).content
        b64 = base64.b64encode(img_bytes).decode()
    image_data[f"image_base64_{i}"] = b64

# Step 3: Submit to CaptchaAI
payload = {
    "key": "YOUR_API_KEY",
    "method": "bls",
    "instructions": instruction,
    **image_data
}
resp = requests.post("https://ocr.captchaai.com/in.php", data=payload)
task_id = resp.text.split("|")[1]

# Step 4: Poll for result
for _ in range(30):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        indices = result.text.split("|")[1]  # e.g., "1,3,5"
        break

# Step 5: Click the correct images
for idx in indices.split(","):
    images[int(idx) - 1].click()
    time.sleep(0.3)  # Small delay between clicks

Node.js:

const axios = require("axios");
const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch({ headless: "new" });
  const page = await browser.newPage();
  await page.goto("https://example-bls-site.com/appointment");

  // Extract instruction text
  const instruction = await page.$eval(
    ".captcha-instruction",
    (el) => el.textContent,
  );

  // Extract images as base64
  const imageElements = await page.$$(".captcha-image img");
  const imageData = {};
  for (let i = 0; i < imageElements.length; i++) {
    const src = await imageElements[i].evaluate((el) => el.src);
    let b64;
    if (src.startsWith("data:image")) {
      b64 = src.split(",")[1];
    } else {
      const resp = await axios.get(src, { responseType: "arraybuffer" });
      b64 = Buffer.from(resp.data).toString("base64");
    }
    imageData[`image_base64_${i + 1}`] = b64;
  }

  // Submit to CaptchaAI
  const formData = new URLSearchParams({
    key: "YOUR_API_KEY",
    method: "bls",
    instructions: instruction,
    ...imageData,
  });
  const submitResp = await axios.post(
    "https://ocr.captchaai.com/in.php",
    formData.toString(),
  );
  const taskId = submitResp.data.split("|")[1];

  // Poll for result
  let indices;
  for (let i = 0; i < 30; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: "YOUR_API_KEY", action: "get", id: taskId },
    });
    if (result.data.startsWith("OK|")) {
      indices = result.data.split("|")[1];
      break;
    }
  }

  // Click correct images
  for (const idx of indices.split(",")) {
    await imageElements[parseInt(idx) - 1].click();
    await new Promise((r) => setTimeout(r, 300));
  }

  await browser.close();
})();

用 CaptchaAI 识别 reCAPTCHA 九宫格

  1. 从页面读取 data-sitekey
  2. 带上 method=userrecaptchagooglekeypageurl 提交任务。
  3. 每 5 秒轮询一次,拿到 g-recaptcha-response token。
  4. 把 token 回填到隐藏字段,或直接随表单 POST 提交。

Python:

import requests
import time

# Step 1: Extract sitekey from page
# <div class="g-recaptcha" data-sitekey="6Le-wvkS..."></div>
sitekey = "6Le-wvkSAAAAAPBMRTvw..."
page_url = "https://example.com/form"

# Step 2: Submit to CaptchaAI
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

# Step 3: Poll for token
for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

# Step 4: Inject token (no clicking needed)
# Option A: Hidden field injection
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)
# Option B: Pure HTTP submission
requests.post(page_url, data={"g-recaptcha-response": token, "other_field": "value"})

Node.js:

const axios = require("axios");

async function solveRecaptchaGrid(sitekey, pageUrl) {
  // Submit
  const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
    params: {
      key: "YOUR_API_KEY",
      method: "userrecaptcha",
      googlekey: sitekey,
      pageurl: pageUrl,
    },
  });
  const taskId = submitResp.data.split("|")[1];

  // Poll for token
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: "YOUR_API_KEY", action: "get", id: taskId },
    });
    if (result.data.startsWith("OK|")) {
      return result.data.split("|")[1];
    }
  }
  throw new Error("Solve timed out");
}

集成复杂度对比

两者最大的差距在集成成本:BLS 每一步都得自己动手,reCAPTCHA 的 token 方法把网格处理都藏在了接口里。

环节 BLS reCAPTCHA 九宫格
图片提取 必须手动从 DOM 逐张抠出 不需要,token 方法内部处理
指令解析 必须从页面读取提示文本 不需要
Base64 编码 每张图片都要 不需要
结果回填 按返回索引逐个点选图片 把 token 提交到隐藏字段或 HTTP POST
浏览器自动化 必需,没有无头替代方案 可选,可纯 HTTP 请求
失败恢复 重新抠图后重试 重新请求 token
并发识别 受限,图片与浏览器会话绑定 简单,token 请求无状态
典型代码量 40–60 行 15–25 行

常见问题排查

两者排查思路不同:BLS 多半错在抠图和指令,reCAPTCHA 多半错在参数和回填。

问题 BLS 排查 reCAPTCHA 排查
返回答案错误 核对指令文本与页面显示是否一致 确认 sitekey 和 pageurl 是否正确
图片加载不出来 抓取图片 URL 时补上 User-Agent 和 cookie 不涉及——没有需要抓取的图片
token 被拒 按正确顺序点选页面上的索引 回填 g-recaptcha-response 并执行回调
识别太慢 减少图片数量,只发可见图片 在目标站点就近部署代理以降低延迟

常见问题

为什么 BLS CAPTCHA 必须开浏览器,reCAPTCHA 却不用?

BLS 的图片直接嵌在页面 DOM 里,只能靠浏览器把每张图抠出来再编码上传,所以必须有浏览器会话。reCAPTCHA 用的是 token 方法,只要页面上的 sitekey 和 pageurl 就能提交,纯 HTTP 请求即可,不依赖浏览器。

reCAPTCHA 九宫格识别该选哪个套餐?

CaptchaAI 按并发线程计费,不按次数。token 请求无状态、可以并发,量不大时 BASIC($15/月,5 线程)就够用;并发需求高再往 ADVANCE($90/月,50 线程)以上升级,线程内识别次数不限。

CaptchaAI 能识别 hCaptcha 和 FunCaptcha 吗?

不支持。CaptchaAI 目前覆盖 reCAPTCHA、Cloudflare Turnstile、GeeTest v3、BLS 以及图片/OCR 类验证码;hCaptcha 和 FunCaptcha 暂不在支持范围内。选型时先确认目标站点用的是哪种验证码。

BLS 预约页面同时出现两种验证码怎么办?

分别处理。有些 BLS 站点用自定义图片验证码做初次校验,再用 reCAPTCHA 守住表单提交。先分别检测两种类型,各自调用对应的 CaptchaAI 方法即可。


相关指南

该文章已禁用评论。