Python 办公自动化 · 第 3 篇30 行 Python,把 PDF 里的表格一键导回 Excel,不用手工抄、文件不出本机作者 · 卓芃智序本篇你将 get 到① 先认命:PDF 里没有"表格",只有画上去的线
② 选对库:为什么是 pdfplumber
③ 单页先跑通:extract_tables() 入门
内容摘要PDF 里的表格想重新算、重新汇总,手工抄又慢又错。本文讲清一个事实:PDF 里根本没有表格,只有画上去的线和字,倒回 Excel 本质是重新识别单元格。给出纯 Python 方案(pdfplumber + openpyxl)、一份可复用批量脚本,外加 5 个避坑实录。
1.先认命:PDF 里没有"表格",只有画上去的线Word、Excel 里的表格是结构化对象——程序知道哪格是哪格、行高列宽是多少。但 PDF 不一样:它是固定版式格式,表格在 PDF 里就是一些线段 + 一些按坐标排好的文字。重点:所谓"PDF 倒回 Excel",不是把表格"导出",而是重新做一遍表格识别——找出哪里是单元格边界、哪些字属于同一格、再按行列拼回去。这一步做不好,后面全歪。所以别指望有个库能"原样还原"。我们能做的,是用提取工具尽量把单元格推断对,剩下的靠参数和清洗兜底。面对带表格的文本型 PDF(注意:不是扫描件),常见三个选手:pdfplumber纯 Python,pip install 即用 | 大多数文本型 PDF | 依赖最少、上手最快,首选camelot要 Ghostscript + 复杂依赖 | 规则网格表、精度要求高 | 精度好但环境麻烦tabula-py依赖 Java + tabula jar | 学术 / 报表类 PDF | 多一层 Java 依赖正确:正确认知:纯文本 PDF 优先 pdfplumber,依赖最少、上手最快;camelot / tabula 留给那种线条特别规整、pdfplumber 抓不准的硬骨头。pip install pdfplumber openpyxl
openpyxl 用来把提取到的二维数据写进 .xlsx,也是纯 Python、零外部依赖。3.单页先跑通:extract_tables() 入门拿一份最简单的单页表格 PDF 试水。pdfplumber 的思路是:先打开 PDF、取某一页、再调用 extract_tables(),它返回一个"表格列表",每个表格是"行列表",每行是"单元格列表"。import pdfplumber
with pdfplumber.open("demo.pdf") as pdf:
page = pdf.pages[0]
tables = page.extract_tables()
for table in tables:
for row in table:
print(row) # 一行就是一个 list,元素是各单元格文本
我本机实跑:一份含"供应商报价表"的单页 PDF,extract_tables() 直接吐出 3 行 4 列,表头、单价、数量都在,连"¥1,280"这种带千分位的字符串都原样拿到了。💡 PDF 里没有表格,只有画上去的线和字——能被"倒回去"的,从来都是重新识别出来的。4.批量倒回一个 Excel(多文件 + 多 Sheet)实战里你手里往往是一文件夹 PDF,想把它们各自倒成一个 Sheet,汇总进同一个 .xlsx。跑通一份文件,只需要三步:1装库:pip install pdfplumber openpyxl2单页试水:page.extract_tables() 看结构对不对3批量倒 Excel:遍历文件夹 + find_tables() 逐表写 Sheet代码骨架很薄:遍历文件夹,逐页提取,写进 Excel。import glob, pdfplumber
from openpyxl import Workbook
wb = Workbook()
wb.remove(wb.active) # 去掉默认空 Sheet
for pdf_path in glob.glob("docs/*.pdf"):
name = pdf_path.split("/")[-1]
ws = wb.create_sheet(title=name[:28]) # Sheet 名有长度限制
with pdfplumber.open(pdf_path) as pdf:
for page in pdf.pages:
for table in page.extract_tables():
for row in table:
ws.append(row)
wb.save("汇总.xlsx")
这样 docs/ 下每个 PDF 变成 汇总.xlsx 里的一张 Sheet,名字就是文件名。下面是我在真实文件上踩过的坑,按"现象、根因、解法"的顺序讲,照着改能省一下午。误区:以为"只要是 PDF 就能提取"。扫描件本质是图片,没有文字层,extract_tables() 抓不到任何东西,xlsx 里自然全是空行。正确:提取前先体检——len(page.chars) == 0 就说明是扫描件。要么找源头要可编辑版本,要么先上 OCR(paddleocr / 腾讯云 OCR)把图转成文字,本工具不覆盖这条路。误区:直接 ws.append(row) 把原始串写进去。单价 "1,280"、金额带千分位逗号和全角空格,进了 Excel 全变文本,SUM 一算全是 0。正确:写之前过一道清洗——去逗号、去空白、去换行,能转 float 就转,转不成的保留原串。第 6 节的 clean_cell() 就是这个逻辑。误区:以为一张表会自动跨页连起来。pdfplumber 按页提取,横跨两页的同一张表会被当成两张断表,首尾对不上。正确:先用 find_tables() 调 vertical_strategy / horizontal_strategy 让识别更贴合;跨页拼接是业务层活儿——用"表头是否一致"判断相邻页是否同一张表,是就拼进同一 Sheet。下面脚本给的是表级提取写法,拼接按你自己的表头补。误区:默认参数一把梭。PDF 表格线不规整时,pdfplumber 默认容差抓不准边界,列整体错位、表头对不齐,金额跑到名称列。重点:给 extract_tables(table_settings=...) 传配置,重点调 vertical_strategy="lines"(按线找竖线)、intersection_x_tolerance(交点容差)。线条清晰的表把容差调小反而更准。settings = {
"vertical_strategy": "lines",
"horizontal_strategy": "lines",
"intersection_x_tolerance": 3,
"intersection_y_tolerance": 3,
}
tables = page.extract_tables(settings)
误区:以为 extract_tables() 会乖乖分开。默认只识别页面里最显眼的那张表,一页上的"汇总表 + 明细表"会被并成一张大表,数据乱套。正确:用 page.find_tables() 拿到所有表对象,逐个 t.extract(),再分别写 Sheet。写法见第 6 节脚本。把上面的要点打包成一份可复用脚本:扫描文件夹、每页用 find_tables() 抓全部表、清洗单元格、一个 PDF 写一张 Sheet、单个出错不影响整体、末尾报成功失败数。运行时可传 SRC 和 OUT 两个参数,不传就用下面的默认值。import sys, glob, os, pdfplumber
from openpyxl import Workbook
SRC = sys.argv[1] if len(sys.argv) > 1 else r"D:/docs"
OUT = sys.argv[2] if len(sys.argv) > 2 else r"D:/docs/汇总.xlsx"
def clean_cell(v):
if v is None:
return ""
s = str(v).replace("\n", " ").strip()
s = s.replace(",", "").replace(" ", "")
try:
return float(s) # 能转数字就转,Excel 才能求和
except ValueError:
return v # 转不了就保留原文本
wb = Workbook()
wb.remove(wb.active)
ok, fail = 0, 0
for pdf_path in glob.glob(os.path.join(SRC, "*.pdf")):
name = os.path.splitext(os.path.basename(pdf_path))[0][:28]
ws = wb.create_sheet(title=name)
try:
with pdfplumber.open(pdf_path) as pdf:
for page in pdf.pages:
for tbl in page.find_tables(): # 一页里的全部表
for row in tbl.extract():
ws.append([clean_cell(c) for c in row])
ok += 1
print("已提取:", name)
except Exception as e:
fail += 1
print("失败:", name, "->", e)
wb.save(OUT)
print(f"完成:成功 {ok} 份,失败 {fail} 份 -> {OUT}")
把 SRC、OUT 改成你的路径(或命令行传参),双击运行,一摞 PDF 里的表格就都躺进一个 Excel 了。体检小技巧:跑之前先 print(len(pdf.pages[0].chars)),输出 0 就是扫描件,别浪费时间跑提取,先去要可编辑版本或上 OCR。PDF 里没有表格对象,倒回 Excel 本质是重新识别单元格,别指望原样导出。
纯文本 PDF 首选 pdfplumber + openpyxl,依赖最少、代码最短。数字务必清洗后转 float,否则 Excel 里全是文本、没法算。
扫描件先体检(page.chars 为空即扫描件),提取库对它无能为力。
一页多表用 find_tables() 逐个抓,跨页断表靠表头匹配自己拼。01 几百个文件要重命名?30 行 Python 一键批量改
02 Word 批量转 PDF:本地一键,不花一分钱
03 PDF 表格批量倒回 Excel:不用手工抄(本文)💬留言区首席等着您如果本文对您有一点点用或者您也遇到了相似的问题,都留下您宝贵的意见 👇