Python 处理 PDF 文件(PyPDF2, ReportLab)

Python 是一门强大的编程语言,在处理PDF文件方面有着丰富的库支持,其中最常用的两个库是 PyPDF2ReportLabPyPDF2 主要用于读取、拆分、合并和修改已有的PDF文件,而 ReportLab 则擅长生成新的PDF文件。

一、PyPDF2

1. PyPDF2 概述

PyPDF2 是一个纯 Python 库,主要用于操作已有的 PDF 文件。它的功能包括从 PDF 中提取文本、合并多个 PDF 文件、拆分 PDF 文件、旋转页面、添加书签和注释等。然而,由于 PDF 文件格式复杂,PyPDF2 在处理某些复杂或加密的 PDF 文件时可能会遇到限制。

2. 安装 PyPDF2

在使用 PyPDF2 之前,你需要确保已安装它。可以通过 pip 安装:

bash 复制代码
pip install PyPDF2

3. PyPDF2 的基本操作

3.1 读取 PDF 文件

PyPDF2 提供了 PdfReader 类来读取 PDF 文件。你可以通过以下代码读取一个 PDF 文件:

python 复制代码
from PyPDF2 import PdfReader

# 打开 PDF 文件
with open('example.pdf', 'rb') as file:
    reader = PdfReader(file)
    
    # 获取 PDF 文件的总页数
    num_pages = len(reader.pages)
    print(f"Total pages: {num_pages}")

    # 提取第1页的文本内容
    page = reader.pages[0]
    text = page.extract_text()
    print(text)
3.2 合并 PDF 文件

PyPDF2 可以将多个 PDF 文件合并为一个新文件。使用 PdfWriter 类来完成此操作:

python 复制代码
from PyPDF2 import PdfReader, PdfWriter

# 创建 PdfWriter 对象
writer = PdfWriter()

# 读取并添加 PDF 文件
pdf_files = ['file1.pdf', 'file2.pdf']
for pdf_file in pdf_files:
    reader = PdfReader(pdf_file)
    for page in reader.pages:
        writer.add_page(page)

# 输出合并后的文件
with open('merged.pdf', 'wb') as output_file:
    writer.write(output_file)
3.3 拆分 PDF 文件

拆分 PDF 文件意味着将一个 PDF 文件的每一页保存为单独的文件:

python 复制代码
from PyPDF2 import PdfReader, PdfWriter

# 读取 PDF 文件
with open('example.pdf', 'rb') as file:
    reader = PdfReader(file)
    
    # 循环遍历每一页并创建一个新的 PDF 文件
    for i, page in enumerate(reader.pages):
        writer = PdfWriter()
        writer.add_page(page)
        
        # 保存单独的页面为新 PDF 文件
        output_filename = f'page_{i + 1}.pdf'
        with open(output_filename, 'wb') as output_file:
            writer.write(output_file)
3.4 旋转 PDF 页面

有时你可能需要旋转 PDF 文件中的某一页或所有页面。以下是旋转 PDF 页面的方法:

python 复制代码
from PyPDF2 import PdfReader, PdfWriter

# 打开 PDF 文件
with open('example.pdf', 'rb') as file:
    reader = PdfReader(file)
    writer = PdfWriter()
    
    # 旋转第一页 90 度
    page = reader.pages[0]
    rotated_page = page.rotate_clockwise(90)
    
    # 添加旋转后的页面到 PdfWriter
    writer.add_page(rotated_page)
    
    # 保存新的 PDF 文件
    with open('rotated.pdf', 'wb') as output_file:
        writer.write(output_file)
3.5 添加书签和注释

虽然 PyPDF2 支持添加书签和注释,但其功能较为有限,而且操作相对复杂。PyPDF2 能够处理简单的书签和注释添加,但对于更复杂的需求,可能需要结合其他库。

4. PyPDF2 的局限性

尽管 PyPDF2 提供了丰富的功能,但它在处理一些复杂的 PDF 文件时可能会遇到问题,例如无法正确提取嵌入图像或复杂布局中的文本。此外,PyPDF2 的文本提取功能也有其局限性,尤其是在处理非英文文本时,可能无法准确提取。

二、ReportLab

1. ReportLab 概述

ReportLab 是一个强大的 Python 库,用于生成 PDF 文档。与 PyPDF2 侧重于操作已有的 PDF 文件不同,ReportLab 主要用于创建新 PDF 文件。它可以生成高质量的文档,支持丰富的文本样式、图表、图像和其他元素的插入。

2. 安装 ReportLab

PyPDF2 类似,你可以使用 pip 来安装 ReportLab

python 复制代码
pip install reportlab

3. ReportLab 的基本操作

3.1 创建一个简单的 PDF 文件

使用 ReportLab 创建 PDF 文件通常涉及到 canvas.Canvas 类。以下是一个简单的例子,创建一个包含文本和图像的 PDF 文件:

python 复制代码
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas

# 创建一个 PDF 文件
pdf_file = "example.pdf"
c = canvas.Canvas(pdf_file, pagesize=A4)

# 添加文本
c.drawString(100, 800, "Hello, World!")

# 添加图像
c.drawImage("example.jpg", 100, 700, width=200, height=100)

# 保存 PDF
c.save()
3.2 创建复杂的文档

除了基本的文本和图像,ReportLab 还支持创建复杂的文档,例如带有多种字体、表格、图形、分栏布局等的文档。以下是一个创建带表格的 PDF 的例子:

python 复制代码
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle

# 创建 PDF 文件
pdf_file = "table_example.pdf"
doc = SimpleDocTemplate(pdf_file, pagesize=A4)

# 创建表格数据
data = [
    ["Header 1", "Header 2", "Header 3"],
    ["Row 1 Col 1", "Row 1 Col 2", "Row 1 Col 3"],
    ["Row 2 Col 1", "Row 2 Col 2", "Row 2 Col 3"],
]

# 创建表格对象
table = Table(data)

# 添加样式
style = TableStyle([
    ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
    ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
    ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
    ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
    ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
    ('GRID', (0, 0), (-1, -1), 1, colors.black),
])
table.setStyle(style)

# 构建 PDF
doc.build([table])
3.3 添加不同的字体和样式

ReportLab 提供了丰富的字体和样式选择,使得你可以创建具有各种排版效果的 PDF 文件:

python 复制代码
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer

# 创建 PDF 文件
pdf_file = "styled_text.pdf"
doc = SimpleDocTemplate(pdf_file, pagesize=letter)

# 获取样式表
styles = getSampleStyleSheet()

# 自定义样式
custom_style = ParagraphStyle(
    name="CustomStyle",
    fontName="Helvetica-Bold",
    fontSize=14,
    leading=16,
    textColor=colors.red,
    alignment=1,  # 中心对齐
)

# 创建带样式的文本段落
story = []
text = "This is a styled paragraph."
story.append(Paragraph(text, custom_style))
story.append(Spacer(1, 12))  # 添加间隔

# 构建 PDF
doc.build(story)
3.4 插入图表

ReportLab 还支持生成和插入各种类型的图表,例如柱状图、饼图等。这些图表可以与其他文档元素无缝集成在一起:

python 复制代码
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics.charts.textlabels import Label

# 创建 PDF 文件
pdf_file = "chart_example.pdf"
doc = SimpleDocTemplate(pdf_file, pagesize=letter)

# 创建图表数据
data = [
    (13, 5, 20, 22, 37, 45, 19, 4),
    (14, 6, 21, 23, 38, 46, 20, 5),
]

# 创建绘图对象
drawing = Drawing(400, 200)

# 创建柱状图
chart = VerticalBarChart()
chart.x = 50
chart.y = 50
chart.height = 125
chart.width = 300
chart.data = data
chart.strokeColor = colors.black

# 添加标签
chart.valueAxis.valueMin = 0
chart.valueAxis.valueMax = 50
chart.valueAxis.valueStep = 10
chart.categoryAxis.labels.boxAnchor = 'ne'
chart.categoryAxis.labels.dx = 8
chart.categoryAxis.labels.dy = -2
chart.categoryAxis.labels.angle = 30
chart.categoryAxis.categoryNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug']

# 添加标题
title = Label()
title.setOrigin(200, 180)
title.setText("Monthly Data")
drawing.add(title)

drawing.add(chart)

# 构建 PDF
doc.build([drawing])

4. ReportLab 的扩展与高级功能

ReportLab 还提供了许多扩展功能和高级特性,使得它成为生成复杂 PDF 报告的强大工具。以下是一些 ReportLab 更高级的功能和技巧。

4.1 流式布局(Flowable)

ReportLab 中,流式布局(Flowable)是一种用于在 PDF 文档中插入内容的机制。流式布局元素可以包括段落、图片、表格、图表等。Platypus(Page Layout and Typography Using Scripts)是 ReportLab 提供的一个强大工具,用于将这些流式布局元素组合在一起,生成复杂的文档。

以下是一个包含多个流式布局元素的例子:

python 复制代码
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image
from reportlab.lib.styles import getSampleStyleSheet

# 创建 PDF 文件
pdf_file = "flowable_example.pdf"
doc = SimpleDocTemplate(pdf_file, pagesize=letter)

# 获取样式表
styles = getSampleStyleSheet()

# 创建文档元素
story = []

# 添加段落
paragraph = Paragraph("This is a paragraph.", styles['Normal'])
story.append(paragraph)
story.append(Spacer(1, 12))

# 添加图片
image = Image("example.jpg")
story.append(image)
story.append(Spacer(1, 12))

# 添加另一段落
paragraph = Paragraph("This is another paragraph after the image.", styles['Normal'])
story.append(paragraph)

# 构建 PDF
doc.build(story)
4.2 自定义报表生成

在企业环境中,经常需要生成包含公司标志、表格、图表等元素的定制报告。ReportLab 可以通过组合不同的流式布局元素、添加页眉页脚以及插入公司标志来生成此类报告。

以下是一个包含页眉和页脚的自定义报告例子:

python 复制代码
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.platypus.frames import Frame
from reportlab.platypus.doctemplate import PageTemplate
from reportlab.lib.styles import getSampleStyleSheet

# 页眉页脚的生成函数
def add_page_number(canvas, doc):
    page_number_text = f"Page {doc.page}"
    canvas.drawRightString(200 * mm, 10 * mm, page_number_text)

# 自定义的页眉
def header_footer(canvas, doc):
    canvas.saveState()
    canvas.setFont('Helvetica', 10)
    canvas.drawString(inch, 11 * inch, "Company Header")
    canvas.line(inch, 10.75 * inch, 7.5 * inch, 10.75 * inch)
    add_page_number(canvas, doc)
    canvas.restoreState()

# 创建 PDF 文件
pdf_file = "custom_report.pdf"
doc = SimpleDocTemplate(pdf_file, pagesize=letter)

# 设置页眉页脚模板
frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal')
template = PageTemplate(id='test', frames=frame, onPage=header_footer)
doc.addPageTemplates([template])

# 获取样式表
styles = getSampleStyleSheet()

# 创建内容
story = [Paragraph("This is the content of the report.", styles['Normal']),
         Spacer(1, 12),
         Paragraph("More content on the next line.", styles['Normal'])]

# 构建 PDF
doc.build(story)

在这个例子中,我们使用 header_footer 函数为每一页添加页眉和页脚。这种方法非常灵活,可以根据具体需求定制不同的页面布局。

4.3 生成图表和插入动态数据

ReportLab 提供的 reportlab.graphics 模块可以生成各种图表,包括柱状图、饼图、折线图等。这些图表可以通过程序动态生成,并插入到 PDF 文档中。例如,你可以从数据库或 API 中获取数据,然后将数据以图表的形式展示在 PDF 中。

以下是生成折线图并插入到 PDF 的示例:

python 复制代码
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.linecharts import HorizontalLineChart
from reportlab.graphics.widgets.markers import makeMarker
from reportlab.lib import colors

# 创建 PDF 文件
pdf_file = "line_chart.pdf"
doc = SimpleDocTemplate(pdf_file, pagesize=letter)

# 创建图表数据
data = [
    (10, 20, 30, 40, 50),
    (15, 25, 35, 45, 55),
]

# 创建绘图对象
drawing = Drawing(400, 200)

# 创建折线图
chart = HorizontalLineChart()
chart.x = 50
chart.y = 50
chart.height = 125
chart.width = 300
chart.data = data

# 配置折线图
chart.lines[0].strokeColor = colors.blue
chart.lines[1].strokeColor = colors.green
chart.lineLabelFormat = '%2.0f'

# 添加数据点标记
chart.lines[0].symbol = makeMarker('Circle')
chart.lines[1].symbol = makeMarker('Square')

# 设置轴和标签
chart.categoryAxis.categoryNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May']
chart.categoryAxis.labels.boxAnchor = 'n'

drawing.add(chart)

# 构建 PDF
doc.build([drawing])

这个例子展示了如何生成一个简单的折线图。ReportLab 的图表模块非常灵活,可以满足各种定制需求。

4.4 使用 ReportLab 生成动态PDF表单

ReportLab 可以生成包含表单字段的 PDF 文件,例如文本框、复选框和下拉列表。这些表单字段可以在生成后由用户在 PDF 阅读器中填写。

python 复制代码
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas

# 创建 PDF 文件
pdf_file = "form_example.pdf"
c = canvas.Canvas(pdf_file, pagesize=letter)

# 创建文本框
c.drawString(100, 700, "Name:")
c.textfield(name='name_field', tooltip='Your Name', x=150, y=700, width=200)

# 创建复选框
c.drawString(100, 650, "Subscribe:")
c.checkbox(name='subscribe', tooltip='Subscribe to Newsletter', x=150, y=650, buttonStyle='check')

# 创建下拉列表
c.drawString(100, 600, "Gender:")
c.choice(name='gender', tooltip='Select Gender', x=150, y=600, width=100, options=['Male', 'Female'])

# 保存 PDF
c.save()

生成的 PDF 文件可以通过 PDF 阅读器(如 Adobe Acrobat Reader)进行交互。这对于创建需要用户输入的文档或问卷非常有用。

4.5 使用模板生成 PDF

在某些情况下,你可能需要基于模板生成多个相似的 PDF 文件。ReportLab 支持通过预定义的模板来快速生成带有动态内容的 PDF。例如,使用 platypus 模块和自定义样式表生成包含多个动态内容的复杂报告。

python 复制代码
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet

# 创建 PDF 文件
pdf_file = "templated_report.pdf"
doc = SimpleDocTemplate(pdf_file, pagesize=letter)

# 获取样式表
styles = getSampleStyleSheet()

# 创建内容模板
story = []

# 模板内容示例
for i in range(1, 11):
    story.append(Paragraph(f"Report Section {i}", styles['Heading1']))
    story.append(Paragraph(f"This is the content of section {i}.", styles['Normal']))
    story.append(PageBreak())  # 添加分页符

# 构建 PDF
doc.build(story)

这个例子展示了如何使用循环生成多个具有相似结构的报告部分,并自动分页。这种方法特别适合批量生成相似结构的文档,如发票、成绩单或报告。

5. ReportLab 的高级功能总结

ReportLab 不仅仅是一个 PDF 生成工具,它更像是一个强大的排版引擎。它的高级功能使得开发者可以创建非常复杂且高度定制化的文档,包括企业报表、交互式表单、可视化数据报告等。通过 ReportLab,你几乎可以生成任何类型的 PDF 文档,并将它们与动态数据源无缝集成。

三、PyPDF2 与 ReportLab 的综合使用

在实际应用中,PyPDF2ReportLab 通常可以结合使用。你可以使用 ReportLab 生成 PDF 文件,然后使用 PyPDF2 对生成的 PDF 进行后续处理,如合并、拆分或添加水印。例如,使用 ReportLab 生成报告,然后使用 PyPDF2 合并多个报告或添加页码。

python 复制代码
from PyPDF2 import PdfReader, PdfWriter
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from io import BytesIO

# 使用 ReportLab 创建一个 PDF
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=letter)
c.drawString(100, 100, "This is a dynamically generated PDF.")
c.save()

# 读取生成的 PDF
packet.seek(0)
new_pdf = PdfReader(packet)

# 读取现有的 PDF
existing_pdf = PdfReader(open("existing.pdf", "rb"))

# 创建 PdfWriter 对象
output = PdfWriter()

# 将现有的 PDF 页面与新生成的页面合并
for page_num in range(len(existing_pdf.pages)):
    page = existing_pdf.pages[page_num]
    if page_num == 0:  # 仅将新内容添加到第一页
        page.merge_page(new_pdf.pages[0])
    output.add_page(page)

# 输出合并后的 PDF
with open("merged_output.pdf", "wb") as output_stream:
    output.write(output_stream)

这个例子展示了如何使用 ReportLab 生成动态内容,并将其合并到现有的 PDF 文档中。通过这种方式,你可以实现高度灵活的 PDF 生成与处理工作流。

在处理 PDF 文件时,PyPDF2ReportLab 是两种功能强大的工具。PyPDF2 侧重于对已有 PDF 文件的操作,如读取、拆分、合并和旋转页面等。而 ReportLab 则专注于创建新的 PDF 文件,提供了丰富的功能来生成复杂的报表、图表和交互式表单。

通过掌握这两个库的使用,可以在 Python 中处理几乎所有的 PDF 相关任务。无论是生成定制化的企业报告,还是自动化批量处理 PDF 文件,这两个库都能提供强有力的支持。结合这两者的功能,能够让 PDF 处理领域游刃有余,满足各种实际应用需求。

相关推荐
CodeCraft Studio4 小时前
【实用技能】使用 TX Text Control 创建带有嵌入式附件的 PDF 文档
pdf·asp.net·.net
小小大侠客7 小时前
IText创建加盖公章的pdf文件并生成压缩文件
java·pdf·itext
DevOpenClub11 小时前
PDF 转 HTML API 数据接口
pdf
zhy81030215 小时前
.net6 使用 FreeSpire.XLS 实现 excel 转 pdf - docker 部署
pdf·.net·excel
慧都小妮子16 小时前
Spire.PDF for .NET【页面设置】演示:打开 PDF 时自动显示书签或缩略图
java·pdf·.net
join819 小时前
解决vue-pdf的签章不显示问题
javascript·vue.js·pdf
小行星12519 小时前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
穆友航1 天前
PDF内容提取,MinerU使用
数据分析·pdf
拾荒的小海螺2 天前
JAVA:探索 PDF 文字提取的技术指南
java·开发语言·pdf
村东头老张2 天前
Java 实现PDF添加水印
java·开发语言·pdf