先说结论:只看识别成功率,headless 和有头 Chrome 对 CaptchaAI 没区别;但脚本依赖 reCAPTCHA v3 分数时,选错模式会直接拉低分数。Headless 启动快、占用低,天生适合跑服务器,代价是验证码系统专门盯着它的检测信号。下面用实测数据说清楚怎么选。
三句话看懂:
- 识别成功率跟浏览器模式无关。
- 差异在 v3 分数和出现频率。
- 两头兼顾就上 Xvfb + 有头。
Headless 与有头 Chrome 怎么选:核心指标一览
| 对比项 | headless 模式 | 有头模式 |
|---|---|---|
| 速度 | 快(无渲染开销) | 较慢(要渲染 UI) |
| 内存占用 | ~100–200 MB | ~300–500 MB |
| 服务器部署 | 原生支持 | 需要虚拟显示 |
| 验证码检测 | 高 | 低 |
| reCAPTCHA v3 分数 | 0.1–0.3 | 0.7–0.9 |
| 调试难度 | 较高 | 较低 |
| 横向扩展 | 优秀 | 较差 |
一句话总结:追并发选 headless,追分数选有头,两头都要就上 Xvfb。
该怎么选:三种典型场景
什么时候用 headless
- 部署在服务器 / CI,没有显示器
- 要扩展到 50+ 并发会话
- 内存预算有限
- 验证码全部交给 CaptchaAI 处理(浏览器模式不影响识别结果)
什么时候用有头模式
- 需要肉眼调试验证码流程
- reCAPTCHA v3 分数很关键(有头模式的分数明显更高)
- 目标站点专门针对 headless 做了拦截
- 本来就跑在带显示器的机器上
什么时候用有头 + 虚拟显示
- 服务器上也需要接近有头模式的检测抗性
- headless 下 reCAPTCHA v3 分数一直偏低
- 预算能承受额外的内存开销(每个会话大约翻倍)
实际案例
某跨境电商团队在阿里云 ECS 上跑 headless 集群做 QA,v3 分数偏低的任务切到 Xvfb + 有头。
实测性能对比:headless / 有头 / 有头 + Xvfb
| 场景 | headless | 有头 | 有头 + Xvfb |
|---|---|---|---|
| 启动耗时 | ~1 秒 | ~2 秒 | ~2.5 秒 |
| 单标签页内存 | 100–200 MB | 300–500 MB | 300–500 MB |
| 页面加载(平均) | 1.5 秒 | 2.5 秒 | 2.5 秒 |
| reCAPTCHA v3 分数 | 0.1–0.3 | 0.7–0.9 | 0.5–0.8 |
| 最大并发数(8GB 内存) | 30–40 | 10–15 | 10–15 |
| 验证码识别成功率 | 相同(API 决定) | 相同(API 决定) | 相同(API 决定) |
关键结论: 浏览器模式不影响 CaptchaAI 的识别结果,只影响验证码出现的频率和 reCAPTCHA v3 的分数区间。
常见故障排查
| 问题 | 原因 | 处理方式 |
|---|---|---|
| headless 被识别 | navigator.webdriver 标志暴露 |
加标准配置补丁或做 CDP 层面的修补 |
| headless 下 v3 分数低 | 缺少渲染相关信号 | 切换到有头 + Xvfb |
| Xvfb 崩溃 | 显示编号冲突 | 加 --auto-servernum 参数 |
| 有头模式内存高 | GPU 进程占用 | 加 --disable-gpu 参数 |
| headless 截图空白 | viewport 设置错误 | 设置 --window-size=1920,1080 |
验证码怎么识别出 headless 浏览器
常见检测信号
// Tests that CAPTCHA systems run
// 1. WebDriver flag (biggest tell)
navigator.userAgent // true in headless, undefined in real browser
// 2. Chrome object completeness
window.chrome // Missing or incomplete in headless
// 3. Plugins
navigator.plugins.length // 0 in headless, 3+ in headed
// 4. WebGL renderer
// Headless: "SwiftShader Renderer"
// Headed: "ANGLE (NVIDIA GeForce GTX 1080...)"
// 5. User-Agent contains "Headless"
navigator.userAgent.includes("Headless") // Old Chrome versions
// 6. Screen dimensions
screen.width === 0 // Some headless configs
// 7. Notification permission
Notification.permission // "denied" in headless without override
实测检测结果对比
Signal Headed Headless New Headless (v112+)
─────────────────────────────────────────────────────────────
webdriver false true true
chrome object full partial improved
plugins 5 0 0
WebGL renderer ANGLE Swift Swift
screen.width 1920 800 800
UA "HeadlessChrome" no yes no (removed)
Chrome 的“新 headless”模式能躲过检测吗?(v112+)
Chrome 112 加入 --headless=new,和有头模式共用渲染代码:
from selenium import webdriver
# Old headless (more detectable)
options = webdriver.ChromeOptions()
options.add_argument("--headless") # Legacy mode
# New headless (less detectable)
options = webdriver.ChromeOptions()
options.add_argument("--headless=new") # Shares headed rendering
driver = webdriver.Chrome(options=options)
新模式确实堵上了一部分检测点,但 navigator.webdriver 依旧会暴露,插件列表也还是空的——只检查这两项的站点照样能把它识别出来。
headless 模式下用 CaptchaAI 识别验证码(Python 示例)
CaptchaAI 服务端识别验证码,浏览器模式不影响结果。完整流程:起 headless 会话、抓 sitekey、调 in.php / res.php 拿 token、写回页面提交表单:
import requests
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
API_KEY = "YOUR_API_KEY"
API_URL = "https://ocr.captchaai.com"
def create_headless_driver():
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
options.add_argument(
"--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
)
return webdriver.Chrome(options=options)
def solve_captcha(site_url, sitekey):
resp = requests.post(f"{API_URL}/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": site_url,
"json": 1,
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
resp = requests.get(f"{API_URL}/res.php", params={
"key": API_KEY, "action": "get",
"id": task_id, "json": 1,
})
data = resp.json()
if data["request"] != "CAPCHA_NOT_READY":
return data["request"]
raise TimeoutError("Solve timeout")
# Full headless workflow
driver = create_headless_driver()
try:
driver.get("https://example.com/form")
time.sleep(2)
sitekey = driver.execute_script(
"return document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')"
)
if sitekey:
token = solve_captcha(driver.current_url, sitekey)
driver.execute_script(f"""
document.querySelector('#g-recaptcha-response').value = '{token}';
""")
driver.find_element(By.CSS_SELECTOR, "form").submit()
finally:
driver.quit()
无头服务器怎么跑有头 Chrome:Xvfb 虚拟显示方案
用 Xvfb 建一块虚拟屏幕,就能在没显示器的服务器上跑“真正”的有头 Chrome。
Linux + Xvfb
# Install
sudo apt-get install xvfb
# Run with virtual display
xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" python script.py
Python + PyVirtualDisplay
from pyvirtualdisplay import Display
from selenium import webdriver
display = Display(visible=0, size=(1920, 1080))
display.start()
options = webdriver.ChromeOptions()
# No --headless flag = headed mode in virtual display
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(options=options)
# Now runs headed Chrome with real rendering, but no physical display
Docker + Xvfb
FROM python:3.12-slim
RUN apt-get update && apt-get install -y \
xvfb \
chromium \
chromium-driver \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . /app
WORKDIR /app
CMD ["xvfb-run", "--auto-servernum", "python", "main.py"]
Node.js 标准配置补丁:减少验证码出现频率
标准配置补丁能降低验证码出现频率:
const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");
puppeteer.use(StealthPlugin());
async function headlessStealth() {
const browser = await puppeteer.launch({
headless: "new",
args: [
"--no-sandbox",
"--window-size=1920,1080",
"--no-sandbox",
],
});
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
// Additional QA patches
await page.evaluateOnNewDocument(() => {
Object.defineProperty(navigator, "webdriver", {
get: () => undefined,
});
Object.defineProperty(navigator, "plugins", {
get: () => [1, 2, 3, 4, 5],
});
});
await page.goto("https://example.com/form");
// Detect and solve CAPTCHA with CaptchaAI
const sitekey = await page.evaluate(() =>
document.querySelector("[data-sitekey]")?.getAttribute("data-sitekey")
);
if (sitekey) {
// Call CaptchaAI API (see other guides for full implementation)
const token = await solveCaptchaAI(page.url(), sitekey);
await page.evaluate((t) => {
document.querySelector("#g-recaptcha-response").value = t;
}, token);
}
await browser.close();
}
验证码仍交给 CaptchaAI 处理。
常见问题
验证码检测的到底是“headless”本身,还是行为特征?
两者都看:navigator.webdriver、插件列表是浏览器信号,鼠标轨迹、停留时间是行为信号。
CaptchaAI 在 headless 模式下识别效果会打折扣吗?
不会,浏览器模式不影响识别结果,只影响验证码出现频率和 v3 分数。
只用 GeeTest v3 或 Turnstile,还需要在意 headless 检测吗?
需要但没那么敏感——这两种更看重滑动、点击信号,识别成功率不受影响。
标准配置补丁和 CaptchaAI,该选哪个?
不是二选一,补丁减少验证码出现次数,出现的仍交给 CaptchaAI 处理。
相关指南
给你的验证码工作流选对浏览器模式——获取 CaptchaAI API Key,headless 或有头模式都能稳定识别验证码。