Use Cases

政府门户网站中的 BLS 验证码:处理策略

签证预约总约不到号,卡住流程的往往不是验证码,而是识别和提交之间的时间差太紧。BLS 是使领馆签证、证件门户常用的验证码方案,几乎每步都会弹一次。CaptchaAI 识别 BLS 通常 1 秒内完成,真正决定成败的是会话保持和提交时机——国内签证代办、留学团队常盯紧名额,一有空位就处理。下面按实际顺序拆解整个流程。

用 CaptchaAI 识别 BLS 验证码:三步流程

分三步:抓图、识别、提交,顺序不能打乱——结果要回填同一个 session。

第一步:抓取验证码图片和 instructions 参数

图片有的内联 base64,有的是独立 URL,两种都要处理:

import requests
from bs4 import BeautifulSoup
import base64

session = requests.Session()

# Load the portal page
page = session.get("https://portal.example.gov/appointment")
soup = BeautifulSoup(page.text, "html.parser")

# Find the CAPTCHA image
captcha_img = soup.select_one("img#captcha-image, img.captcha")
captcha_url = captcha_img["src"]

# Download the CAPTCHA image
if captcha_url.startswith("data:"):
    # Base64 encoded inline image
    img_data = captcha_url.split(",")[1]
else:
    # URL-referenced image
    img_response = session.get(captcha_url)
    img_data = base64.b64encode(img_response.content).decode()

第二步:调用 CaptchaAI 接口识别

提交到 in.php,每 3 秒轮询一次 res.php,最多 30 次超时报错:

import time

def solve_bls_captcha(image_base64, instructions=""):
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "base64",
        "body": image_base64,
        "instructions": instructions,
        "json": 1
    })
    task_id = resp.json()["request"]

    for _ in range(30):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]
    raise TimeoutError("BLS solve timed out")

# Solve
captcha_answer = solve_bls_captcha(img_data)

第三步:把识别结果提交回表单

用同一个 session 提交,cookie 自动带上,换新 session 会失效:

# Find form fields
form_data = {
    "captcha_response": captcha_answer,
    "appointment_type": "visa",
    "location": "embassy-city",
    # ... other form fields
}

# Submit with the same session (cookies preserved)
result = session.post(
    "https://portal.example.gov/appointment/submit",
    data=form_data
)

if "success" in result.text.lower():
    print("Form submitted successfully")

政府门户的三种典型交互模式

摸清交互模式比提速更有效,常见三种:

模式一:多步骤表单,验证码放在最后一步

服务类型、个人信息、时段依次填完,验证码卡最后一步:

# Step 1: Select service type
session.post(url, data={"service": "passport"})

# Step 2: Fill personal details
session.post(url, data={"name": "...", "dob": "..."})

# Step 3: Select appointment slot
session.post(url, data={"slot": "2026-04-10-09:00"})

# Step 4: Solve CAPTCHA and confirm
captcha_answer = solve_bls_captcha(get_captcha_image(session))
session.post(url, data={"captcha": captcha_answer, "confirm": "true"})

模式二:验证码答错后自动刷新

答错会直接换新图,重试要连着重新抓图一起做:

max_attempts = 3
for attempt in range(max_attempts):
    # Get fresh CAPTCHA for each attempt
    captcha_image = get_captcha_image(session)
    answer = solve_bls_captcha(captcha_image)

    result = session.post(submit_url, data={"captcha": answer})
    if "incorrect" not in result.text.lower():
        break
    print(f"Attempt {attempt + 1} — CAPTCHA refreshed, retrying")

模式三:会话有效期限制

会话通常 10 分钟过期,提前留余量比重试更省时间:

import time

session_start = time.time()
SESSION_TIMEOUT = 600  # 10 minutes typical

def check_session_valid():
    elapsed = time.time() - session_start
    if elapsed > SESSION_TIMEOUT - 60:  # 1 min safety margin
        print("Session expiring — refresh needed")
        return False
    return True

# Before CAPTCHA submission
if not check_session_valid():
    # Start a fresh session
    session = requests.Session()
    session.get(portal_url)
    session_start = time.time()

常见问题排查

问题 原因 处理方式
识别成功但提示会话已过期 识别和提交间隔太久 识别完立刻提交
验证码图片加载不出来 门户校验 Referer 头 Referer 设为门户页面 URL
答案正确但表单被拒 缺少 CSRF token 或隐藏字段 提取表单所有隐藏 input
多次尝试后门户拒绝 触发限流 拉长尝试间隔
每次验证码都不一样 门户按请求动态生成 每次重新抓图再识别

政府门户对会话容忍度比电商网站低:

要求 落地做法
精确维护 cookie requests.Session() 或持久化上下文
不触发限流 请求间加 2–5 秒延迟
处理 CSRF token 每次 POST 前提取并带上
尊重会话超时 全流程控制在超时窗口内
跟随重定向 客户端自动处理重定向

BLS 验证码出现在政府门户的哪些环节

BLS 验证码常见于需要锁定名额或核实身份的环节:

门户场景 验证码出现位置 目的
签证预约 选时段前 防止脚本批量占用时段
材料上传 提交前 确认操作者是真人
状态查询 展示结果前 限制查询频率
申请表提交 提交前 防止批量提交

BLS 验证码常见的挑战类型

BLS 验证码不是单一样式,常见的有这几类:

  • 扭曲文字的图像挑战
  • 数学算式挑战
  • 自定义图片选择任务
  • 文字类谜题

每种挑战对应一个 instructions 参数,告诉 CaptchaAI 按哪种方式识别。

门户需要 JavaScript 渲染时,改用浏览器自动化

验证码由前端动态渲染时,改用 Puppeteer 更合适:

const puppeteer = require('puppeteer');

async function handleBLSPortal() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();

  await page.goto('https://portal.example.gov/appointment');

  // Wait for CAPTCHA to load
  await page.waitForSelector('img#captcha-image');

  // Get CAPTCHA image as base64
  const imgBase64 = await page.evaluate(() => {
    const img = document.querySelector('img#captcha-image');
    const canvas = document.createElement('canvas');
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0);
    return canvas.toDataURL('image/png').split(',')[1];
  });

  // Solve with CaptchaAI
  const answer = await solveBLSCaptcha(imgBase64);

  // Type the answer
  await page.type('#captcha-input', answer);

  // Submit
  await page.click('#submit-button');

  // Wait for result
  await page.waitForNavigation();
}

常见问题

BLS 验证码和常见的 reCAPTCHA、Turnstile 有什么不同?

BLS 更接近图片验证码:扭曲文字、算式、图片选择为主,依赖图像识别而非行为打分。建议先抓一张真实图片确认题型。

识别 BLS 验证码要多久?

识别本身通常 1 秒内完成,是官方 SLA 上限,真正占时间的是下载、排队和提交,都算进超时预算。

提交后提示会话已过期,是识别太慢了吗?

多数不是,常见原因是没立刻提交,或 cookie、CSRF token 没带过去。验证码放最后一步识别即可避免。

应该用浏览器自动化还是直接发 HTTP 请求?

字段能从 HTML 直接拿到时,requests.Session() 更快;只有依赖 JavaScript 渲染时才需要浏览器自动化。

相关文章

下一步

门槛不在识别率,而在会话和提交时机。获取 CaptchaAI API 密钥,实测一遍。

该文章已禁用评论。