You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求解决方案:构建PDF文本查找替换应用并实现PDF自动化处理

Python实现PDF文本替换自动化方案

核心逻辑

PDF并非可直接编辑的文本文件,直接替换文本不可行,需采用先擦除目标文本区域,再叠加新文本的思路,完全匹配你的需求流程:读取数据源→遍历PDF文件夹→处理单文件→重命名+生成报告→备份原文件。

依赖库安装

先安装必备工具包,执行以下命令:

pip install PyPDF2 reportlab pandas sqlalchemy pdfplumber python-dotenv
  • PyPDF2:读写PDF页面内容
  • reportlab:绘制白色覆盖层擦除文本、添加新文本
  • pdfplumber:精准定位文本坐标(比PyPDF2的文本提取更可靠)
  • pandas:读取Excel数据源
  • sqlalchemy:连接SQL数据库

分步代码实现

1. 读取数据源(Excel/SQL二选一)

import pandas as pd
from sqlalchemy import create_engine

# 读取Excel配置(假设Excel列名:原文件名, 目标文本, 替换文本, 新文件名)
def load_excel_config(excel_path):
    df = pd.read_excel(excel_path)
    return df.set_index('原文件名').to_dict('index')

# 读取SQL配置
def load_sql_config(db_params):
    engine = create_engine(f"mysql+pymysql://{db_params['user']}:{db_params['pwd']}@{db_params['host']}/{db_params['db']}")
    query = "SELECT 原文件名, 目标文本, 替换文本, 新文件名 FROM pdf_replace_rules"
    df = pd.read_sql(query, engine)
    return df.set_index('原文件名').to_dict('index')

2. PDF文本替换核心函数

from PyPDF2 import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
import io
import pdfplumber

def replace_target_text(input_pdf, output_pdf, target_text, new_text):
    # 读取原PDF
    reader = PdfReader(input_pdf)
    writer = PdfWriter()

    with pdfplumber.open(input_pdf) as pdf:
        for page_num in range(len(reader.pages)):
            pdf_page = pdf.pages[page_num]
            page = reader.pages[page_num]
            page_w = float(page.mediabox[2])
            page_h = float(page.mediabox[3])
            upper_third_top = page_h * 2/3  # 页面上三分之一区域的顶部边界(pdfplumber的top从页面顶部开始计算)

            # 创建白色覆盖层,用于擦除目标文本
            packet = io.BytesIO()
            can = canvas.Canvas(packet, pagesize=(page_w, page_h))
            can.setFillColorRGB(1,1,1)  # 白色完全覆盖原文本

            # 遍历页面上三分之一区域的文本,定位目标文本并覆盖
            for word in pdf_page.extract_words():
                if word['text'] == target_text and word['top'] <= upper_third_top:
                    # 转换坐标:pdfplumber的y轴从顶部算,reportlab从底部算
                    rect_x = word['x0']
                    rect_y = page_h - word['bottom']
                    rect_w = word['x1'] - word['x0']
                    rect_h = word['bottom'] - word['top']
                    can.rect(rect_x, rect_y, rect_w, rect_h, fill=True)

            # 在原文本位置添加新文本(取第一个匹配位置的坐标)
            target_words = [w for w in pdf_page.extract_words() if w['text'] == target_text and w['top'] <= upper_third_top]
            if target_words:
                first_word = target_words[0]
                can.setFillColorRGB(0,0,0)
                can.setFont("Helvetica", 12)  # 需替换为原文档的字体、字号
                can.drawString(first_word['x0'], page_h - first_word['top'], new_text)

            can.save()
            packet.seek(0)
            overlay = PdfReader(packet).pages[0]
            page.merge_page(overlay)
            writer.add_page(page)

    # 写入新PDF文件
    with open(output_pdf, "wb") as f:
        writer.write(f)

3. 主流程:批量处理+备份+生成报告

import os
import shutil
from datetime import datetime

def batch_process_pdfs(folder_path, config_data):
    report_rows = []
    backup_dir = os.path.join(folder_path, "原始文件备份")
    os.makedirs(backup_dir, exist_ok=True)
    report_path = f"./PDF处理报告_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"

    for filename in os.listdir(folder_path):
        if not filename.endswith(".pdf"):
            continue
        file_path = os.path.join(folder_path, filename)
        # 跳过备份文件夹中的文件
        if os.path.abspath(file_path).startswith(os.path.abspath(backup_dir)):
            continue

        # 匹配替换规则
        if filename not in config_data:
            report_rows.append({
                "原文件名": filename,
                "新文件名": "-",
                "处理状态": "无对应替换规则"
            })
            continue

        rule = config_data[filename]
        target_text = rule['目标文本']
        new_text = rule['替换文本']
        new_filename = f"{rule['新文件名']}.pdf"
        output_path = os.path.join(folder_path, new_filename)

        try:
            replace_target_text(file_path, output_path, target_text, new_text)
            # 备份原文件
            shutil.copy(file_path, os.path.join(backup_dir, filename))
            report_rows.append({
                "原文件名": filename,
                "新文件名": new_filename,
                "处理状态": "成功"
            })
        except Exception as e:
            report_rows.append({
                "原文件名": filename,
                "新文件名": "-",
                "处理状态": f"失败:{str(e)}"
            })

    # 生成Excel格式的处理报告
    pd.DataFrame(report_rows).to_excel(report_path, index=False)
    print(f"批量处理完成,报告已保存到:{report_path}")

# 执行示例
if __name__ == "__main__":
    # 选择一种数据源加载方式
    # config = load_excel_config("./pdf替换规则.xlsx")
    db_params = {
        "user": "你的数据库用户名",
        "pwd": "你的数据库密码",
        "host": "localhost",
        "db": "你的数据库名"
    }
    config = load_sql_config(db_params)

    pdf_folder = "./待处理PDF"
    batch_process_pdfs(pdf_folder, config)

关键注意点

  • 扫描件PDF处理:如果是扫描生成的PDF(图片格式),需先通过pytesseract+pdf2image做OCR转文本,否则无法提取和替换文本。
  • 字体匹配:若要求新文本与原文本字体一致,可通过pdfplumber提取原文本的字体信息,再在reportlab中加载对应字体文件。
  • 坐标转换:pdfplumber与reportlab的y轴计算方向相反,必须转换坐标才能精准覆盖目标文本。
  • 异常扩展:可补充捕获PDF文件损坏、权限不足、数据源格式错误等异常场景,提升代码稳定性。

原代码故障排查方向

如果之前的代码无法运行,优先检查以下几点:

  1. 是否为扫描件PDF?扫描件无法直接提取文本,必须先做OCR处理。
  2. 依赖库版本冲突:旧版PyPDF2的API与新版差异较大,可尝试锁定版本PyPDF2==2.12.0。
  3. 文本定位错误:原代码可能未过滤上三分之一区域,或存在坐标转换错误。
  4. 文件路径问题:是否使用了相对路径但工作目录不正确,或存在中文路径编码问题。

内容的提问来源于stack exchange,提问作者RadoFafo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:40:21