ARTICLE · 1284922
月底录发票别再手敲:两条路线批量进Excel
推广:aiwebcool.com - 最硬核的 AI 工具指南网站,挑工具前先来这查一眼
实战SOP月底录发票别再手敲:两条路线批量进Excel
发布于 2026年10月30日 · 7 分钟阅读
每到月底,财务和行政的桌角总会准时出现一摞报销发票:专票、普票、电子发票打印件,有的还压着红章。逐张打开、逐个字段敲进 Excel,一晚上过去,价税合计栏还差三十行。这件事完全可以交给脚本:把整个文件夹的发票批量喂给 OCR,跑完直接得到一张汇总表。本文给两条可复现的完整路线,从装依赖到导出 xlsx 一步不落。
先把分工说清楚:站内那篇 DeepSeek-OCR 部署教程讲的是「把 OCR 模型跑起来」,属于工具导向;本篇讲的是「把一摞发票变成一张 Excel」,属于任务导向,部署细节不再重复展开。
两条路线怎么选
主流做法分两条:云 API 路线和本地开源路线。一张表看清差异:
一句话结论:图省事走 A,数据敏感或票量大走 B;也可以先拿 A 的免费额度把流程跑通,再迁到 B。
动手前建议先把文件归拢:新建一个「发票」文件夹,电子发票 PDF 原件直接另存进去,纸票用手机平拍(镜头贴近平面、避开灯光直射),命名尽量带上开票方和日期,后面排查漏识别时能对上号。文件夹结构没有强制要求,本文脚本示例用的就是同目录「发票」文件夹加汇总表输出的布局,照搬即可。
路线 A:云 API 六步走
以百度智能云「增值税发票识别」为例。官方文档给出的接口是 POST https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice,入参 image、url、pdf_file、ofd_file 四选一,优先级依次降低。也就是说 PDF 发票可以直接传 pdf_file,不必先转图片;base64 编码并 urlencode 后不超过 8M,图片最短边不小于 15px、最长边不超过 4096px;多页 PDF 用 pdf_file_num 指定页码,不传默认识别第 1 页。
第一步:装依赖。 一条命令装齐四个库:
pip install pymupdf pandas openpyxl requests一个许可提醒:PyMuPDF 采用 AGPL/商业双许可——个人项目与开源(AGPL 兼容)场景免费,闭源商用需向厂商购买商业授权;发票场景若在公司内部工具里用,先确认许可边界,介意的话可换 pdf2image(GPL 组件依赖,同样要核对)或直接走云 API 的 pdf_file 直传,绕开本地渲染。
第二步:开通服务、管好密钥。 在百度智能云控制台创建 OCR 应用,拿到 API Key 和 Secret Key。密钥不要写进代码,用环境变量承载——官方 SDK 指南原话就是「不要把 AccessKey 写进项目代码」。
第三步:换 access_token。 调用识别接口前,先拿两个 Key 换 token,之后把 token 带在 URL 参数里请求:
import os, requests def get_token(): # 密钥放环境变量,不硬编码 resp = requests.get( "https://aip.baidubce.com/oauth/2.0/token", params={ "grant_type": "client_credentials", "client_id": os.environ["BAIDU_OCR_API_KEY"], "client_secret": os.environ["BAIDU_OCR_SECRET_KEY"], }, ) return resp.json()["access_token"]第四步:确认票种与参数。 接口默认 type=normal,覆盖增值税普票、专票、电子发票(含全电票)和区块链发票;卷票传 type=roll;开 seal_tag=true 会附带印章判断结果。注意票种边界:定额发票、通用机打发票、医疗发票不在增值税发票识别范围内,硬传会失败或字段缺失,这类票要换百度智能云的智能财务票据识别接口 multiple_invoice,一次能拆 13 种常见票据的混贴图。
第五步:收集文件、跑批量脚本。 用标准库 pathlib 或 glob 递归通配文件夹里的 PDF、JPG、PNG,零第三方依赖。PDF 用 PyMuPDF 渲染成 300dpi 的 PNG——PDF 默认按 72dpi 渲染,150dpi 够网页预览但不够 OCR 认小字,OCR 输入建议 300dpi,且 PNG 优于 JPG(避免压缩伪影干扰笔画)。逐张调接口,把 words_result 字段装进字典,失败的单记状态、不中断整批:
import os, time, base64, glob import fitz # PyMuPDF import pandas as pd import requests VAT_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice" def pdf_to_png(pdf_path, dpi=300): # PDF 渲染成 300dpi PNG,OCR 认小字更稳 doc = fitz.open(pdf_path) pix = doc[0].get_pixmap(matrix=fitz.Matrix(dpi / 72, dpi / 72)) return pix.tobytes("png") def recognize(token, img_bytes): resp = requests.post( VAT_URL, params={"access_token": token}, headers={"Content-Type": "application/x-www-form-urlencoded"}, data={"image": base64.b64encode(img_bytes).decode()}, ) return resp.json() def main(): token = get_token() rows = [] files = glob.glob("发票/*.pdf") + glob.glob("发票/*.jpg") + glob.glob("发票/*.png") for path in files: row = {"文件名": os.path.basename(path), "识别状态": "成功"} try: if path.lower().endswith(".pdf"): img = pdf_to_png(path) else: img = open(path, "rb").read() w = recognize(token, img).get("words_result", {}) row.update({ "发票号码": w.get("InvoiceNum", ""), "开票日期": w.get("InvoiceDate", ""), "销售方税号": w.get("SellerRegisterNum", ""), "合计金额": w.get("TotalAmount", ""), "合计税额": w.get("TotalTax", ""), "价税合计": w.get("AmountInFiguers", ""), }) except Exception as e: row["识别状态"] = f"失败:{e}" rows.append(row) time.sleep(0.6) # 免费态 2 QPS,串行节流 pd.DataFrame(rows).to_excel("发票汇总.xlsx", index=False) if __name__ == "__main__": main()顺带一提,脚本里统一先转 PNG 是为了让输入可控、便于本地留档复查;如果你追求最少步骤,接口本身支持 pdf_file 直传,跳过转图那步也能跑。
第六步:额度与限速要心里有数。 按百度智能云官方免费测试资源页(页面更新时间 2026-10-22,本文 10-30 核对):增值税发票识别个人认证 1,000 次/月、企业认证 2,000 次/月,额度按月发放,当月没用完不结转;官方原文还写明「成功调用与失败调用均消耗免费测试资源」——传一张废图照样扣次,别拿模糊测试图刷量。QPS 以官方 QA 口径为准:未开通付费 2 QPS,开通付费后提升至 10 QPS;社区流传的 5 QPS、3 QPS 说法与官方口径不一致,本文不采。2 QPS 意味着脚本必须串行加 time.sleep 节流,或对限流错误做指数退避重试,上面脚本的 sleep(0.6) 就是干这个的。
其他云厂商可作对照:腾讯云混贴票据识别接口单图支持 14 种标准报销发票混贴,默认请求频率 5 次/秒;阿里云 RecognizeInvoice 支持增值税专票、普票、电子发票,格式覆盖最广(含 OFD、TIFF),官方自述总体识别准确率可达 98%——注意这是厂商自报口径。腾讯云免费额度各处说法不一,动手前以控制台资源包列表实际显示为准。
路线 B:本地 PaddleOCR
选它的理由:PaddleOCR 是目前 GitHub 上关注度最高的开源 OCR 项目之一(截至 2026-10-30 实测 91,929 星),Apache-2.0 许可。最新 release v3.7.0 发布了 PP-OCRv6 系列,分 tiny、small、medium 三档,CPU 就能跑——官方 release 说明给了 OpenVINO CPU 推理加速 5.2 倍的实证,发票批量场景用 CPU 完全可行,只是吞吐低于 GPU;不上显卡就没有显存压力。
pip install paddlepaddle paddleocr环境注意:仓库提交记录里提到 PaddlePaddle 3.3.0 的 CPU 原生推理对 paddleocr 模型存在 bug,官方曾给出版本回退建议。装环境时把 PaddlePaddle 版本锁住是常见做法,遇到推理异常先查版本兼容,别急着怀疑代码。
关键认知,也是本文最想帮你避开的坑:开源版 PaddleOCR 没有增值税发票专用模型。 正确用法是 PP-OCRv6 做通用文字检测识别,拿到一串文本块之后自己写正则规则映射字段。这和云 API 直接返回 InvoiceNum 命名字段的工程量差异,正是两条路线选型的核心论据。需要表格或版面还原时,v3.6.0 起的 PaddleOCR-VL 配合 PP-StructureV3 管道支持表格识别与印章识别开关,可以叠加使用。
import re, glob import pandas as pd from paddleocr import PaddleOCR ocr = PaddleOCR(ocr_version="PP-OCRv6", device="cpu") # CPU 即可跑 def extract_fields(texts): # 从文本块里按规则捞字段,开源路线的核心工作量在这里 row = {} for t in texts: if re.fullmatch(r"\d{8}", t): # 8 位发票号码 row["发票号码"] = t m = re.search(r"(\d{4}年\d{1,2}月\d{1,2}日)", t) if m: row["开票日期"] = m.group(1) m = re.search(r"(?:价税合计|合\s*计).*?([\d,]+\.\d{2})", t) if m: row.setdefault("价税合计", m.group(1)) return row rows = [] for path in glob.glob("发票/*.png") + glob.glob("发票/*.jpg"): result = ocr.predict(path) texts = result[0]["rec_texts"] # 通用文本块列表 rows.append({"文件名": path, **extract_fields(texts)}) pd.DataFrame(rows).to_excel("发票汇总_本地.xlsx", index=False)示例正则只覆盖三类最典型字段。真实票面远比示例复杂:全电票版式、卷票、带折痕的扫描件都会让规则漏抓,所以本地路线的产出务必保留一列人工复核状态。
字段映射与 Excel 导出
云 API 返回的是英文字段名,落表前要做一次映射。百度智能云官方文档里发票识别的关键字段对照如下:
商品明细数组里的 CommodityName、CommodityPrice 等字段可按需展开成子表,这里不铺开。导出环节用 pandas 出数、openpyxl 做样式:pandas 的 to_excel 写 .xlsx 底层用的就是 openpyxl 引擎;当前 pandas 稳定版 3.0.6(2026-09-18 发布)要求 Python 3.11 以上。给汇总表加一点办公体面:
from openpyxl import load_workbook from openpyxl.styles import Font wb = load_workbook("发票汇总.xlsx") ws = wb.active for cell in ws[1]: cell.font = Font(bold=True) # 表头加粗 ws.freeze_panes = "A2" # 冻结首行 for col in "FGH": # 金额三列套千分位 for cell in ws[col][1:]: cell.number_format = "#,##0.00" wb.save("发票汇总.xlsx")两个库的分工口诀:按「表格」思考用 pandas,按「单元格和样式」思考用 openpyxl。注意 openpyxl 不计算公式——如果表里写了公式,用 load_workbook(data_only=True) 读结果前,须先在 Excel 或 LibreOffice 里重算保存过。
大模型路线:作补充,不当主力
GLM-OCR(智谱开源,0.9B 参数)支持 text、formula、table、custom 四种模式,custom 模式用自定义 JSON schema 提示词做结构化抽取,社区有开发者用它对收据抽出发票号、日期、明细与合计的实测示例。但口径要说全:这是官方能力宣称加第三方通用实测,目前没有发票专项公开基准,实测者的结论也是「结构化抽取靠 prompt 明确约束后稳定性才大幅提升」。0.9B 参数对显存要求很低,票量不大、想用一行 prompt 代替一套正则时可以试;要稳定产线,前两条路线更可靠。资源清单见站内 GLM-OCR 篇(文末延伸阅读)。
常见报错与对策
识别失败和识别不准要分开排查:前者是接口报错或返回空,多为图片质量问题;后者是有结果但字段错位,多为版式与语义问题。排查顺序四步走:图片质量、版式与语言、引擎参数、业务兜底。
采集端的高频原因:覆膜票面灯光直射反光过曝、倾斜拍摄致字段畸变、折痕污渍褪色、红色发票章压住税号或金额栏、截图滤镜过度压缩丢细节。对策是柔光平拍、抚平折痕、印章遮挡时微调角度、优先用电子发票 PDF 原件而非翻拍截图。量化看有多伤:百度智能云一篇技术文的实验口径称 15 度倾斜使字符识别准确率下降 23%,另有案例印章覆盖导致 35% 的金额字段识别错误——注意这是该文实验与案例数据,不是行业通识。
接口侧可对照官方错误码表(以腾讯云文档为例,各家逻辑相似):ImageBlur 图片模糊就重拍或预处理;ImageDecodeFailed 解码失败就核对文件确为 PNG/JPG/PDF 且未损坏;文件超限就压缩或拆分。票种不匹配(定额、机打、医疗发票硬传增值税接口)就换混贴票据接口。
大模型路线有三类典型错误也值得知道(腾讯云官方公众号口径):字段串行(购销方名称与税号错位)、金额串行(不含税金额、税额、价税合计读串)、明细截断(多行明细只出前几行);专业 OCR 按字段坐标返回,不发生串行问题。
合规边界,一句话说清
发票含税号、购销方名称等经营信息,走云 API 前确认服务商数据协议(百度智能云协议明确用户业务数据归用户所有);验真伪只认国家税务总局全国增值税发票查验平台——每票每天最多查验 5 次、可查最近 5 年内开具的发票、当日开具当日可查验;AI 审查结果作辅助,不替代专业意见。
AI 声明:本文由 AI 辅助生成,经人工审核编辑。文中涉及第三方模型与服务,请以官方说明为准。互动:百度云 API 免费额度按月发(个人 1000 次/月),PaddleOCR 本地 CPU 就能跑。注意坑:开源版没有发票专用模型,字段要自己写正则映射。附完整可跑脚本。
- AI 甜点 · 每天一块 AI 资讯甜点 -















































































