
有些表格整理工作,说难也不难,说简单也不简单。
比如一批政府网站年报、企业年报、项目验收报告、审计报告或者统计年鉴 PDF,里面的字段都差不多,但每次都要人工打开文件、翻页、复制表格、整理 Excel。
文件少的时候还能忍,文件一多就很麻烦。
尤其是这种场景:
河北省-130000-2022.pdf
山西省-140000-2022.pdf
辽宁省-210000-2022.pdf
江苏省-320000-2022.pdf
浙江省-330000-2022.pdf每份 PDF 里都有类似的表格字段:
• 网站名称 • 主办单位 • 网站类型 • 信息发布总数 • 政务动态信息数 • 解读回应信息数 • 办事服务事项数 • 互动交流留言数
人工处理时,一份 PDF 可能只需要几分钟,但几十份、几百份放在一起,就会变成非常重复的机械劳动。
这篇教程要做的事情很直接:
用 Python 批量读取 PDF 表格,自动提取核心字段,最后汇总成一张 Excel 表。
一、背景
很多 PDF 年报看起来像“表格”,但实际上并不是 Excel 表。
它们通常是 PDF 页面里的文字、线条和坐标信息。
人工可以直接看懂:
但对程序来说,需要先把 PDF 页面里的表格结构识别出来,再把字段和字段值对应起来。
所以这个任务可以拆成四步:
读取 PDF 文件
→ 提取页面表格
→ 根据关键词定位字段
→ 汇总导出 Excel最终我们希望得到一张这样的结果表:
二、代码思路
这篇教程主要使用三个 Python 包:
pdfplumber | |
pandas | |
re |
整体代码逻辑如下:
1. 扫描 input_pdfs 文件夹中的所有 PDF
2. 从文件名中提取省份、行政区划代码、年份
3. 逐页读取 PDF 表格
4. 把表格内容拉平成文本单元格
5. 根据关键词查找字段值
6. 将每份 PDF 的结果合并
7. 导出 CSV 和 Excel 文件三、安装依赖
先安装需要用到的 Python 包:
pip install pdfplumber pandas openpyxl如果后面需要处理扫描版 PDF,还可以额外使用 OCR 工具。
但这次先处理最常见的一类:
带文本层的 PDF,也就是可以直接复制文字的 PDF。
四、核心代码
1. 导入依赖
import re
from pathlib import Path
import pandas as pd
import pdfplumber这里用到的几个库分别负责:
• Path:管理文件路径;• re:用正则表达式解析文件名;• pandas:整理和导出结果;• pdfplumber:读取 PDF 表格。
2. 从文件名提取信息
假设 PDF 文件名格式为:
河北省-130000-2022.pdf我们可以从中提取:
• 省份:河北省 • 行政区划代码:130000 • 年份:2022
代码如下:
def parse_filename(pdf_path: Path) -> dict:
"""
从文件名中提取省份、行政区划代码和年份。
文件名示例:河北省-130000-2022.pdf
"""
name = pdf_path.stem
pattern = r"(.+?)-(\d{6})-(\d{4})"
match = re.search(pattern, name)
if not match:
return {
"省份": "",
"行政区划代码": "",
"年份": ""
}
province, code, year = match.groups()
return {
"省份": province,
"行政区划代码": code,
"年份": year
}这一步的作用是先把文件本身的信息提取出来。
很多年报 PDF 的文件名里已经包含地区和年份,这些信息不需要再从正文里找,直接从文件名解析更稳定。
3. 清洗单元格文本
PDF 表格提取出来以后,单元格里经常会有换行、空格、特殊符号。
所以先写一个文本清洗函数。
def clean_text(x):
"""
清洗 PDF 表格中的单元格文本。
"""
if x is None:
return ""
x = str(x)
x = x.replace("\n", "")
x = x.replace("\r", "")
x = re.sub(r"\s+", "", x)
return x.strip()比如原始内容可能是:
信息发布
总数清洗后会变成:
信息发布总数这样后面用关键词匹配时会更方便。
4. 提取 PDF 中的所有表格
接下来读取 PDF 的每一页,并提取页面中的表格。
def extract_all_tables(pdf_path: Path) -> list:
"""
提取 PDF 中的所有表格。
返回结果是一个二维表格列表。
"""
all_tables = []
with pdfplumber.open(pdf_path) as pdf:
for page_no, page in enumerate(pdf.pages, start=1):
tables = page.extract_tables()
for table in tables:
cleaned_table = []
for row in table:
cleaned_row = [clean_text(cell) for cell in row]
cleaned_table.append(cleaned_row)
all_tables.append({
"page": page_no,
"table": cleaned_table
})
return all_tables这里需要注意:
• 一个 PDF 可能有很多页; • 一页里可能有多个表格; • 每个表格可能有很多行和列; • 提取后要统一清洗单元格内容。
5. 根据关键词查找字段值
年报表格通常是“字段名—字段值”的形式。
比如:
我们可以根据关键词找到字段所在单元格,然后取右侧单元格作为字段值。
def find_value_by_keyword(all_tables: list, keyword: str) -> str:
"""
在所有表格中查找关键词,并返回其右侧单元格内容。
"""
for item in all_tables:
table = item["table"]
for row in table:
for col_idx, cell in enumerate(row):
if keyword in cell:
if col_idx + 1 < len(row):
value = row[col_idx + 1]
if value:
return value
cell_clean = cell.replace(keyword, "")
if cell_clean:
return cell_clean
return ""这个函数的核心逻辑是:
找到关键词
→ 查看右侧单元格
→ 如果右侧有值,就返回
→ 如果没有,再尝试从当前单元格中拆出值6. 提取单个 PDF 的核心字段
现在可以把前面的函数组合起来,提取一份 PDF 的关键信息。
def extract_one_pdf(pdf_path: Path) -> dict:
"""
提取单个 PDF 年报中的核心字段。
"""
file_info = parse_filename(pdf_path)
all_tables = extract_all_tables(pdf_path)
field_map = {
"网站名称": "网站名称",
"主办单位": "主办单位",
"网站类型": "网站类型",
"信息发布总数": "信息发布总数",
"政务动态信息数": "政务动态信息数",
"解读回应信息数": "解读回应信息数",
"办事服务事项数": "办事服务事项数",
"互动交流留言数": "互动交流留言数"
}
result = {
"文件名": pdf_path.name,
**file_info
}
for output_col, keyword in field_map.items():
result[output_col] = find_value_by_keyword(all_tables, keyword)
return result这里的 field_map 可以按照自己的 PDF 内容继续扩展。
比如你想提取更多字段,可以继续加:
field_map = {
"网站名称": "网站名称",
"主办单位": "主办单位",
"年度总访问量": "年度总访问量",
"首页访问量": "首页访问量",
"新媒体账号数量": "新媒体账号数量"
}7. 批量处理文件夹
最后写一个批量处理函数,扫描整个文件夹里的 PDF。
def batch_extract(input_dir: str, output_dir: str):
"""
批量提取 PDF 表格字段,并导出 CSV 和 Excel。
"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
pdf_files = sorted(input_path.glob("*.pdf"))
records = []
for pdf_file in pdf_files:
print(f"正在处理:{pdf_file.name}")
try:
record = extract_one_pdf(pdf_file)
records.append(record)
except Exception as e:
records.append({
"文件名": pdf_file.name,
"错误信息": str(e)
})
df = pd.DataFrame(records)
csv_path = output_path / "pdf_year_report_summary.csv"
xlsx_path = output_path / "pdf_year_report_summary.xlsx"
df.to_csv(csv_path, index=False, encoding="utf-8-sig")
df.to_excel(xlsx_path, index=False)
print("处理完成")
print(f"CSV 文件已保存:{csv_path}")
print(f"Excel 文件已保存:{xlsx_path}")这个函数做了几件事:
1. 找到所有 PDF 文件; 2. 逐个 PDF 提取字段; 3. 如果某个文件报错,也不会中断整个程序; 4. 最后统一导出 CSV 和 Excel。
8. 主程序入口
完整脚本最后加上主程序入口:
if __name__ == "__main__":
batch_extract(
input_dir="input_pdfs",
output_dir="output"
)运行代码:
python extract_pdf_tables.py五、结果展示
代码运行后,会在 output 文件夹中生成两个文件:
pdf_year_report_summary.csv
pdf_year_report_summary.xlsx汇总结果示例如下:
从结果可以看到,原本分散在多个 PDF 里的字段已经被统一整理到一张 Excel 表中。
这样后续无论是做描述统计、地区对比,还是进一步合并到面板数据里,都可以直接使用。
六、结果解读
其实重点不是单纯“读取 PDF”,而是完成一条完整的数据整理流程:
批量 PDF 文件
→ 自动识别文件信息
→ 提取表格字段
→ 汇总结构化数据
→ 导出 Excel / CSV相比人工整理,这种方法有三个优势。
1. 节省重复劳动
人工需要逐份 PDF 打开、复制、粘贴。
代码只需要把 PDF 放进指定文件夹,一次运行即可批量处理。
2. 字段格式统一
人工整理时,容易出现字段命名不一致的问题。
比如:
信息发布总数
信息发布数量
发布信息总数代码可以通过统一字段表进行规范化处理。
3. 方便后续分析
导出的 Excel 表可以继续用于:
• 地区对比; • 年份对比; • 政务公开水平测度; • 政府网站绩效评价; • 政策执行透明度指标构建。
七、总结
这次我们演示了如何用 Python 批量提取 PDF 年报中的表格字段。
整个流程可以概括为:
读取 PDF
→ 提取表格
→ 匹配关键词
→ 整理字段
→ 导出 Excel对于大量格式相近的 PDF 文件,这种方法非常适合用来减少重复劳动。
它尤其适用于:
• 政府网站年报整理; • 企业年报字段提取; • 项目验收报告汇总; • 审计报告表格提取; • 统计公报数据整理; • 政策文件附表提取。
最后得到的不是一堆零散 PDF,而是一张可以继续分析的结构化数据表。
这也是 Python 自动化处理 PDF 的核心价值:
把“看得见但不好用”的 PDF 表格,变成“能统计、能合并、能分析”的 Excel 数据。

夜雨聆风