Comparisons

文本验证码与图像验证码:开发人员比较

一句话结论:扭曲字符图 + 一个输入框 = 文本验证码,走 OCR 接口就能识别;加载了第三方脚本、弹出九宫格点红绿灯 = 图像验证码,需要专门的求解器。 判断错了,你会在一个不存在的 sitekey 上耗掉半天。下面先给对比结论,再讲原理、检测和选型。


先看硬指标:两类验证码的正面对比

维度 文本验证码 图像验证码
安全强度 低(OCR 识别率高) 高(需物体识别)
用户解决时间 5–10 秒 10–30 秒
人类失败率 15–20% 8–15%
无障碍 视障用户困难 视障用户几乎不可用
移动端 一般(字符小) 较好(点选)
自动化难度 低(OCR) 高(图像分类)
部署成本 免费(自建) 免费到付费(第三方)
自动识别成本 每 1,000 次约 $0.50–$1.00 每 1,000 次约 $1.50–$3.00
数据采集 可能训练 ML 模型
接入工作量 小(服务端生成) 中(JavaScript SDK)

表中价格是按次计费市场的参考区间,实际报价以各服务商公开页面为准。CaptchaAI 不按次计费,而是按并发线程计价、套餐内不限识别次数:BASIC $15/月(5 线程)、STANDARD $30(15 线程)、ADVANCE $90(50 线程),最高到 VIP-3 $7,500(5,000 线程)。混合负载要估的是并发量。


文本验证码的原理与常见干扰手段

文本验证码把随机字符渲染成图片,用户读出来填进输入框,服务端做一次字符串比对(通常忽略大小写)。整套逻辑服务端就能实现,不依赖外部服务——这也是它在老系统和自建后台里活到今天的原因。常见干扰手段:

技术 目的
字符扭曲 让简单 OCR 失效
背景噪点 文字后加线条、点或渐变
字符粘连 相邻字母重叠,阻止分割
字体随机 每次换字体和字号
颜色扰动 随机化前景与背景配色

生成与校验流程:

Server generates random string (e.g., "X7mK9p")
    ↓
Applies distortion: warping, noise, overlap
    ↓
Renders as PNG/JPEG image
    ↓
User reads characters, types into input field
    ↓
Server compares input against stored string (case-insensitive usually)

干扰强度和可读性此消彼长:扭曲到 OCR 认不出,真人失败率也会上去。


图像验证码的原理与常见形态

图像验证码给出一组图片和提示语,让用户点出符合类别的那几张,判断依据是选择是否与标注数据一致。

形态 挑战内容 代表提供商
九宫格选择 “选出所有含红绿灯的方块” reCAPTCHA v2
图片标注 “点击所有包含公交车的图片” hCaptcha
物体计数 “图中有几辆自行车” 自研
旋转校正 “把图片转正” FunCaptcha

流程:

Server selects images from a labeled dataset
    ↓
Presents 3×3 or 4×4 grid with a text prompt
    ↓
User clicks matching images
    ↓
Server validates selections against ground truth
    ↓
If fading images: new images load in place of selected ones (multi-round)

国内站点上遇到的“图像验证码”,多半不是 reCAPTCHA。 主流是 GeeTest(极验)的滑块与点选、网易易盾、腾讯防水墙、阿里云验证码;reCAPTCHA 多见于海外站点,脚本托管在 Google 域名下,国内联调常卡在加载这一步。所以动手前先跑一遍检测。


用代码判断页面上是哪一种

规则很简单:先查第三方脚本特征,命中即图像验证码;没命中再看有没有“验证码图片 + 输入框”这对组合。 顺序不能反——接了 reCAPTCHA 的页面同样有带 captcha 的输入框。

Python 检测脚本

import requests
from bs4 import BeautifulSoup
import re

def detect_captcha_type(url):
    """Detect whether page uses text or image CAPTCHA."""
    response = requests.get(url, timeout=10)
    soup = BeautifulSoup(response.text, "html.parser")
    html = response.text

    result = {"text_captcha": False, "image_captcha": False, "provider": None}

    # Check for reCAPTCHA (image-based)
    if "google.com/recaptcha" in html or "g-recaptcha" in html:
        result["image_captcha"] = True
        result["provider"] = "reCAPTCHA"
        return result

    # Check for hCaptcha (image-based)
    if "hcaptcha.com" in html or "h-captcha" in html:
        result["image_captcha"] = True
        result["provider"] = "hCaptcha"
        return result

    # Check for text CAPTCHA patterns
    captcha_images = soup.find_all("img", attrs={
        "src": re.compile(r"captcha", re.I)
    })
    captcha_inputs = soup.find_all("input", attrs={
        "name": re.compile(r"captcha", re.I)
    })

    if captcha_images and captcha_inputs:
        # Image with text input = text CAPTCHA
        result["text_captcha"] = True
        result["provider"] = "custom text CAPTCHA"
        return result

    # Check for FunCaptcha (image-based rotation)
    if "funcaptcha" in html.lower() or "arkoselabs" in html.lower():
        result["image_captcha"] = True
        result["provider"] = "FunCaptcha"
        return result

    return result

captcha = detect_captcha_type("https://staging.example.com/qa-login")
print(captcha)

Node.js 检测脚本

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

async function detectCaptchaType(url) {
    const { data: html } = await axios.get(url, { timeout: 10000 });
    const $ = cheerio.load(html);

    const result = { textCaptcha: false, imageCaptcha: false, provider: null };

    // reCAPTCHA detection
    if (html.includes("google.com/recaptcha") || html.includes("g-recaptcha")) {
        result.imageCaptcha = true;
        result.provider = "reCAPTCHA";
        return result;
    }

    // hCaptcha detection
    if (html.includes("hcaptcha.com") || html.includes("h-captcha")) {
        result.imageCaptcha = true;
        result.provider = "hCaptcha";
        return result;
    }

    // Text CAPTCHA: image + input with "captcha" in name/class
    const captchaImgs = $("img[src*='captcha' i]").length;
    const captchaInputs = $("input[name*='captcha' i]").length;

    if (captchaImgs > 0 && captchaInputs > 0) {
        result.textCaptcha = true;
        result.provider = "custom text CAPTCHA";
        return result;
    }

    return result;
}

detectCaptchaType("https://staging.example.com/qa-login").then(console.log);

两段代码只做静态 HTML 匹配。页面若由前端框架渲染,骨架里可能没有验证码节点,需改用 Selenium 或 Playwright 取渲染后的 DOM。


用 CaptchaAI 识别文本验证码

文本验证码本质是一张图,走图像 OCR 接口即可:取图、base64 编码、提交 in.php,再轮询 res.php

import requests
import base64
import time

API_KEY = "YOUR_API_KEY"

# Get the CAPTCHA image
captcha_url = "https://example.com/captcha.png"
image_data = requests.get(captcha_url).content
b64 = base64.b64encode(image_data).decode()

# Submit to CaptchaAI
submit = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "base64",
    "body": b64,
    "json": 1,
})
task_id = submit.json()["request"]

# Poll for result
for _ in range(30):
    time.sleep(3)
    resp = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "get",
        "id": task_id,
        "json": 1,
    }).json()

    if resp.get("status") == 1:
        print(f"CAPTCHA text: {resp['request']}")
        break

CaptchaAI 的图像 OCR 支持 27,500 多种图片验证码类型,涵盖扭曲文本、数学算式和字符识别。调用方式与快速上手流程一致,method 换成 base64 即可。

图像验证码要按类型走对应求解器。CaptchaAI 正式支持 reCAPTCHA v2(含隐形与 Enterprise 变体)、reCAPTCHA v3、GeeTest v3、Cloudflare Turnstile 与 Challenge、图片/OCR、九宫格图片和 BLS,另有 CaptchaFox(测试版)、Friendly Captcha(测试版)、Lemin(测试版)。hCaptcha 与 FunCaptcha(Arkose Labs)不支持,GeeTest v4 尚未上线(官方口径为即将支持)。 检测脚本仍匹配这两者,是因为识别类型和识别结果是两件事。各类型提交参数不同,接入前按文档核对 method 与必填字段。


站在防护方:这两种还该不该用

如果你是给自己的站点选方案:

  • 留着文本验证码:需要零依赖、完全自托管,机器人流量也不大,例如内部后台登录页。
  • 换成图像验证码:持续遭遇自动化流量,表单背后是登录、支付等敏感操作。
  • 两种都不用:面向普通用户的表单更适合隐形方案——reCAPTCHA v3 和 Cloudflare Turnstile 在后台打分,用户无感知。

合规提醒:数据采集只抓你有权限抓的数据,遵守 robots 协议与 PIPL 等法规要求。


常见问题

国内站点为什么很少见到九宫格点红绿灯?

国内主要用 GeeTest(极验)、网易易盾、腾讯防水墙、阿里云验证码,形态以滑块和点选文字为主;reCAPTCHA 依赖 Google 域名下的脚本,国内访问不稳定。其中 CaptchaAI 支持 GeeTest v3。

文本验证码现在还拦得住机器人吗?

基本拦不住了。现代 OCR 对标准文本验证码识别准确率很高;扭曲到能压低机器识别率的程度,真人失败率也会上升,结果常是挡掉的真实用户比机器人还多。

识别一张图片验证码大概要多久?

图像 OCR 类任务通常几秒内返回,取决于图片复杂度和排队情况。按上面代码轮询即可:提交后隔几秒查一次 res.php,设好重试上限和超时。以上为参考值,建议在自有环境实测。

一个项目里同时有文本和图像验证码,要买两份套餐吗?

不需要。CaptchaAI 按并发线程计价,同一个 API Key 可提交不同类型的任务,套餐内不限次数,也不按类型加价。你只要估峰值并发,挑一档即可。


小结

文本验证码部署成本低,OCR 就能识别;图像验证码自动化难度高得多,代价是用户多花时间点图。写自动化先跑检测判准类型,文本类送 CaptchaAI 的图像 OCR,图像类按类型选求解器。做防护方趋势也很明确:能上隐形验证码,就别再让用户认字点图。

相关文章

该文章已禁用评论。