Python 使用 FPDF 和 OpenPyXL 自动化生成 PDF 文档
前言
在办公场景中,经常需要将 Excel 表格中的数据批量转换为格式固定的 PDF 文档,例如员工工卡、合同书、报表等。手动操作不仅耗时且容易出错,而使用 Python 脚本可以实现自动化处理,大幅提升效率。
本文将以制作员工工卡为例,详细介绍如何利用 Python 的 openpyxl 库读取 Excel 数据,并结合 fpdf 库生成包含图片、文字和边框的 PDF 文档。通过本教程,读者可以掌握办公自动化的核心技能,将重复性劳动转化为代码执行。
环境准备
1. 安装 Python 环境
确保已安装 Python 3.8 及以上版本。可以通过命令行输入 python --version 进行验证。
2. 选择开发工具
推荐使用 Visual Studio Code (VS Code) 作为编辑器,并安装 Python 插件以获得更好的代码提示和调试体验。
3. 安装依赖库
打开终端(Terminal),依次执行以下命令安装所需的第三方库:
pip install openpyxl
pip install fpdf
- openpyxl:用于读写 Excel (.xlsx) 文件。
- fpdf:用于创建和操作 PDF 文件,支持文本、图片和基本图形绘制。
核心实现原理
1. 数据读取 (OpenPyXL)
使用 load_workbook 函数加载 Excel 文件,获取工作表对象。通过遍历行和列,提取单元格中的文本内容(如姓名、部门)和图片文件名。
2. 文档生成 (FPDF)
初始化 FPDF 对象,设置页面尺寸(如 A4)。利用 rect() 绘制边框,text() 或 cell() 输出文本,image() 插入图片。通过循环控制分页逻辑,当一页容纳的员工数量达到上限时,添加新页。
3. 布局与样式
根据实际工卡设计图,计算坐标位置。注意中文字体的嵌入问题,因为 fpdf 默认不支持中文,需要指定 .ttf 字体文件。
完整代码示例
假设 Excel 文件名为 employees.xlsx,第一行为标题,后续每行包含:姓名、职位、照片文件名。照片存放在 images/ 目录下。
from openpyxl import load_workbook
from fpdf import FPDF
import os
class EmployeeCardPDF(FPDF):
def header(self):
# 可选:在每个页面顶部添加统一信息
pass
def ():
.set_y(-)
.cell(, , , , , )
():
wb = load_workbook(filename=excel_path)
ws = wb.active
pdf = EmployeeCardPDF()
pdf.add_page()
pdf.set_auto_page_break(auto=, margin=)
:
pdf.add_font(, , , uni=)
pdf.set_font(, size=)
Exception e:
()
row_count =
employees_per_page =
row ws.iter_rows(min_row=, values_only=):
name_cell = row[].value
pos_cell = row[].value
img_name = row[].value
name_cell:
row_count > row_count % employees_per_page == :
pdf.add_page()
pdf.set_font(, size=)
x_pos = + (row_count % ) *
y_pos = + (row_count // ) *
pdf.set_xy(x_pos, y_pos)
pdf.rect(x_pos, y_pos, , , style=)
img_path = os.path.join(image_dir, (img_name))
os.path.exists(img_path):
pdf.image(img_path, x=x_pos + , y=y_pos + , w=, h=)
:
pdf.text(x_pos + , y_pos + , )
pdf.set_xy(x_pos + , y_pos + )
pdf.cell(, , txt=, ln=, align=)
pdf.set_xy(x_pos + , y_pos + )
pdf.cell(, , txt=, ln=, align=)
row_count +=
pdf.output(output_path)
()
__name__ == :
generate_pdf(
excel_path=,
image_dir=,
output_path=
)


