Python 自动化之PDF处理——pdfplumber + PyPDF2 实战

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/爬虫 实战干货,不让你白来。