当前位置: 代码网 > it编程>前端脚本>Python > Python自动化处理PDF文档的操作完整指南

Python自动化处理PDF文档的操作完整指南

2025年08月20日 Python 我要评论
pdf(portable document format,便携式文档格式)是一种广泛使用的文档格式,具有跨平台、稳定性好、安全性高等特点。在办公自动化中,pdf文档处理是一项常见需求。本文将介绍如何使

pdf(portable document format,便携式文档格式)是一种广泛使用的文档格式,具有跨平台、稳定性好、安全性高等特点。在办公自动化中,pdf文档处理是一项常见需求。本文将介绍如何使用python实现pdf文档的自动化处理,包括读写、合并拆分、提取内容、添加水印等操作。

使用pymupdf读写pdf文件

基本概念

一个真实的pdf文件主要由四大部分构成,分别是文件头(header)、文件主体(body)、交叉引用表(cross-reference table)和文件尾(trailer)。了解这些基本结构有助于我们更好地处理pdf文件。

安装pymupdf

pip install pymupdf

提取文本内容

pymupdf库(也称为fitz)可以轻松实现对pdf文件的读写操作。以下是提取pdf文本内容的示例:

import fitz  # pymupdf的导入名称是fitz

def extract_text_from_pdf(pdf_path):
    """从pdf文件中提取所有文本内容"""
    # 打开pdf文件
    doc = fitz.open(pdf_path)
    
    # 创建一个空字符串用于存储文本内容
    text = ""
    
    # 遍历每一页
    for page_num in range(len(doc)):
        # 获取当前页面
        page = doc[page_num]
        
        # 提取文本
        page_text = page.get_text()
        
        # 添加页码信息和页面文本
        text += f"\n--- 第 {page_num + 1} 页 ---\n"
        text += page_text
    
    # 关闭文档
    doc.close()
    
    return text

# 使用示例
pdf_path = "example.pdf"  # 替换为实际的pdf文件路径
try:
    extracted_text = extract_text_from_pdf(pdf_path)
    print("提取的文本内容:")
    print(extracted_text[:500] + "..." if len(extracted_text) > 500 else extracted_text)
    
    # 将提取的文本保存到文件
    with open("extracted_text.txt", "w", encoding="utf-8") as f:
        f.write(extracted_text)
    print("文本已保存到 extracted_text.txt")
    
except exception as e:
    print(f"提取文本时出错: {e}")

提取图像

一个pdf文件通常会包含图像元素,图像作为pdf文件中的对象也会记录在交叉引用表中。在pymupdf库中,可以通过相应的方法获取交叉引用表中记录的对象id编号,并将其称为xref整数。

import fitz
import os

def extract_images_from_pdf(pdf_path, output_folder="extracted_images"):
    """从pdf文件中提取所有图像"""
    # 确保输出文件夹存在
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    
    # 打开pdf文件
    doc = fitz.open(pdf_path)
    
    # 用于记录提取的图像数量
    image_count = 0
    
    # 遍历每一页
    for page_num in range(len(doc)):
        # 获取当前页面
        page = doc[page_num]
        
        # 获取页面上的图像列表
        image_list = page.get_images()
        
        # 遍历图像列表
        for img_index, img in enumerate(image_list):
            # 获取图像的xref
            xref = img[0]
            
            # 获取图像信息
            base_image = doc.extract_image(xref)
            image_bytes = base_image["image"]
            image_ext = base_image["ext"]
            
            # 生成输出文件名
            output_filename = f"{output_folder}/page{page_num + 1}_img{img_index + 1}.{image_ext}"
            
            # 保存图像
            with open(output_filename, "wb") as f:
                f.write(image_bytes)
            
            image_count += 1
    
    # 关闭文档
    doc.close()
    
    return image_count

# 使用示例
pdf_path = "example.pdf"  # 替换为实际的pdf文件路径
try:
    num_images = extract_images_from_pdf(pdf_path)
    print(f"成功提取了 {num_images} 张图像到 'extracted_images' 文件夹")
except exception as e:
    print(f"提取图像时出错: {e}")

添加水印

import fitz

def add_watermark_to_pdf(input_pdf, output_pdf, watermark_text):
    """为pdf文件添加文字水印"""
    # 打开pdf文件
    doc = fitz.open(input_pdf)
    
    # 遍历每一页
    for page_num in range(len(doc)):
        # 获取当前页面
        page = doc[page_num]
        
        # 获取页面尺寸
        rect = page.rect
        
        # 创建一个透明的水印文本
        # 设置字体大小、颜色和透明度
        text_color = (0.5, 0.5, 0.5)  # 灰色
        alpha = 0.3  # 透明度
        fontsize = 24
        
        # 在页面中心添加水印
        tw = fitz.textwriter(rect)
        tw.append((rect.width/2, rect.height/2), watermark_text, fontsize=fontsize, color=text_color)
        tw.write_text(page, opacity=alpha)
    
    # 保存修改后的pdf
    doc.save(output_pdf)
    doc.close()
    
    return output_pdf

# 使用示例
input_pdf = "example.pdf"  # 替换为实际的pdf文件路径
output_pdf = "watermarked.pdf"
watermark_text = "机密文件 - 请勿外传"

try:
    result_pdf = add_watermark_to_pdf(input_pdf, output_pdf, watermark_text)
    print(f"已成功添加水印并保存为: {result_pdf}")
except exception as e:
    print(f"添加水印时出错: {e}")

使用pdfplumber提取pdf中表格

pdf文件中通常会有表格元素,如果想提取表格元素中的内容,可以使用pdfplumber库。

安装pdfplumber

pip install pdfplumber

提取表格数据

pdfplumber库提供的extract_table方法可以轻松提取pdf文件中某页的所有表格,对于缺少边界的表格,pdfplumber库会利用文本位置信息进行猜测,从而定位出不可见边界的位置。

import pdfplumber
import pandas as pd

def extract_tables_from_pdf(pdf_path):
    """从pdf文件中提取所有表格"""
    # 打开pdf文件
    with pdfplumber.open(pdf_path) as pdf:
        all_tables = []
        
        # 遍历每一页
        for page_num, page in enumerate(pdf.pages):
            # 提取表格
            tables = page.extract_tables()
            
            if tables:
                print(f"在第 {page_num + 1} 页找到 {len(tables)} 个表格")
                
                # 处理每个表格
                for table_num, table in enumerate(tables):
                    # 创建dataframe
                    df = pd.dataframe(table[1:], columns=table[0])
                    
                    # 添加页码和表格编号信息
                    df['页码'] = page_num + 1
                    df['表格编号'] = table_num + 1
                    
                    all_tables.append(df)
            else:
                print(f"在第 {page_num + 1} 页没有找到表格")
        
        # 如果找到了表格,合并所有表格
        if all_tables:
            combined_df = pd.concat(all_tables, ignore_index=true)
            return combined_df
        else:
            return none

# 使用示例
pdf_path = "example_with_tables.pdf"  # 替换为包含表格的pdf文件路径
try:
    tables_df = extract_tables_from_pdf(pdf_path)
    
    if tables_df is not none:
        print("\n提取的表格数据:")
        print(tables_df.head())
        
        # 将表格数据保存到excel文件
        excel_path = "extracted_tables.xlsx"
        tables_df.to_excel(excel_path, index=false)
        print(f"表格数据已保存到: {excel_path}")
    else:
        print("未在pdf中找到任何表格")
        
except exception as e:
    print(f"提取表格时出错: {e}")

使用pypdf2操控pdf文件

pypdf2是一个流行的python库,用于处理pdf文件。它能完成pdf文件的信息提取、拆分、合并、页面裁剪、加密/解密等多种操作。

安装pypdf2

pip install pypdf2

合并pdf文件

from pypdf2 import pdfmerger

def merge_pdfs(pdf_files, output_path):
    """合并多个pdf文件"""
    merger = pdfmerger()
    
    # 添加每个pdf文件
    for pdf in pdf_files:
        try:
            merger.append(pdf)
            print(f"已添加: {pdf}")
        except exception as e:
            print(f"添加 {pdf} 时出错: {e}")
    
    # 保存合并后的pdf
    merger.write(output_path)
    merger.close()
    
    return output_path

# 使用示例
pdf_files = ["document1.pdf", "document2.pdf", "document3.pdf"]  # 替换为实际的pdf文件路径
output_path = "merged_document.pdf"

try:
    result_path = merge_pdfs(pdf_files, output_path)
    print(f"已成功合并pdf文件并保存为: {result_path}")
except exception as e:
    print(f"合并pdf文件时出错: {e}")

拆分pdf文件

from pypdf2 import pdfreader, pdfwriter
import os

def split_pdf(input_pdf, output_folder="split_pages"):
    """将pdf文件拆分为单页文件"""
    # 确保输出文件夹存在
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    
    # 打开pdf文件
    reader = pdfreader(input_pdf)
    total_pages = len(reader.pages)
    
    # 获取文件名(不含扩展名)
    base_name = os.path.splitext(os.path.basename(input_pdf))[0]
    
    # 拆分每一页
    for page_num in range(total_pages):
        writer = pdfwriter()
        writer.add_page(reader.pages[page_num])
        
        # 生成输出文件名
        output_filename = f"{output_folder}/{base_name}_page_{page_num + 1}.pdf"
        
        # 保存单页pdf
        with open(output_filename, "wb") as output_file:
            writer.write(output_file)
        
        print(f"已保存第 {page_num + 1} 页到: {output_filename}")
    
    return total_pages

# 使用示例
input_pdf = "example.pdf"  # 替换为实际的pdf文件路径
try:
    num_pages = split_pdf(input_pdf)
    print(f"已成功将 {input_pdf} 拆分为 {num_pages} 个单页pdf文件")
except exception as e:
    print(f"拆分pdf文件时出错: {e}")

加密和解密pdf

from pypdf2 import pdfreader, pdfwriter

def encrypt_pdf(input_pdf, output_pdf, password):
    """加密pdf文件"""
    reader = pdfreader(input_pdf)
    writer = pdfwriter()
    
    # 复制所有页面
    for page in reader.pages:
        writer.add_page(page)
    
    # 设置密码和加密选项
    writer.encrypt(password)
    
    # 保存加密后的pdf
    with open(output_pdf, "wb") as output_file:
        writer.write(output_file)
    
    return output_pdf

def decrypt_pdf(input_pdf, output_pdf, password):
    """解密pdf文件"""
    reader = pdfreader(input_pdf)
    
    # 检查pdf是否加密
    if reader.is_encrypted:
        # 尝试使用密码解密
        if reader.decrypt(password) != 1:
            raise valueerror("密码不正确")
    else:
        print("警告: 输入的pdf文件未加密")
    
    writer = pdfwriter()
    
    # 复制所有页面
    for page in reader.pages:
        writer.add_page(page)
    
    # 保存解密后的pdf
    with open(output_pdf, "wb") as output_file:
        writer.write(output_file)
    
    return output_pdf

# 使用示例 - 加密
input_pdf = "example.pdf"  # 替换为实际的pdf文件路径
encrypted_pdf = "encrypted_document.pdf"
password = "secure123"  # 设置密码

try:
    result_path = encrypt_pdf(input_pdf, encrypted_pdf, password)
    print(f"已成功加密pdf文件并保存为: {result_path}")
except exception as e:
    print(f"加密pdf文件时出错: {e}")

# 使用示例 - 解密
decrypted_pdf = "decrypted_document.pdf"

try:
    result_path = decrypt_pdf(encrypted_pdf, decrypted_pdf, password)
    print(f"已成功解密pdf文件并保存为: {result_path}")
except exception as e:
    print(f"解密pdf文件时出错: {e}")

使用wkhtmltopdf将网页转为pdf

wkhtmltopdf是一个开源工具,可以将html页面转换为pdf文档。它可以通过命令行直接使用,也可以通过python的pdfkit库进行调用。

安装wkhtmltopdf和pdfkit

首先,需要安装wkhtmltopdf工具:

  • 在macos上:brew install wkhtmltopdf
  • 在windows上:从官方网站下载安装程序
  • 在linux上:sudo apt-get install wkhtmltopdf(ubuntu/debian)或 sudo yum install wkhtmltopdf(centos/rhel)

然后,安装pdfkit python库:

pip install pdfkit

将网页转换为pdf

import pdfkit

def url_to_pdf(url, output_pdf):
    """将url指向的网页转换为pdf"""
    try:
        # 配置wkhtmltopdf路径(如果不在系统path中)
        # config = pdfkit.configuration(wkhtmltopdf='/path/to/wkhtmltopdf')
        # pdfkit.from_url(url, output_pdf, configuration=config)
        
        # 如果wkhtmltopdf在系统path中
        pdfkit.from_url(url, output_pdf)
        print(f"已成功将 {url} 转换为pdf: {output_pdf}")
        return output_pdf
    except exception as e:
        print(f"转换网页到pdf时出错: {e}")
        return none

def html_to_pdf(html_file, output_pdf):
    """将html文件转换为pdf"""
    try:
        pdfkit.from_file(html_file, output_pdf)
        print(f"已成功将 {html_file} 转换为pdf: {output_pdf}")
        return output_pdf
    except exception as e:
        print(f"转换html文件到pdf时出错: {e}")
        return none

def html_string_to_pdf(html_content, output_pdf):
    """将html字符串转换为pdf"""
    try:
        pdfkit.from_string(html_content, output_pdf)
        print(f"已成功将html内容转换为pdf: {output_pdf}")
        return output_pdf
    except exception as e:
        print(f"转换html字符串到pdf时出错: {e}")
        return none

# 使用示例 - 从url创建pdf
url = "https://www.example.com"  # 替换为实际的url
output_pdf = "webpage.pdf"
url_to_pdf(url, output_pdf)

# 使用示例 - 从html文件创建pdf
html_file = "example.html"  # 替换为实际的html文件路径
output_pdf = "from_html_file.pdf"
html_to_pdf(html_file, output_pdf)

# 使用示例 - 从html字符串创建pdf
html_content = """<!doctype html>
<html>
<head>
    <title>测试页面</title>
</head>
<body>
    <h1>hello, world!</h1>
    <p>这是一个由html字符串生成的pdf文档。</p>
</body>
</html>"""
output_pdf = "from_html_string.pdf"
html_string_to_pdf(html_content, output_pdf)

将网页转换为图片

除了转换为pdf,wkhtmltoimage工具(wkhtmltopdf的一部分)还可以将网页转换为图片:

import subprocess

def url_to_image(url, output_image):
    """将url指向的网页转换为图片"""
    try:
        # 执行wkhtmltoimage命令
        command = ["wkhtmltoimage", url, output_image]
        subprocess.run(command, check=true)
        print(f"已成功将 {url} 转换为图片: {output_image}")
        return output_image
    except subprocess.calledprocesserror as e:
        print(f"转换网页到图片时出错: {e}")
        return none
    except exception as e:
        print(f"发生错误: {e}")
        return none

# 使用示例
url = "https://www.example.com"  # 替换为实际的url
output_image = "webpage.jpg"
url_to_image(url, output_image)

从word/excel导出pdf报告

从word导出pdf

from docx2pdf import convert

def word_to_pdf(input_docx, output_pdf=none):
    """将word文档转换为pdf"""
    try:
        # 如果未指定输出pdf路径,则使用相同的文件名但扩展名为.pdf
        if output_pdf is none:
            output_pdf = input_docx.replace(".docx", ".pdf")
        
        # 转换word文档为pdf
        convert(input_docx, output_pdf)
        print(f"已成功将 {input_docx} 转换为pdf: {output_pdf}")
        return output_pdf
    except exception as e:
        print(f"转换word到pdf时出错: {e}")
        return none

# 使用示例
input_docx = "example.docx"  # 替换为实际的word文档路径
word_to_pdf(input_docx)

从excel导出pdf

import win32com.client
import os

def excel_to_pdf(input_excel, output_pdf=none):
    """将excel文件转换为pdf(仅适用于windows系统)"""
    try:
        # 如果未指定输出pdf路径,则使用相同的文件名但扩展名为.pdf
        if output_pdf is none:
            output_pdf = input_excel.replace(".xlsx", ".pdf").replace(".xls", ".pdf")
        
        # 获取绝对路径
        input_excel = os.path.abspath(input_excel)
        output_pdf = os.path.abspath(output_pdf)
        
        # 创建excel应用程序实例
        excel = win32com.client.dispatch("excel.application")
        excel.visible = false
        
        # 打开excel文件
        workbook = excel.workbooks.open(input_excel)
        
        # 将工作簿导出为pdf
        workbook.exportasfixedformat(0, output_pdf)
        
        # 关闭工作簿和excel应用程序
        workbook.close()
        excel.quit()
        
        print(f"已成功将 {input_excel} 转换为pdf: {output_pdf}")
        return output_pdf
    except exception as e:
        print(f"转换excel到pdf时出错: {e}")
        return none

# 使用示例(仅适用于windows系统)
# input_excel = "example.xlsx"  # 替换为实际的excel文件路径
# excel_to_pdf(input_excel)

实际应用场景

场景一:批量处理发票pdf

import os
import fitz
import re
from datetime import datetime
import pandas as pd

def process_invoice_pdfs(invoice_folder, output_excel):
    """批量处理发票pdf,提取关键信息并生成汇总表"""
    # 存储提取的发票信息
    invoices_data = []
    
    # 获取文件夹中的所有pdf文件
    pdf_files = [f for f in os.listdir(invoice_folder) if f.lower().endswith('.pdf')]
    
    for pdf_file in pdf_files:
        pdf_path = os.path.join(invoice_folder, pdf_file)
        print(f"处理: {pdf_path}")
        
        try:
            # 打开pdf文件
            doc = fitz.open(pdf_path)
            
            # 提取第一页文本(假设发票信息在第一页)
            text = doc[0].get_text()
            
            # 使用正则表达式提取关键信息
            # 注意:以下正则表达式需要根据实际发票格式进行调整
            invoice_number = re.search(r'发票号码[::](\s*\d+)', text)
            invoice_number = invoice_number.group(1).strip() if invoice_number else "未知"
            
            invoice_date = re.search(r'开票日期[::](\s*\d{4}[年/-]\d{1,2}[月/-]\d{1,2})', text)
            invoice_date = invoice_date.group(1).strip() if invoice_date else "未知"
            
            amount = re.search(r'金额[::]\s*¥?\s*(\d+\.\d{2})', text)
            amount = amount.group(1).strip() if amount else "0.00"
            
            # 将信息添加到列表
            invoices_data.append({
                '文件名': pdf_file,
                '发票号码': invoice_number,
                '开票日期': invoice_date,
                '金额': float(amount),
            })
            
            # 关闭文档
            doc.close()
            
        except exception as e:
            print(f"处理 {pdf_file} 时出错: {e}")
    
    # 创建dataframe并保存为excel
    if invoices_data:
        df = pd.dataframe(invoices_data)
        
        # 添加总计行
        total_amount = df['金额'].sum()
        df.loc[len(df)] = ['总计', '', '', total_amount]
        
        # 保存为excel
        df.to_excel(output_excel, index=false)
        print(f"已成功处理 {len(invoices_data)} 个发票pdf并保存汇总表到: {output_excel}")
        return output_excel
    else:
        print("未找到有效的发票pdf文件")
        return none

# 使用示例
invoice_folder = "invoices"  # 替换为实际的发票pdf文件夹路径
output_excel = "invoice_summary.xlsx"

# process_invoice_pdfs(invoice_folder, output_excel)

场景二:自动生成pdf报告

import pandas as pd
import matplotlib.pyplot as plt
import fitz
import os
from datetime import datetime

def generate_sales_report_pdf(sales_data_excel, output_pdf):
    """根据销售数据生成pdf报告"""
    # 读取销售数据
    df = pd.read_excel(sales_data_excel)
    
    # 创建临时html文件
    html_path = "temp_report.html"
    
    # 生成图表
    plt.figure(figsize=(10, 6))
    df.groupby('产品')['销售额'].sum().plot(kind='bar')
    plt.title('各产品销售额对比')
    plt.ylabel('销售额')
    plt.tight_layout()
    chart_path = "sales_chart.png"
    plt.savefig(chart_path)
    
    # 计算汇总数据
    total_sales = df['销售额'].sum()
    avg_sales = df['销售额'].mean()
    max_product = df.loc[df['销售额'].idxmax()]['产品']
    max_sales = df['销售额'].max()
    
    # 生成html报告
    html_content = f"""
    <!doctype html>
    <html>
    <head>
        <title>销售数据报告</title>
        <style>
            body {{ font-family: arial, sans-serif; margin: 40px; }}
            h1 {{ color: #2c3e50; text-align: center; }}
            .report-date {{ text-align: right; color: #7f8c8d; }}
            .summary {{ background-color: #f8f9fa; padding: 20px; border-radius: 5px; margin: 20px 0; }}
            table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
            th, td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }}
            th {{ background-color: #3498db; color: white; }}
            tr:hover {{ background-color: #f5f5f5; }}
            .chart {{ text-align: center; margin: 30px 0; }}
            .footer {{ text-align: center; margin-top: 50px; font-size: 12px; color: #7f8c8d; }}
        </style>
    </head>
    <body>
        <div class="report-date">生成日期: {datetime.now().strftime('%y年%m月%d日')}</div>
        <h1>销售数据报告</h1>
        
        <div class="summary">
            <h2>销售摘要</h2>
            <p>总销售额: ¥{total_sales:,.2f}</p>
            <p>平均销售额: ¥{avg_sales:,.2f}</p>
            <p>最畅销产品: {max_product} (¥{max_sales:,.2f})</p>
        </div>
        
        <h2>销售数据明细</h2>
        <table>
            <tr>
                <th>产品</th>
                <th>销售量</th>
                <th>销售额</th>
                <th>日期</th>
            </tr>
    """
    
    # 添加表格数据
    for _, row in df.iterrows():
        html_content += f"""
            <tr>
                <td>{row['产品']}</td>
                <td>{row['销售量']}</td>
                <td>¥{row['销售额']:,.2f}</td>
                <td>{row['日期']}</td>
            </tr>
        """
    
    # 添加图表和页脚
    html_content += f"""
        </table>
        
        <div class="chart">
            <h2>销售图表</h2>
            <img src="{chart_path}" alt="销售数据图表" style="max-width: 100%;">
        </div>
        
        <div class="footer">
            <p>此报告由python自动生成 | 仅供内部使用</p>
        </div>
    </body>
    </html>
    """
    
    # 保存html文件
    with open(html_path, "w", encoding="utf-8") as f:
        f.write(html_content)
    
    # 将html转换为pdf
    import pdfkit
    try:
        pdfkit.from_file(html_path, output_pdf)
        print(f"已成功生成销售报告pdf: {output_pdf}")
        
        # 清理临时文件
        os.remove(html_path)
        os.remove(chart_path)
        
        return output_pdf
    except exception as e:
        print(f"生成pdf报告时出错: {e}")
        return none

# 使用示例
sales_data_excel = "sales_data.xlsx"  # 替换为实际的销售数据excel文件路径
output_pdf = "sales_report.pdf"

# generate_sales_report_pdf(sales_data_excel, output_pdf)

通过以上代码示例和应用场景,你可以轻松掌握python pdf文档自动化的各种技巧,大幅提高工作效率。无论是提取文本和图像、合并拆分pdf、添加水印,还是从网页或office文档生成pdf报告,python都能帮你轻松应对。

以上就是python自动化处理pdf文档的操作完整指南的详细内容,更多关于python自动化处理pdf的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com