跳到主内容

PaddleOCR表格识别导出Excel实战:卡脖子的不是识别率,是这行方法名

先给结论:PaddleOCR 做表格识别再导出 Excel,走的是 PP-StructureV3 这条文档解析流水线,不是通用 OCR 那条线。表格部分识别完拿到的是一段 HTML 字符串,落盘成 xlsx 用官方的 save_to_xlsx()。我头一回做的时候照着网上的教程写 save_to_excel(),AttributeError 报了小半天,翻官方手册才确认压根没这个方法名。

下面是我跑通的完整路径,版本号与参数以官方最新说明为准。

准备:环境与前置条件

装之前先想清楚一件事:你是只要文字识别,还是要整表的结构。通用 OCR 只给你一堆带坐标的文本行,谁跟谁同行同列得你自己算;PP-StructureV3 才是做版面分析 + 表格结构还原的那一层。

官方文档给出的分层大致是这样(具体版本要求以官方安装页为准):

  • 底层飞桨框架:3.0 及以上即可,官方推荐较新的 3.2.0;
  • Python:基础包 pip install paddleocr 支持 3.8~3.13,但带文档解析能力的 paddleocr[doc-parser] 依赖要求 Python 3.9 起步;
  • 硬件:CPU 能跑,就是慢,批量走 GPU 才现实。
# 只要基础 OCR
pip install paddleocr

# 要跑 PP-StructureV3(表格识别在这里面)
pip install "paddleocr[doc-parser]"

源码在 GitHub · PaddlePaddle/PaddleOCR,国内拉不动可走 Gitee 镜像(官方提示有 3~5 天同步延时)。显存吃紧就导出配置文件关掉用不上的子模块。

步骤一:先判断这张表到底该不该走 OCR

这一步很多人跳过,然后抱怨识别率不行。我在站内另一篇里写过一句直白的提醒:内网页面表格导出Excel实战里那句「别一上来就想着用OCR去识别网页截图」,放到表格场景同样成立。能拿到结构化源头,就别绕道去识别图片。

我的判断顺序是:

  • 网页上的表 —— 直接解析 DOM,截图是最后一步;
  • PDF —— 先用 PyMuPDF 之类试能不能直接取到文字层,取得到就不用 OCR;
  • 扫描件、手机拍照、没有文字层的图片 PDF —— 这才轮到 OCR 上场。

顺序搞反了,后面所有调参都是在给错误决策擦屁股。

步骤二:命令行先跑通,把 HTML 攥在手里

别急着写脚本。先一行命令确认环境没问题:

paddleocr pp_structurev3 -i ./table.png

拍照歪的、纸面卷曲的,把预处理开关打开再跑一遍:

paddleocr pp_structurev3 -i ./table.png --use_doc_orientation_classify True
paddleocr pp_structurev3 -i ./table.png --use_doc_unwarping True

确认能出结果了,再落到 Python:

from paddleocr import PPStructureV3

pipeline = PPStructureV3()
output = pipeline.predict("./table.png")

for res in output:
    res.print()
    res.save_to_html("./out")

还有个默认值容易忽略:use_table_recognition、use_seal_recognition、use_formula_recognition 默认全是 True。只要表格就关掉另外两个,能快一截。

结果对象里跟表格有关的字段长这样,官方手册是这么定义的:

  • table_res_list:表格识别结果列表;
  • pred_html:这一段就是表格的 HTML 字符串,也是后面转 Excel 的真正原料;
  • cell_box_list:单元格框坐标;
  • table_ocr_pred.rec_texts / rec_scores:每个单元格的文本与置信度。

拿到 pred_html 之后,你就有两条路可走:让官方方法帮你落盘,或者自己接 pandas 处理。

步骤三:从 HTML 到 Excel,方法名别写错

直接落盘就一行:

for res in output:
    res.save_to_xlsx("./out")   # 表格 → xlsx
    res.save_to_html("./out")   # 表格 → html,留着做人工核对

官方给的结果对象方法是这几个:print()、save_to_json()、save_to_img()、save_to_markdown()、save_to_html()、save_to_xlsx()。没有 save_to_excel()。网上不少二手教程写的还是早期 PPStructure 那套 save_structure_res,或者更旧的 PPStructure(table=True) 写法,那是 2.x 时代的接口,3.x 已经换了类名和调用方式,别混着抄。

想自己控制表头、合并单元格、数字格式,就别用落盘方法,自己接管 HTML:

import pandas as pd

html = res.json["res"]["table_res_list"][0]["pred_html"]
dfs = pd.read_html(html)
dfs[0].to_excel("table.xlsx", index=False)

字段名与层级请以本地 res.json 实际结构为准,不同小版本挪过位置。跑不通就先 res.save_to_json("./out"),对着 JSON 找路径比猜快。

两种长表格的坑,我分别踩过:

一是超长截图。之前在 长图表格分割OCR识别工具里处理过一张 12000 像素高的长表格,直接整图喂进去,表格结构模型会把长边压到固定长度再推理,字都糊成一团,结构还原自然崩。后来改成按行切图、逐段识别再拼,效果反而稳。

二是合并单元格和多层表头。这类表社区里反馈的失败率一直偏高,常见表现是 rowspan/colspan 偏大偏小、单元格错位。两条实用的土办法:复杂表头的图片宽度尽量留在 2000 像素以上,分辨率不够时模型连字符都认不全,更别说判结构;置信度低于阈值的单元格单独标黄,让人快速扫一遍再定稿。字段级的高精度场景,我在 发票识别导出Excel那篇里走的是另一条路——只抽关键字段而不是整表还原,取舍要看业务。

结果校验:我怎么判断这一版能不能上线

识别完不等于能用。我固定查三样:

  1. 行数、列数对不对得上,尤其是被识别成两个独立子表的跨页表;
  2. 金额、日期这类数字抽样核对,OCR 最容易把 0 和 O、1 和 l 搞混;
  3. 合并单元格有没有被拆散,表头层级丢没丢。

批量跑的话,第一件事不是堆并发,是加缓存。同一张图重复识别纯属浪费,我在 桌面端 AI 分类工具那篇里就把结果缓到本地库,重复文件直接命中,响应时间从几秒级压到毫秒级。OCR 批量任务是一个道理,缓存命中率上去了,比换显卡省钱。

最后一句必须说在前面:只处理自己有权处理的材料。批量采集、识别他人平台数据之前先确认授权,遵守平台规则与法律法规。

常见问题

PaddleOCR 表格识别导出的 Excel 列错位怎么办?

先看源头。多层表头、合并单元格、无边框表格是最容易错位的三类。优先提高输入分辨率(复杂表头建议宽度 2000 像素以上),再检查是不是被拆成了多个子表。如果错在结构模型本身,可以把 HTML 拿出来人工或用规则修正后再落 xlsx。

save_to_excel 报 AttributeError 是什么原因?

方法名不对。3.x 的结果是 save_to_xlsx(),不是 save_to_excel()。从 2.x 教程看来的 PPStructure + save_structure_res 是旧接口,按 3.x 写法改。

只想导出表格,怎么让 PaddleOCR 跑快一点?

把用不上的子流水线关掉:use_seal_recognition、use_formula_recognition 默认是 True,只做表格时可以关。参数可以传进 PPStructureV3(),也可以在执行 export_paddlex_config_to_yaml() 导出的 YAML 里改,再用 paddlex_config 载入。

扫描件拍歪了识别很差,有补救吗?

有。命令行加 --use_doc_orientation_classify True 做方向矫正,--use_doc_unwarping True 做弯曲拉平,Python 侧是同名参数。这一步属于文档预处理,比换模型见效快。

能不能直接吃 PDF?

可以,PP-StructureV3 支持 PDF 输入,多页会逐页处理。但 PDF 如果有文字层,先用 PyMuPDF 之类的库直接取表格,准确率和速度都远好于 OCR 路径。OCR 只用在没有文字层的扫描版 PDF 上。

相关阅读

分享到:

本文链接:https://www.biyeyuanma.cn/post/263.html

服务热线

加我微信

加我微信