最近在做财务报销相关的需求,需要从大量电子发票 PDF 中提取发票号码、购买方、销售方、金额等信息。手动复制粘贴效率极低,于是研究了一下能不能纯前端实现自动识别。
折腾了几天,最终用 PDF.js + jsQR + Tesseract.js 实现了一个完全在浏览器端运行的发票批量识别工具,不需要后端,不上传文件,隐私安全。本文记录一下核心实现思路。
技术选型
| 功能 | 库 | 说明 |
|---|---|---|
| PDF 解析 | pdf.js | Mozilla 出品,浏览器端解析 PDF |
| 二维码识别 | jsQR | 纯 JS 二维码解码 |
| 图片 OCR | Tesseract.js | Google Tesseract 的 WebAssembly 版本 |
核心流程
1. PDF 文字层提取
电子发票 PDF 本身带有文字层,pdf.js 可以直接提取,不需要 OCR,准确率高:
async function extractPdfText(pdf) {
let fullText = '';
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const textContent = await page.getTextContent();
// items.str 就是每个文字块的内容
const pageText = textContent.items.map(item => item.str).join(' ');
fullText += pageText + '\n';
}
return fullText;
}
2. 扫描发票二维码
把 PDF 页面渲染到离屏 canvas,再用 jsQR 扫描像素数据:
注意 scale 建议设 2.0 以上,分辨率太低二维码识别率会下降。
3. 解析二维码内容
增值税发票二维码格式是逗号分隔的字符串:
字段顺序:版本, 类型码, 发票代码, 发票号码, 金额, 日期, 校验码
踩坑:不同版本发票二维码字段顺序不同,新版电子发票 parts[4] 是金额,parts[5] 才是日期,不要搞反。
4. 从 PDF 文本中提取结构化字段
这是最麻烦的部分。不同发票 PDF 的文本提取顺序差异很大:
- 新版电子发票:标签和值分离,"名称:"标签在前半段,公司名在后半段
- 旧版专票:标签值紧邻,名称: XXX科技有限公司
- 部分发票:销售方在购买方前面出现(布局不同)
针对这些差异,我的处理策略:
税号同理,通过标签位置判断哪个是购买方哪个是销售方:
5. 图片发票走 OCR
图片发票没有文字层,用 Tesseract.js 识别:
OCR 识别出来的文本每个字之间有空格,所以正则要先 text.replace(/\s+/g, '') 去掉所有空白再匹配。
批量处理
核心是维护一个文件队列,逐一处理:
效果
实测下来,新版电子发票 PDF 识别准确率很高,发票号码、金额、购买方/销售方基本都能正确提取。图片识别因为 OCR 精度问题,税号偶尔会有字符识别错误。
识别结果支持导出 CSV,带 BOM 头,Excel 直接打开中文不乱码:
落地时最有用的部分
整个方案完全在浏览器端运行,核心依赖:
- pdf.js 解析 PDF 文字层和渲染页面
- jsQR 扫描二维码
- Tesseract.js 处理图片 OCR
最麻烦的是不同发票格式的兼容,需要针对各种布局写不同的正则策略。如果你也有类似需求,可以参考这个思路,或者直接用我做好的在线工具试试效果:。
如有问题欢迎评论区交流。