Troubleshooting

常见网格图像验证码错误和修复

网格图像验证码(Grid Image CAPTCHA)识别失败,多半不是引擎问题,而是格式、坐标或超时没对齐。先看排查清单,再逐条处理。


3 秒自查:网格验证码报错排查清单

排查项 处理方式
图片格式? 只用 PNG 或 JPEG,Base64 编码正确
图片体积? 控制在 600 KB 以内
网格截全了? 连边框一起截,留几像素边距
图片够清晰? 不模糊、不等比例缩小
索引对齐? API 返回从 1 开始,转成从 0 开始
在 iframe 里? 先切换 iframe,再定位格子
已经过期? 截图后立刻提交

清单都过了还报错?直接跳到下面对应的错误码小节。


提交阶段的常见错误:图片格式与体积

ERROR_WRONG_FILE_EXTENSION

原因: 上传的文件不是有效的图片格式:

  1. 只用 PNG 或 JPEG 格式
  2. 确认 Base64 字符串编码正确
  3. 发送前去掉 data:image/...;base64, 前缀
# WRONG — includes data URI prefix
body = "data:image/png;base64,iVBORw0KGgo..."

# CORRECT — raw base64 only
body = "iVBORw0KGgo..."

ERROR_TOO_BIG_CAPTCHA_FILESIZE

原因: 图片超过了最大文件体积(通常 600 KB):

from PIL import Image
import io
import base64

# Resize if too large
img = Image.open("captcha.png")
if img.width > 600:
    ratio = 600 / img.width
    img = img.resize((600, int(img.height * ratio)), Image.LANCZOS)

buffer = io.BytesIO()
img.save(buffer, format="PNG")
b64 = base64.b64encode(buffer.getvalue()).decode()

ERROR_ZERO_CAPTCHA_FILESIZE

原因: 文件为空,或图片提取失败:

  1. 提取前先确认图片元素已经加载完成
  2. 检查 src 属性不是空的
  3. 给懒加载的图片留出等待时间
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Wait for image to load
WebDriverWait(driver, 10).until(
    lambda d: d.find_element(By.CSS_SELECTOR, ".captcha img").get_attribute("complete") == "true"
)

识别结果错误:为什么选错了格子

ERROR_CAPTCHA_UNSOLVABLE

原因: 图片太模糊、太扭曲,或图中物体本身难以辨认:

  1. 按原始分辨率截图,不要缩小
  2. 确认没有遮罩或水印挡住网格
  3. 换一张新验证码重试(有些挑战本身就模棱两可)

这两个错误常一起出现:先排除压缩导致的模糊,再检查截图范围是否完整。

选中了错误的格子

原因: 图片质量差,或只截取了部分区域:

  1. 截图要包含整个验证码元素,连边框一起截
  2. 不要裁得太紧,留出几像素的边距
  3. 保存截图后手动打开看一眼,确认截对了
# Take a proper element screenshot
captcha_el = driver.find_element(By.CSS_SELECTOR, "#captcha-container")
captcha_el.screenshot("debug_captcha.png")

# Open and check manually
from PIL import Image
Image.open("debug_captcha.png").show()

结果应用与点击错误

索引错位:差一错误

原因: API 返回的索引从 1 开始,数组下标却是从 0 开始,两边没对齐。

# API returns "1,3,5" (1-based)
solution = "1,3,5"
indices = [int(i) for i in solution.split(",")]

# DON'T: use directly as array index
# cells[1], cells[3], cells[5]  ← WRONG (off by one)

# DO: convert to 0-based
for idx in indices:
    cells[idx - 1].click()  # 1→0, 3→2, 5→4

点了格子,页面却没反应

原因: 点击目标不对 —— 可能被遮罩挡住、验证码在 iframe 里,或用了 shadow DOM:

# Check if captcha is in an iframe
iframes = driver.find_elements(By.TAG_NAME, "iframe")
for iframe in iframes:
    if "captcha" in iframe.get_attribute("src").lower():
        driver.switch_to.frame(iframe)
        break

# Now find and click cells
cells = driver.find_elements(By.CSS_SELECTOR, ".grid-cell")

动态网格——点完之后图块又变了

原因: reCAPTCHA 风格的动态网格会在点击后替换图块——改用 token 方式提交:

# Token method handles dynamic grids automatically
response = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": "SITE_KEY",
    "pageurl": "https://example.com",
    "json": 1
})

动态网格没必要死磕图像点击,切 token 方式最省事。


超时与轮询错误

结果还没返回,验证码先过期了

原因: 网格验证码通常 2~3 分钟就会过期:

  1. 截图后立刻提交,别攒着
  2. 如果识别耗时超过 60 秒,直接刷新重试

卡在 CAPCHA_NOT_READY,一直轮询不停

原因: 任务大概率静默失败了——给轮询设最大重试次数:

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

    if result.get("status") == 1:
        return result["request"]
    if result.get("request") not in ["CAPCHA_NOT_READY"]:
        break  # Actual error, stop polling

raise Exception("Grid captcha solve failed — refresh and retry")

国内环境下的额外排查建议

国内跑脚本时,Pillow、Selenium 装到一半超时也会间接触发上述错误,建议换国内镜像。不少国内后台、OA 系统仍用图片或网格验证码,排查思路通用。

pip install 卡住时换镜像,如 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pillow selenium


常见问题

PNG 和 JPEG,哪种格式识别更准?

PNG 无损,边界最清晰;JPEG 压缩率一高会糊边界,拉低识别率。

提交网格图片一定要带文字说明吗?

method=post 搭配 recaptcha=1 不需要;method=bls 必须带,否则报错。

一直卡在 CAPCHA_NOT_READY,是我的任务丢了吗?

大概率静默失败,不是账号或图片问题。给轮询设最大重试次数,超过就直接重新提交。

格子明明选对了,点击却没反应,怎么排查?

先确认验证码是不是嵌在 iframe 里——大多数点击失效都是脚本操作了外层 DOM。

网格验证码识别失败,会浪费我的线程配额吗?

不会。CaptchaAI 按并发线程计费,一个线程处理完一个任务(无论成败)就能接下一个,BASIC 套餐($15 / 月,5 个线程)同样适用。


相关指南

该文章已禁用评论。