PDF 是办公文件里最难处理的格式------看似简单的提取文字、合并拆分,用常规方法做起来都很麻烦。这篇讲几个最实用的 PDF 处理场景,代码直接复制就能用。
一、安装
bash
pip install pdfplumber PyPDF2 # 两个库各有侧重,搭配使用
| 库 | 擅长 | 不擅长 |
|---|---|---|
| pdfplumber | 提取文字、表格,精度高 | 合并拆分 PDF |
| PyPDF2 | 合并、拆分、旋转、加密 PDF | 提取表格不太行 |
两个都装上,各取所长。
二、读取 PDF 文字
1. 提取所有文字
python
import pdfplumber
with pdfplumber.open("报告.pdf") as pdf:
# 总页数
print(f"共 {len(pdf.pages)} 页")
full_text = ""
for i, page in enumerate(pdf.pages):
text = page.extract_text()
if text:
full_text += text + "\n"
print(f"第 {i+1} 页: {len(text)} 字符")
# 保存成 txt
with open("输出.txt", "w", encoding="utf-8") as f:
f.write(full_text)
2. 提取指定页面
python
import pdfplumber
with pdfplumber.open("报告.pdf") as pdf:
# 提取第 3-5 页(页码从 0 开始)
for i in range(2, 5):
page = pdf.pages[i]
text = page.extract_text()
print(f"=== 第 {i+1} 页 ===")
print(text)
3. 解决中文乱码问题
PDF 中文提取乱码很常见,试试这些方法:
python
import pdfplumber
with pdfplumber.open("报告.pdf") as pdf:
for page in pdf.pages:
# 方法1:直接提取
text = page.extract_text()
# 方法2:如果乱码,试试保留空白
text = page.extract_text(x_tolerance=3, y_tolerance=3)
# 方法3:按行提取
lines = page.extract_text_lines()
for line in lines:
print(line["text"])
如果还是乱码,那说明 PDF 本身是扫描件(图片型 PDF),需要 OCR 识别,后面会讲。
三、提取 PDF 中的表格
pdfplumber 提取表格精度很高,比手动复制粘贴快 100 倍:
python
import pdfplumber
import pandas as pd
with pdfplumber.open("财务报表.pdf") as pdf:
all_tables = []
for page in pdf.pages:
tables = page.extract_tables()
for table in tables:
# table 是二维列表,第一行通常是表头
df = pd.DataFrame(table[1:], columns=table[0])
all_tables.append(df)
print(f"找到 1 个表格,{len(table)} 行 × {len(table[0])} 列")
# 合并所有表格并导出
if all_tables:
result = pd.concat(all_tables, ignore_index=True)
result.to_excel("表格数据.xlsx", index=False)
print(f"共提取 {len(result)} 行数据,已导出到 表格数据.xlsx")
实际案例: 提取每个月的财务报表 PDF → 自动汇总到 Excel → 每月省 30 分钟的重复劳动。
四、合并多个 PDF
python
from PyPDF2 import PdfMerger
import os
def merge_pdfs(input_dir, output_file):
"""合并一个文件夹下的所有 PDF"""
merger = PdfMerger()
# 按文件名排序,保证顺序
files = sorted([f for f in os.listdir(input_dir) if f.endswith(".pdf")])
for f in files:
filepath = os.path.join(input_dir, f)
merger.append(filepath)
print(f"已添加: {f}")
merger.write(output_file)
merger.close()
print(f"合并完成,共 {len(files)} 个文件 → {output_file}")
# 使用
merge_pdfs("要合并的PDF", "合并结果.pdf")
五、拆分 PDF
python
from PyPDF2 import PdfReader, PdfWriter
def split_pdf(input_file, output_dir, pages_per_file=10):
"""按每N页一组拆分 PDF"""
reader = PdfReader(input_file)
total_pages = len(reader.pages)
os.makedirs(output_dir, exist_ok=True)
file_index = 1
for start in range(0, total_pages, pages_per_file):
writer = PdfWriter()
end = min(start + pages_per_file, total_pages)
for page_num in range(start, end):
writer.add_page(reader.pages[page_num])
output_file = f"{output_dir}/第{file_index}部分({start+1}-{end}页).pdf"
with open(output_file, "wb") as f:
writer.write(f)
print(f"已生成: {output_file}")
file_index += 1
# 使用:每 20 页拆一份
split_pdf("大文件.pdf", "拆分输出", pages_per_file=20)
六、给 PDF 加密码
python
from PyPDF2 import PdfReader, PdfWriter
def encrypt_pdf(input_file, password, output_file=None):
"""给 PDF 加上密码保护"""
reader = PdfReader(input_file)
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
writer.encrypt(password)
output = output_file or input_file.replace(".pdf", "_加密.pdf")
with open(output, "wb") as f:
writer.write(f)
print(f"已加密: {output}")
return output
# 使用
encrypt_pdf("合同.pdf", "123456", "合同_加密.pdf")
七、处理扫描件 PDF(OCR 识别)
如果 PDF 是扫描图片,pdfplumber 提取不到文字,需要用 OCR:
bash
pip install pytesseract pillow
# 还需要安装 Tesseract-OCR 引擎(百度搜索下载)
python
import pytesseract
from PIL import Image
import pdfplumber
import io
def ocr_pdf(pdf_path):
"""OCR 识别扫描件 PDF"""
with pdfplumber.open(pdf_path) as pdf:
full_text = ""
for i, page in enumerate(pdf.pages):
# 把 PDF 页面转成图片
img = page.to_image(resolution=300)
img_path = f"temp_page_{i}.png"
img.save(img_path)
# OCR 识别
text = pytesseract.image_to_string(
Image.open(img_path), lang="chi_sim+eng"
)
full_text += text + "\n"
print(f"第 {i+1} 页识别完成,{len(text)} 字符")
with open("ocr_result.txt", "w", encoding="utf-8") as f:
f.write(full_text)
return full_text
# 使用(识别中文要下载中文语言包)
ocr_pdf("扫描件.pdf")
注意: OCR 识别需要安装 Tesseract-OCR 引擎,Windows 用户下载安装包后要配置环境变量。中文识别还需要下载 chi_sim 语言包。
八、常用场景速查表
| 场景 | 代码 | 用哪个库 |
|---|---|---|
| 提取文字 | page.extract_text() |
pdfplumber |
| 提取表格 | page.extract_tables() |
pdfplumber |
| 合并多个 PDF | merger.append(file) |
PyPDF2 |
| 拆分 PDF | writer.add_page(page) |
PyPDF2 |
| 加密码 | writer.encrypt(password) |
PyPDF2 |
| 提取图片 | page.to_image() |
pdfplumber |
| OCR 识别 | image_to_string() |
pytesseract |
| 旋转页面 | page.rotate(90) |
PyPDF2 |
九、完整案例:发票信息批量提取
python
import pdfplumber
import pandas as pd
import os
def extract_invoice_info(pdf_path):
"""从发票 PDF 中提取关键信息"""
info = {"文件名": os.path.basename(pdf_path)}
with pdfplumber.open(pdf_path) as pdf:
text = ""
for page in pdf.pages:
text += page.extract_text() or ""
# 用正则提取关键信息(根据实际发票格式调整)
import re
# 发票号码
match = re.search(r"发票号码[::]\s*(\d+)", text)
info["发票号码"] = match.group(1) if match else ""
# 开票日期
match = re.search(r"开票日期[::]\s*(\d{4}[-年]\d{1,2}[-月]\d{1,2})", text)
info["开票日期"] = match.group(1) if match else ""
# 金额
match = re.search(r"价税合计[::]\s*[¥¥]?([\d,]+\.\d{2})", text)
info["金额"] = match.group(1) if match else ""
# 销售方名称
match = re.search(r"销售方[名称]?[::]\s*(.+?)(?:\n|$)", text)
info["销售方"] = match.group(1).strip() if match else ""
return info
# 批量处理所有 PDF
pdf_dir = "发票文件夹"
results = []
for f in os.listdir(pdf_dir):
if f.endswith(".pdf"):
try:
info = extract_invoice_info(os.path.join(pdf_dir, f))
results.append(info)
print(f"已处理: {f}")
except Exception as e:
print(f"处理失败 {f}: {e}")
# 导出到 Excel
df = pd.DataFrame(results)
df.to_excel("发票汇总.xlsx", index=False)
print(f"共处理 {len(results)} 份发票")
总结
PDF 自动化处理最难的不是技术,而是不同的 PDF 格式差异太大(有的是文字型、有的是扫描件、有的表格不规范)。一篇 80% 的 PDF 用上面的代码能搞定,剩下 20% 需要根据具体 PDF 格式微调参数。
建议遇到新的 PDF 格式时,先用 pdfplumber 打开看看结构,再决定怎么提取。
💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。