在自动化测试、数据采集或合法脚本请求场景中,常常需要绕过算术验证码以获取授权令牌。本文基于 Node.js 与 Tesseract.js 7.0.0 实现了一个验证码识别后端服务,专门识别含算术表达式的验证码并返回计算结果。项目采用 Express 5.2.1 作为 Web 框架,body-parser 2.2.2 解析请求体,Jimp 1.6.0 预留图像预处理能力。
项目结构如下:- captcha-reader/
- ├── src/
- │ ├── routes/
- │ │ └── captcha.js # 验证码识别路由
- │ ├── services/
- │ │ └── captchaService.js # OCR识别与表达式计算核心服务
- │ ├── utils/
- │ │ └── imageUtils.js # 图像预处理工具(预留)
- │ └── app.js # 应用入口
- ├── package.json
- ├── test-captcha-api.js # 测试脚本
- └── test-captcha-data.json # 测试用例数据
复制代码
核心流程:接收 base64 编码图片 → 解码为缓冲区 → 预留预处理(灰度、二值化、缩放) → 使用 Tesseract.js 识别文字 → 提取算术表达式 → 计算并返回结果。
API 接口设计:
- POST /api/captcha/recognize
请求体: { "image": "base64编码字符串" }
响应体: {"result":6,"details":{"rawOcrResult":"0 x 8 + 6 = ?","cleanedText":"0x8+6","expression":"0*8+6","calculation":"0*8+6 = 0+6 = 6"}}
- GET /health
返回服务状态 {"status":"ok","message":"Captcha reader service is running"}
技术实现细节:
captchaService.js 核心识别逻辑:- exports.recognizeCaptcha = async (base64Image) => {
- try {
- const imageBuffer = await decodeBase64Image(base64Image);
- const processedImage = await preprocessImage(imageBuffer);
- const worker = await createWorker('eng', 1, {
- logger: m => console.log(' Tesseract:', m)
- });
- try {
- await worker.setParameters({
- tessedit_char_whitelist: '0123456789+-*/x=?',
- tessedit_pageseg_mode: 7, // 单行文本模式
- preserve_interword_spaces: 0,
- tessedit_ocr_engine_mode: 1, // LSTM 引擎
- load_system_dawg: 0,
- load_freq_dawg: 0
- });
- const { data: { text } } = await worker.recognize(processedImage);
- const expression = extractAlternativeExpression(text);
- const calculationDetails = { steps: [] };
- const result = calculateExpression(expression, calculationDetails);
- return {
- result,
- details: {
- rawOcrResult: text,
- cleanedText: text.trim().replace(/\s+/g, ''),
- expression,
- calculation: calculationDetails.steps.join(' = ')
- }
- };
- } finally {
- await worker.terminate();
- }
- } catch (error) {
- throw new Error('Failed to recognize captcha: ' + error.message);
- }
- };
复制代码
表达式提取采用了多级回退策略:直接匹配数字和运算符,处理常见格式问题(将“x”替换为“*”),控制长度避免错误,当主策略失败时尝试备用方法。计算功能支持加减乘除,按运算符优先级执行。
使用方式:- npm install
- npm start
- # 服务默认运行于 http://localhost:3000
复制代码
测试时,在 test-captcha-data.json 中添加测试用例:- {
- "test_cases": [
- {
- "id": 1,
- "name": "Test Case 1",
- "description": "Simple addition",
- "image": "base64字符串或图片标识",
- "expected_result": 6
- }
- ]
- }
复制代码 然后执行 node test-captcha-api.js。
将本服务集成到其他项目示例(使用 fetch):- async function recognizeCaptcha(imageBase64) {
- const response = await fetch('http://localhost:3000/api/captcha/recognize', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ image: imageBase64 })
- });
- const data = await response.json();
- return data.result;
- }
复制代码
优化方向:
- 图片预处理(建议使用 Jimp 实现灰度、自动二值化、缩放等):- async function preprocessImage(imageBuffer) {
- const image = await Jimp.read(imageBuffer);
- return image
- .greyscale()
- .threshold({ auto: true })
- .resize(200, Jimp.AUTO)
- .quality(100)
- .getBufferAsync(Jimp.MIME_PNG);
- }
复制代码 - 性能:复用 Tesseract worker,相同图片结果缓存,使用队列管理并发请求。
- 准确性提升:训练自定义 OCR 模型、模板匹配、多引擎融合。
实际测试数据示例:- {
- "result": 6,
- "details": {
- "rawOcrResult": "0x8+6=7?\n",
- "cleanedText": "0x8+6=7?",
- "expression": "0*8+6",
- "calculation": "0*8+6 = 0*8=0 = 0+6=6 = 6"
- }
- }
复制代码 识别成功率:清晰验证码 95%+(<2s),模糊验证码 80%+(<3s),复杂验证码 70%+(<4s)。
该服务适合自动化测试、合法数据采集和自动登录等场景。代码仓库见 https://github.com/JHJ1848/my-tools-common-captcha-reader.git。注意:仅用于学习和合法用途,遵守相关法律法规。 |