数学验证码考的是算数,不是认字:页面显示 "3 + 7 = ?",正确答案是 10,不是算式本身。普通 OCR 只读出算式原文,还得自己写代码再算一遍。CaptchaAI 的 calc 参数省掉这一步,接口直接把算式算完返回结果。下面用可运行的 Python 示例说明怎么接。
先判断要不要用 calc 参数
满足以下任意一条,直接加 calc=1:
- 只要最终数字,不关心算式原文。
- 不想自己维护一套算式解析逻辑。
- 算式偶尔是文字描述(比如
"three plus five")。
带括号、指数或多步运算的算式,calc 力不从心,见后文"复杂算式"一节。
calc 参数的两种取值
calc=0 是默认值,原样返回识别到的算式文字,例如 "3+7"。calc=1 直接算出结果返回,例如 "10"。
数学验证码识别基础用法:提交任务并轮询结果
import requests
import base64
import time
import os
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_math_captcha(image_b64):
"""Solve a math CAPTCHA — returns the computed result."""
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "base64",
"body": image_b64,
"calc": 1, # Compute the math
"numeric": 1, # Result will be a number
"json": 1,
}, timeout=30)
result = resp.json()
if result.get("status") != 1:
raise RuntimeError(result.get("request"))
task_id = result["request"]
time.sleep(8)
for _ in range(24):
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get",
"id": task_id, "json": 1,
}, timeout=15)
data = resp.json()
if data.get("status") == 1:
return data["request"]
if data["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(data["request"])
time.sleep(5)
raise TimeoutError("Solve timeout")
# Example: Image shows "3 + 7 = ?"
# With calc=0: Returns "3+7"
# With calc=1: Returns "10"
calc=1 建议和 numeric=1 一起提交,双保险防止误判。示例先等 8 秒再轮询,每 5 秒一次、最多 24 次,约 2 分钟超时,复杂算式可适当调大重试次数。
常见的算式格式一览
Format Example Result
─────────────────────────────────────────
Addition 3 + 7 = ? 10
Subtraction 15 - 8 = ? 7
Multiplication 4 × 6 = ? 24
Division 20 ÷ 5 = ? 4
Mixed 3 + 4 × 2 = ? 11
Text-based "three plus five" 8
calc 覆盖的运算范围:
- 加、减、乘、除四则运算
- 先乘除后加减的混合运算
- 文字型算式(比如
"three plus five")——识别难度更高,建议单独测试一批样本再上生产
复杂算式:搭配 textinstructions 参数
有些算式格式比较特殊,光靠 calc=1 未必能猜对怎么算,这时加一个 textinstructions 参数,用一句话告诉 CaptchaAI 该怎么处理这张图:
def solve_text_math_captcha(image_b64, instructions):
"""Solve a math CAPTCHA with custom instructions."""
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "base64",
"body": image_b64,
"calc": 1,
"textinstructions": instructions,
"json": 1,
}, timeout=30)
return resp.json()
# Example instructions:
# "Solve the math expression and enter the number"
# "What is the result of the equation shown?"
# "Enter the sum of the two numbers"
textinstructions非必填,只在默认识别不稳定时加,一次只描述一件事,识别更稳定。
处理异常与结果校验
返回值可能带空格、负数或小数,都要在校验函数里处理掉,别指望接口每次都干净返回。
# edge_cases.py
def validate_math_result(answer):
"""Validate and clean math CAPTCHA result."""
if not answer:
return None
# Remove spaces
answer = answer.strip()
# Handle negative results
if answer.startswith("-"):
try:
return str(int(answer))
except ValueError:
return answer
# Handle decimal results
try:
num = float(answer)
if num == int(num):
return str(int(num))
return str(num)
except ValueError:
return answer
def solve_math_with_fallback(image_b64):
"""Try calc=1, fall back to manual parsing if needed."""
# Try with calc
result = solve_math_captcha(image_b64)
# Validate result is actually a number
try:
float(result)
return result
except (ValueError, TypeError):
pass
# Fallback: solve without calc and compute locally
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "base64",
"body": image_b64,
"calc": 0, # Get the expression text
"json": 1,
}, timeout=30)
# ... poll for result ...
expression = "3+7" # Example OCR result
# Safely evaluate
return str(safe_eval(expression))
def safe_eval(expression):
"""Safely evaluate a simple math expression."""
# Only allow digits and basic operators
import re
cleaned = expression.replace("×", "*").replace("÷", "/").replace("=", "").replace("?", "")
cleaned = cleaned.strip()
if not re.match(r'^[\d\s+\-*/().]+$', cleaned):
raise ValueError(f"Unsafe expression: {expression}")
return eval(cleaned) # Safe because we validated the pattern
别默认相信返回值一定干净:validate_math_result 先处理空格、负数和小数;solve_math_with_fallback 更进一步,校验不通过就自动切回 calc=0,本地用 safe_eval 重新算,不会因一次识别失误就卡死整条流水线。
完整流程:截图 → 识别 → 自动填表
# full_flow.py
from selenium import webdriver
from selenium.webdriver.common.by import By
import base64
import os
def solve_math_captcha_on_page(driver, captcha_selector, input_selector, submit_selector):
"""Complete flow: capture math CAPTCHA, solve, enter answer."""
# Capture CAPTCHA image
captcha_el = driver.find_element(By.CSS_SELECTOR, captcha_selector)
image_b64 = captcha_el.screenshot_as_base64
# Solve with calc=1
answer = solve_math_captcha(image_b64)
print(f"Math answer: {answer}")
# Enter the computed result
input_el = driver.find_element(By.CSS_SELECTOR, input_selector)
input_el.clear()
input_el.send_keys(answer)
# Submit
driver.find_element(By.CSS_SELECTOR, submit_selector).click()
# Usage
driver = webdriver.Chrome()
driver.get("https://example.com/form")
solve_math_captcha_on_page(
driver,
captcha_selector="#captcha-image",
input_selector="#captcha-answer",
submit_selector="#submit-btn",
)
这段代码把前面几步串起来,接入时把三个 CSS 选择器换成你自己表单的元素即可:
- 截图——拿到验证码图片的 base64。
- 识别——调
solve_math_captcha,拿到计算结果。 - 填表——把结果写进输入框。
- 提交——点击提交按钮。
常见故障排查
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 返回算式文本而非得数 | 漏了 calc=1 |
检查参数,补上 calc=1 |
| 得数不对 | 运算符识别错误(× 看成 +) | 加 textinstructions 说明算式格式 |
| 整数算式返回小数 | 浮点精度问题 | 转整数:str(int(float(result))) |
报错 ERROR_CAPTCHA_UNSOLVABLE |
算式图片扭曲太严重 | 先预处理图片(提升对比度、去噪) |
国内开发环境的两个小提示
国内教务系统、政务平台、部分电商注册页也常见类似算术题,不只是海外站点才有。
| 场景 | 建议 |
|---|---|
pip install 网络慢 |
加国内镜像:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests |
| 首次接入 | 先在有权限访问的表单或 staging 环境跑通,再上生产 |
常见问题
calc 和 numeric 两个参数一起提交,谁说了算?
calc=1 算出数字;numeric=1 只是校验结果是纯数字。只传 numeric=1 不加 calc=1,接口仍只识别文字。
轮询时一直收到 CAPCHA_NOT_READY,要一直等吗?
正常状态,任务还在队列里。示例每 5 秒轮询一次、最多 24 次,约 2 分钟超时;不建议无限轮询,超时就判定失败并重试。
calc 能处理带括号、指数这类复杂算式吗?
不能,calc 只覆盖加减乘除。遇到括号、指数或多步表达式,把 calc 设为 0 取回算式文本,本地用 safe_eval 计算。
结果是负数,calc 返回的准确吗?
准确,"5 - 8 = ?" 会返回 "-3"。下游代码用正则或 int() 处理返回值时记得兼容负号。
怎么确认 calc 返回的确实是数字?
别默认相信返回值是数字,尤其图片模糊时。像上文 validate_math_result 一样先用 float() 校验,失败就回退到 calc=0 兜底。
相关阅读
自动完成数学验证码识别——从 CaptchaAI 开始接入。