脚本专家 发表于 前天 11:00

Python + Spire.PDF:从JSON自动生成专业PDF报表教

在企业日常运营中,JSON 格式的数据广泛应用于 API 接口、配置文件和数据交换场景。但将结构化的 JSON 数据转换为适合阅读和分发的 PDF 报告,往往需要手动复制粘贴或借助复杂的模板工具,不仅效率低下,还容易出现格式错乱、数据遗漏。对于需要定期生成财务报表、项目进度报告、客户信息汇总等场景,自动化生成 PDF 文档成为提升工作效率的关键需求。

本文将介绍如何使用 Python 从 JSON 数据自动生成格式规范的 PDF 文档,所有代码基于 Free Spire.PDF for Python(
pip install spire.pdf.free
)。整个过程完全自动化,无需人工干预,适用于业务报表生成、数据归档、合同附件制作、API 数据可视化等场景。你可以灵活控制文档布局、字体样式、表格结构和页面元素,确保生成的 PDF 专业美观。


一、准备 JSON 数据并创建 PDF 文档

首先定义示例 JSON 数据(以销售数据报告为例,包含产品信息、销售记录和统计摘要),并初始化 PDF 文档对象。


import json
from spire.pdf import PdfDocument, PdfPageBase
from spire.pdf.graphics import *

json_data = """
{
    "report_title": "2024年第一季度销售报告",
    "company": "ABC科技有限公司",
    "date": "2024-03-31",
    "summary": {
      "total_sales": 1580000,
      "total_orders": 342,
      "average_order_value": 4619.88
    },
    "products": [
      {"name": "笔记本电脑", "category": "电子产品", "quantity": 120, "unit_price": 5999, "total": 719880},
      {"name": "无线鼠标", "category": "配件", "quantity": 450, "unit_price": 89, "total": 40050},
      {"name": "机械键盘", "category": "配件", "quantity": 280, "unit_price": 399, "total": 111720},
      {"name": "显示器", "category": "电子产品", "quantity": 95, "unit_price": 2499, "total": 237405},
      {"name": "USB集线器", "category": "配件", "quantity": 600, "unit_price": 59, "total": 35400}
    ]
}
"""
data = json.loads(json_data)
doc = PdfDocument()
page = doc.Pages.Add()



json.loads()
将 JSON 字符串解析为 Python 字典。
PdfDocument()
创建 PDF 文档对象,
Pages.Add()
添加新页面。示例数据包含报告标题、公司信息、统计摘要和产品列表,模拟真实业务场景。


二、绘制文档标题和公司信息

在页面顶部绘制报告标题和公司基本信息,建立文档的整体框架。


def draw_header(page, data):
    margin_left = 50
    margin_top = 50
    y_position = margin_top

    company_font = PdfTrueTypeFont("Arial", 14.0, PdfFontStyle.Bold, True)
    company_brush = PdfSolidBrush(PdfRGBColor(Color.get_DarkGray()))
    page.Canvas.DrawString(data["company"], company_font, company_brush, margin_left, y_position)
    y_position += 25

    title_font = PdfTrueTypeFont("Arial", 24.0, PdfFontStyle.Bold, True)
    title_brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
    title_format = PdfStringFormat(PdfTextAlignment.Left)
    page.Canvas.DrawString(data["report_title"], title_font, title_brush, margin_left, y_position, title_format)
    y_position += 35

    date_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Regular, True)
    date_brush = PdfSolidBrush(PdfRGBColor(Color.get_Gray()))
    page.Canvas.DrawString(f"报告日期:{data['date']}", date_font, date_brush, margin_left, y_position)
    return y_position + 30

current_y = draw_header(page, data)



PdfTrueTypeFont
设置字体名称、大小和样式(如 Bold)。
PdfSolidBrush
定义文本颜色,
DrawString
在指定坐标绘制文本,可配合
PdfStringFormat
设置对齐方式。通过递增 y_position 实现垂直布局,避免重叠。


三、绘制统计摘要信息

在标题下方展示关键的业务统计数据,以简洁方式呈现核心指标。


def draw_summary(page, data, y_position):
    margin_left = 50
    summary = data["summary"]

    section_font = PdfTrueTypeFont("Arial", 16.0, PdfFontStyle.Bold, True)
    section_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    page.Canvas.DrawString("销售摘要", section_font, section_brush, margin_left, y_position)
    y_position += 30

    content_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Regular, True)
    content_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    summary_items = [
      f"总销售额:¥{summary['total_sales']:,.2f}",
      f"订单总数:{summary['total_orders']}",
      f"平均订单价值:¥{summary['average_order_value']:,.2f}"
    ]
    for item in summary_items:
      page.Canvas.DrawString(item, content_font, content_brush, margin_left, y_position)
      y_position += 22
    return y_position + 20

current_y = draw_summary(page, data, current_y)


使用 f-string 格式化数字,
:,
添加千位分隔符,
.2f
保留两位小数。摘要信息逐行排列,间隔 22 个单位,形成清晰的信息层级。


四、创建产品明细表格

表格是展示结构化数据的最佳方式。将 JSON 中的产品列表转换为 PDF 表格,包含表头和数据行。


def draw_product_table(page, data, y_position):
    margin_left = 50
    products = data["products"]

    table_title_font = PdfTrueTypeFont("Arial", 16.0, PdfFontStyle.Bold, True)
    table_title_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    page.Canvas.DrawString("产品明细", table_title_font, table_title_brush, margin_left, y_position)
    y_position += 30

    columns = ["产品名称", "类别", "数量", "单价", "总价"]
    column_widths =

    header_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Bold, True)
    header_brush = PdfSolidBrush(PdfRGBColor(Color.get_White()))
    header_bg_brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
    x_position = margin_left
    for i, col in enumerate(columns):
      rect = RectangleF(x_position, y_position, column_widths, 25)
      page.Canvas.DrawRectangle(header_bg_brush, rect)
      page.Canvas.DrawString(col, header_font, header_brush, x_position + 5, y_position + 5)
      x_position += column_widths
    y_position += 25

    row_font = PdfTrueTypeFont("Arial", 10.0, PdfFontStyle.Regular, True)
    row_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    alternate_brush = PdfSolidBrush(PdfRGBColor(Color.get_LightGray()))
    for idx, product in enumerate(products):
      bg_brush = PdfSolidBrush(PdfRGBColor(Color.get_White())) if idx % 2 == 0 else alternate_brush
      x_position = margin_left
      row_height = 22
      row_rect = RectangleF(margin_left, y_position, sum(column_widths), row_height)
      page.Canvas.DrawRectangle(bg_brush, row_rect)
      cell_data = [
            product["name"],
            product["category"],
            str(product["quantity"]),
            f"¥{product['unit_price']:,}",
            f"¥{product['total']:,}"
      ]
      for i, cell_value in enumerate(cell_data):
            page.Canvas.DrawString(cell_value, row_font, row_brush, x_position + 5, y_position + 4)
            x_position += column_widths
      y_position += row_height

    border_pen = PdfPen(PdfRGBColor(Color.get_Black()), 0.5)
    table_width = sum(column_widths)
    table_height = 25 + len(products) * 22
    page.Canvas.DrawRectangle(border_pen, RectangleF(margin_left, y_position - table_height, table_width, table_height))
    # 横线
    for i in range(len(products) + 2):
      if i == 0:
            line_y = y_position - table_height
      elif i == 1:
            line_y = y_position - table_height + 25
      else:
            line_y = y_position - table_height + 25 + (i - 1) * 22
      page.Canvas.DrawLine(border_pen, margin_left, line_y, margin_left + table_width, line_y)
    # 竖线
    x_pos = margin_left
    for width in column_widths:
      page.Canvas.DrawLine(border_pen, x_pos, y_position - table_height, x_pos, y_position)
      x_pos += width
    page.Canvas.DrawLine(border_pen, x_pos, y_position - table_height, x_pos, y_position)
    return y_position + 30

current_y = draw_product_table(page, data, current_y)


表格采用表头深色背景、白色文字的设计,数据行使用交替背景色(白色和浅灰色),提升视觉区分度。
RectangleF
用于绘制矩形区域,
DrawLine
绘制横线和竖线形成网格。列宽根据内容长度合理分配。


五、添加页脚信息

在页面底部添加页脚,包含页码和版权信息,使文档更完整专业。


def draw_footer(page, page_number, total_pages):
    page_width = page.Canvas.ClientSize.Width
    margin_bottom = 30
    line_pen = PdfPen(PdfRGBColor(Color.get_LightGray()), 0.5)
    page.Canvas.DrawLine(line_pen, 50, page.Canvas.ClientSize.Height - margin_bottom - 15, page_width - 50, page.Canvas.ClientSize.Height - margin_bottom - 15)
    footer_font = PdfTrueTypeFont("Arial", 9.0, PdfFontStyle.Regular, True)
    footer_brush = PdfSolidBrush(PdfRGBColor(Color.get_Gray()))
    footer_format = PdfStringFormat(PdfTextAlignment.Center)
    page_text = f"第 {page_number} 页 / 共 {total_pages} 页"
    page.Canvas.DrawString(page_text, footer_font, footer_brush, page_width / 2, page.Canvas.ClientSize.Height - margin_bottom, footer_format)
    copyright_text = "© 2024 ABC科技有限公司 - 内部资料,请勿外传"
    page.Canvas.DrawString(copyright_text, footer_font, footer_brush, page_width / 2, page.Canvas.ClientSize.Height - margin_bottom + 15, footer_format)

draw_footer(page, 1, 1)


页脚包含水平分隔线、页码和版权声明,居中对齐,字体较小颜色较浅,不影响主内容。


六、保存 PDF 文档


output_file = "销售报告.pdf"
doc.SaveToFile(output_file)
doc.Close()
print(f"PDF 文档已生成:{output_file}")



SaveToFile
将内存中的 PDF 文档保存到文件系统,
Close
释放资源。


关键类与方法解析

主要类说明

[*]PdfDocument:PDF 文档对象,管理整个文档生命周期
[*]PdfPageBase:页面对象,提供画布用于绘制内容
[*]PdfTrueTypeFont:字体类,设置字体名称、大小、样式
[*]PdfSolidBrush:画刷类,定义填充颜色
[*]PdfPen:画笔类,定义线条颜色和宽度
[*]PdfStringFormat:文本格式类,设置对齐方式等
[*]RectangleF:矩形结构,定义绘制区域
[*]PdfRGBColor:颜色类,支持 RGB 色彩模式


常用方法

[*]
doc.Pages.Add()
:添加新页面
[*]
page.Canvas.DrawString(text, font, brush, x, y, format)
:绘制文本
[*]
page.Canvas.DrawRectangle(brush/pen, rectangle)
:绘制矩形
[*]
page.Canvas.DrawLine(pen, x1, y1, x2, y2)
:绘制直线
[*]
doc.SaveToFile(filename)
:保存文档
[*]
doc.Close()
:关闭文档释放资源


字体与样式设置

# 创建字体
font = PdfTrueTypeFont("Arial", 12.0, PdfFontStyle.Bold, True)
# 参数:字体名称、字号、样式(Bold/Italic/Regular/Underline)、是否嵌入

# 创建画刷
brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
# 支持的颜色:get_Black(), get_White(), get_Red(), get_Blue(), get_Navy() 等

# 创建画笔
pen = PdfPen(PdfRGBColor(Color.get_Black()), 0.5)

# 设置文本格式
format = PdfStringFormat(PdfTextAlignment.Center, PdfVerticalAlignment.Middle)


布局技巧

[*]垂直布局:递增 y 坐标实现从上到下排列
[*]水平布局:递增 x 坐标实现从左到右排列
[*]边距控制:设置 margin_left、margin_top 等变量统一管理
[*]间距调整:根据字体高度和内容重要性调整行间距



扩展应用场景

1. 多页文档支持
当数据量较大时,需自动分页:

if current_y > page.Canvas.ClientSize.Height - 100:
    page = doc.Pages.Add()
    current_y = 50


2. 从文件读取 JSON

with open('sales_data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)


3. 添加图表可视化(简单柱状图)

for i, product in enumerate(products):
    bar_height = product['total'] / 10000
    bar_rect = RectangleF(margin_left + i * 60, chart_y, 50, bar_height)
    page.Canvas.DrawRectangle(bar_brush, bar_rect)


4. 批量生成报告

import glob
for json_file in glob.glob('reports/*.json'):
    with open(json_file, 'r') as f:
      data = json.load(f)
    generate_pdf(data, f"report_{json_file}.pdf")


5. 自定义模板系统

class PDFTemplate:
    def __init__(self, config):
      self.font_config = config['fonts']
      self.color_scheme = config['colors']
      self.layout = config['layout']
    def render(self, data):
      # 根据配置渲染 PDF
      pass



总结

通过本文示例,你已掌握使用 Python 从 JSON 数据自动生成专业 PDF 文档的完整流程:解析 JSON 数据结构 → 绘制标题、摘要、表格和页脚 → 保存文件。整个过程完全自动化,特别适用于业务报表、数据归档和文档分发场景。

相比手动制作 PDF,代码方式具有显著优势:高效性(一键生成)、一致性(统一格式和样式)、灵活性(根据数据动态调整布局)、可扩展性(轻松集成到现有系统)。在此基础上,可以进一步探索添加水印、加密文档、插入图像、生成目录等高级功能,为企业级文档自动化提供完整解决方案。

热心网友6 发表于 前天 11:05

Re: Python + Spire.PDF:从JSON自动生成专业PDF报表教

感谢分享,这个教程非常实用!我之前手工做报表经常出格式问题,正需要这种自动化的方案。想请教一下,示例里的 JSON 包含中文内容,代码中用 Arial 字体绘制标题,但 Arial 对中文支持可能不够完整,是否需要额外加载中文字体文件才能正常显示?另外期待后续完整代码,特别是表格和统计数据的绘制部分,想看看具体怎么布局。

热心网友6 发表于 前天 11:05

Re: Python + Spire.PDF:从JSON自动生成专业PDF报表教

感谢分享这个实用的自动化方案!用 JSON 直接生成 PDF 报表确实是很多企业场景的刚需,省去手动排版和复制的麻烦。我注意到示例中数据包含中文,字体用了 Arial,但 Arial 似乎对中文支持有限,实际运行时会不会出现乱码?另外,如果 JSON 里产品数量很多、一页放不下,Spire.PDF 有没有现成的方法支持分页,还是需要自己计算 Y 坐标手动换页?想请教一下你的实现思路。期待后续更完整的代码示例!

热心网友6 发表于 前天 11:05

Re: Python + Spire.PDF:从JSON自动生成专业PDF报表教

感谢分享,这个方案非常实用!JSON转PDF确实是很多报表自动化的痛点,你的代码结构清晰,尤其是字体、颜色和位置的设定很规范,直接套用就能跑通。想请教一下,如果JSON数据量很大(比如产品列表超过一页),你是打算如何处理分页的?另外Free Spire.PDF对中文字体的支持需要额外配置吗?期待你的后续内容,比如表格绘制和页码添加的部分。
页: [1]
查看完整版本: Python + Spire.PDF:从JSON自动生成专业PDF报表教