Python 实战:把 PDF 表格完整转换成 Excel(小白教程)
很多同学第一次接触 PDF 数据处理时,都会遇到一个问题:
PDF 里的表格能看,不能算,不能统计。
比如:
- 招聘成绩公示
- 学校成绩单
- 名单汇总表
本文将通过一个完整可运行的 Python 示例,一步一步教你:
👉 如何把一个多页 PDF 表格,稳定地转换成 Excel 文件
一、整体思路先说明(很重要)
在正式写代码前,你一定要明白一件事:
PDF ≠ Excel
- Excel:天然是"行 + 列"
- PDF:只是"排好版的页面"
所以我们要做的是:
1. 从 PDF 中提取"表格结构"
2. 把每一行数据收集起来
3. 修复列数不一致的问题
4. 再导出为 Excel
二、完整代码(先给结论)
下面是完整、可直接运行的代码,后面我会逐步拆解讲解。
python
import pdfplumber
import pandas as pd
import os
def pdf_to_excel(pdf_path, excel_path):
all_rows = []
# 打开 PDF
with pdfplumber.open(pdf_path) as pdf:
print(f"PDF共有 {len(pdf.pages)} 页")
# 遍历每一页
for page_num, page in enumerate(pdf.pages, start=1):
print(f"正在处理第 {page_num} 页...")
tables = page.extract_tables()
if not tables:
continue
for table in tables:
for row in table:
# 跳过全空行
if row and any(cell and cell.strip() for cell in row if isinstance(cell, str)):
all_rows.append(row)
if not all_rows:
print(" 未提取到任何表格数据")
return
# 计算最大列数
max_cols = max(len(row) for row in all_rows)
print(f"检测到最大列数:{max_cols}")
# 统一所有行的列数
normalized_rows = []
for row in all_rows:
if len(row) < max_cols:
row = row + [None] * (max_cols - len(row))
elif len(row) > max_cols:
row = row[:max_cols]
normalized_rows.append(row)
# 第一行作为表头
header = normalized_rows[0]
data = normalized_rows[1:]
# 去除重复表头行
clean_data = []
for row in data:
if row != header:
clean_data.append(row)
# 构建 DataFrame
df = pd.DataFrame(clean_data, columns=header)
# 清理空行、空列
df = df.dropna(how='all').dropna(axis=1, how='all')
# 导出 Excel
df.to_excel(excel_path, index=False, engine='openpyxl')
print("\n 转换完成")
print(f"Excel 文件路径:{excel_path}")
print(f"数据行数:{len(df)}")
print(f"列数:{len(df.columns)}")
print("列名:", list(df.columns))
print("\n前 5 行数据预览:")
print(df.head())
if __name__ == "__main__":
pdf_file = "Example.pdf"
excel_file = "Result.xlsx"
if not os.path.exists(pdf_file):
print(f"找不到 PDF 文件:{pdf_file}")
else:
pdf_to_excel(pdf_file, excel_file)
三、逐步解析代码(小白重点)
1️⃣ 导入库
python
import pdfplumber
import pandas as pd
import os
作用说明:
| 库 | 作用 |
|---|---|
| pdfplumber | 读取 PDF、提取表格 |
| pandas | 处理表格数据 |
| os | 判断文件是否存在 |
2️⃣ 定义核心函数
python
def pdf_to_excel(pdf_path, excel_path):
这个函数只做一件事:
把一个 PDF 表格文件,转换成 Excel
3️⃣ 收集所有表格行
python
all_rows = []
为什么要这样做?
👉 因为 PDF 是一页一页的 ,
但 Excel 是一个整体表格。
4️⃣ 打开 PDF 并逐页处理
python
with pdfplumber.open(pdf_path) as pdf:
pdf.pages:PDF 的每一页extract_tables():提取当前页中的表格
5️⃣ 跳过空行(非常关键)
python
if row and any(cell and cell.strip() for cell in row if isinstance(cell, str)):
作用:
- 防止空行进入 Excel
- 防止生成一堆没用的数据
6️⃣ 为什么要"统一列数"(核心思想)
python
max_cols = max(len(row) for row in all_rows)
现实中的 PDF 表格:
- 有的页 8 列
- 有的页 9 列
- 有的页 10 列
👉 如果不统一,pandas 会直接报错
所以我们要:
python
不足的补 None,多的截断
7️⃣ 第一行作为表头
python
header = normalized_rows[0]
PDF 表格通常每一页都有表头,
我们只保留第一行作为最终列名。
8️⃣ 去掉重复表头行
python
if row != header:
clean_data.append(row)
否则 Excel 会变成:
职位代码 | 职位名称 | ...
职位代码 | 职位名称 | ...
职位代码 | 职位名称 | ...
9️⃣ 导出 Excel
python
df.to_excel(excel_path, index=False, engine='openpyxl')
这一步就是真正生成 Excel 文件。
四、示例 PDF 模板(示意)
假设你的 PDF 表格内容长这样(每一页类似):
| 职位代码 | 职位名称 | 准考证号 | 考场号 | 座位号 | 成绩 |
|---|---|---|---|---|---|
| 00001 | A001 | A00010201 | 2 | 1 | 78.25 |
| 00001 | A001 | A00010101 | 1 | 1 | 82.50 |
五、预期 Excel 处理结果
最终生成的 Excel 表格应为:
| 职位代码 | 职位名称 | 准考证号 | 考场号 | 座位号 | 成绩 |
|---|---|---|---|---|---|
| 00001 | A001 | A00010201 | 2 | 1 | 78.25 |
| 00001 | A001 | A00010101 | 1 | 1 | 82.50 |
| ... | ... | ... | ... | ... | ... |
👉 一人一行,可直接统计、排序、筛选
六、这个程序能做什么 / 不能做什么
✅ 能处理
- 多页 PDF 表格
- 列数不一致
- 招聘、公示、成绩类 PDF
❌ 不能处理
- 扫描版 PDF(图片)
- 完全靠空格排版的"假表格"
七、总结一句话
PDF → Excel 的难点不在"读取",而在"结构修复"。
这份代码已经解决了:
- 多页
- 表头重复
- 列数不一致