查看: 100|回复: 3

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

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

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



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

首先定义示例 JSON 数据(以销售数据报告为例,包含产品信息、销售记录和统计摘要),并初始化 PDF 文档对象。
  1. import json
  2. from spire.pdf import PdfDocument, PdfPageBase
  3. from spire.pdf.graphics import *
  4. json_data = """
  5. {
  6.     "report_title": "2024年第一季度销售报告",
  7.     "company": "ABC科技有限公司",
  8.     "date": "2024-03-31",
  9.     "summary": {
  10.         "total_sales": 1580000,
  11.         "total_orders": 342,
  12.         "average_order_value": 4619.88
  13.     },
  14.     "products": [
  15.         {"name": "笔记本电脑", "category": "电子产品", "quantity": 120, "unit_price": 5999, "total": 719880},
  16.         {"name": "无线鼠标", "category": "配件", "quantity": 450, "unit_price": 89, "total": 40050},
  17.         {"name": "机械键盘", "category": "配件", "quantity": 280, "unit_price": 399, "total": 111720},
  18.         {"name": "显示器", "category": "电子产品", "quantity": 95, "unit_price": 2499, "total": 237405},
  19.         {"name": "USB集线器", "category": "配件", "quantity": 600, "unit_price": 59, "total": 35400}
  20.     ]
  21. }
  22. """
  23. data = json.loads(json_data)
  24. doc = PdfDocument()
  25. page = doc.Pages.Add()
复制代码
  1. json.loads()
复制代码
将 JSON 字符串解析为 Python 字典。
  1. PdfDocument()
复制代码
创建 PDF 文档对象,
  1. Pages.Add()
复制代码
添加新页面。示例数据包含报告标题、公司信息、统计摘要和产品列表,模拟真实业务场景。



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

在页面顶部绘制报告标题和公司基本信息,建立文档的整体框架。
  1. def draw_header(page, data):
  2.     margin_left = 50
  3.     margin_top = 50
  4.     y_position = margin_top
  5.     company_font = PdfTrueTypeFont("Arial", 14.0, PdfFontStyle.Bold, True)
  6.     company_brush = PdfSolidBrush(PdfRGBColor(Color.get_DarkGray()))
  7.     page.Canvas.DrawString(data["company"], company_font, company_brush, margin_left, y_position)
  8.     y_position += 25
  9.     title_font = PdfTrueTypeFont("Arial", 24.0, PdfFontStyle.Bold, True)
  10.     title_brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
  11.     title_format = PdfStringFormat(PdfTextAlignment.Left)
  12.     page.Canvas.DrawString(data["report_title"], title_font, title_brush, margin_left, y_position, title_format)
  13.     y_position += 35
  14.     date_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Regular, True)
  15.     date_brush = PdfSolidBrush(PdfRGBColor(Color.get_Gray()))
  16.     page.Canvas.DrawString(f"报告日期:{data['date']}", date_font, date_brush, margin_left, y_position)
  17.     return y_position + 30
  18. current_y = draw_header(page, data)
复制代码
  1. PdfTrueTypeFont
复制代码
设置字体名称、大小和样式(如 Bold)。
  1. PdfSolidBrush
复制代码
定义文本颜色,
  1. DrawString
复制代码
在指定坐标绘制文本,可配合
  1. PdfStringFormat
复制代码
设置对齐方式。通过递增 y_position 实现垂直布局,避免重叠。



三、绘制统计摘要信息

在标题下方展示关键的业务统计数据,以简洁方式呈现核心指标。
  1. def draw_summary(page, data, y_position):
  2.     margin_left = 50
  3.     summary = data["summary"]
  4.     section_font = PdfTrueTypeFont("Arial", 16.0, PdfFontStyle.Bold, True)
  5.     section_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
  6.     page.Canvas.DrawString("销售摘要", section_font, section_brush, margin_left, y_position)
  7.     y_position += 30
  8.     content_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Regular, True)
  9.     content_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
  10.     summary_items = [
  11.         f"总销售额:¥{summary['total_sales']:,.2f}",
  12.         f"订单总数:{summary['total_orders']}",
  13.         f"平均订单价值:¥{summary['average_order_value']:,.2f}"
  14.     ]
  15.     for item in summary_items:
  16.         page.Canvas.DrawString(item, content_font, content_brush, margin_left, y_position)
  17.         y_position += 22
  18.     return y_position + 20
  19. current_y = draw_summary(page, data, current_y)
复制代码

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



四、创建产品明细表格

表格是展示结构化数据的最佳方式。将 JSON 中的产品列表转换为 PDF 表格,包含表头和数据行。
  1. def draw_product_table(page, data, y_position):
  2.     margin_left = 50
  3.     products = data["products"]
  4.     table_title_font = PdfTrueTypeFont("Arial", 16.0, PdfFontStyle.Bold, True)
  5.     table_title_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
  6.     page.Canvas.DrawString("产品明细", table_title_font, table_title_brush, margin_left, y_position)
  7.     y_position += 30
  8.     columns = ["产品名称", "类别", "数量", "单价", "总价"]
  9.     column_widths = [120, 100, 80, 100, 100]
  10.     header_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Bold, True)
  11.     header_brush = PdfSolidBrush(PdfRGBColor(Color.get_White()))
  12.     header_bg_brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
  13.     x_position = margin_left
  14.     for i, col in enumerate(columns):
  15.         rect = RectangleF(x_position, y_position, column_widths[i], 25)
  16.         page.Canvas.DrawRectangle(header_bg_brush, rect)
  17.         page.Canvas.DrawString(col, header_font, header_brush, x_position + 5, y_position + 5)
  18.         x_position += column_widths[i]
  19.     y_position += 25
  20.     row_font = PdfTrueTypeFont("Arial", 10.0, PdfFontStyle.Regular, True)
  21.     row_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
  22.     alternate_brush = PdfSolidBrush(PdfRGBColor(Color.get_LightGray()))
  23.     for idx, product in enumerate(products):
  24.         bg_brush = PdfSolidBrush(PdfRGBColor(Color.get_White())) if idx % 2 == 0 else alternate_brush
  25.         x_position = margin_left
  26.         row_height = 22
  27.         row_rect = RectangleF(margin_left, y_position, sum(column_widths), row_height)
  28.         page.Canvas.DrawRectangle(bg_brush, row_rect)
  29.         cell_data = [
  30.             product["name"],
  31.             product["category"],
  32.             str(product["quantity"]),
  33.             f"¥{product['unit_price']:,}",
  34.             f"¥{product['total']:,}"
  35.         ]
  36.         for i, cell_value in enumerate(cell_data):
  37.             page.Canvas.DrawString(cell_value, row_font, row_brush, x_position + 5, y_position + 4)
  38.             x_position += column_widths[i]
  39.         y_position += row_height
  40.     border_pen = PdfPen(PdfRGBColor(Color.get_Black()), 0.5)
  41.     table_width = sum(column_widths)
  42.     table_height = 25 + len(products) * 22
  43.     page.Canvas.DrawRectangle(border_pen, RectangleF(margin_left, y_position - table_height, table_width, table_height))
  44.     # 横线
  45.     for i in range(len(products) + 2):
  46.         if i == 0:
  47.             line_y = y_position - table_height
  48.         elif i == 1:
  49.             line_y = y_position - table_height + 25
  50.         else:
  51.             line_y = y_position - table_height + 25 + (i - 1) * 22
  52.         page.Canvas.DrawLine(border_pen, margin_left, line_y, margin_left + table_width, line_y)
  53.     # 竖线
  54.     x_pos = margin_left
  55.     for width in column_widths:
  56.         page.Canvas.DrawLine(border_pen, x_pos, y_position - table_height, x_pos, y_position)
  57.         x_pos += width
  58.     page.Canvas.DrawLine(border_pen, x_pos, y_position - table_height, x_pos, y_position)
  59.     return y_position + 30
  60. current_y = draw_product_table(page, data, current_y)
复制代码

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



五、添加页脚信息

在页面底部添加页脚,包含页码和版权信息,使文档更完整专业。
  1. def draw_footer(page, page_number, total_pages):
  2.     page_width = page.Canvas.ClientSize.Width
  3.     margin_bottom = 30
  4.     line_pen = PdfPen(PdfRGBColor(Color.get_LightGray()), 0.5)
  5.     page.Canvas.DrawLine(line_pen, 50, page.Canvas.ClientSize.Height - margin_bottom - 15, page_width - 50, page.Canvas.ClientSize.Height - margin_bottom - 15)
  6.     footer_font = PdfTrueTypeFont("Arial", 9.0, PdfFontStyle.Regular, True)
  7.     footer_brush = PdfSolidBrush(PdfRGBColor(Color.get_Gray()))
  8.     footer_format = PdfStringFormat(PdfTextAlignment.Center)
  9.     page_text = f"第 {page_number} 页 / 共 {total_pages} 页"
  10.     page.Canvas.DrawString(page_text, footer_font, footer_brush, page_width / 2, page.Canvas.ClientSize.Height - margin_bottom, footer_format)
  11.     copyright_text = "© 2024 ABC科技有限公司 - 内部资料,请勿外传"
  12.     page.Canvas.DrawString(copyright_text, footer_font, footer_brush, page_width / 2, page.Canvas.ClientSize.Height - margin_bottom + 15, footer_format)
  13. draw_footer(page, 1, 1)
复制代码

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



六、保存 PDF 文档
  1. output_file = "销售报告.pdf"
  2. doc.SaveToFile(output_file)
  3. doc.Close()
  4. print(f"PDF 文档已生成:{output_file}")
复制代码
  1. SaveToFile
复制代码
将内存中的 PDF 文档保存到文件系统,
  1. Close
复制代码
释放资源。



关键类与方法解析

主要类说明

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


常用方法

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


字体与样式设置
  1. # 创建字体
  2. font = PdfTrueTypeFont("Arial", 12.0, PdfFontStyle.Bold, True)
  3. # 参数:字体名称、字号、样式(Bold/Italic/Regular/Underline)、是否嵌入
  4. # 创建画刷
  5. brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
  6. # 支持的颜色:get_Black(), get_White(), get_Red(), get_Blue(), get_Navy() 等
  7. # 创建画笔
  8. pen = PdfPen(PdfRGBColor(Color.get_Black()), 0.5)
  9. # 设置文本格式
  10. format = PdfStringFormat(PdfTextAlignment.Center, PdfVerticalAlignment.Middle)
复制代码

布局技巧

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




扩展应用场景

1. 多页文档支持
当数据量较大时,需自动分页:
  1. if current_y > page.Canvas.ClientSize.Height - 100:
  2.     page = doc.Pages.Add()
  3.     current_y = 50
复制代码

2. 从文件读取 JSON
  1. with open('sales_data.json', 'r', encoding='utf-8') as f:
  2.     data = json.load(f)
复制代码

3. 添加图表可视化(简单柱状图)
  1. for i, product in enumerate(products):
  2.     bar_height = product['total'] / 10000
  3.     bar_rect = RectangleF(margin_left + i * 60, chart_y, 50, bar_height)
  4.     page.Canvas.DrawRectangle(bar_brush, bar_rect)
复制代码

4. 批量生成报告
  1. import glob
  2. for json_file in glob.glob('reports/*.json'):
  3.     with open(json_file, 'r') as f:
  4.         data = json.load(f)
  5.     generate_pdf(data, f"report_{json_file}.pdf")
复制代码

5. 自定义模板系统
  1. class PDFTemplate:
  2.     def __init__(self, config):
  3.         self.font_config = config['fonts']
  4.         self.color_scheme = config['colors']
  5.         self.layout = config['layout']
  6.     def render(self, data):
  7.         # 根据配置渲染 PDF
  8.         pass
复制代码



总结

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

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

使用道具 举报

发表于 1 小时前 | 显示全部楼层

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

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

使用道具 举报

发表于 1 小时前 | 显示全部楼层

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

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

使用道具 举报

发表于 1 小时前 | 显示全部楼层

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

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

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-11 12:07 , Processed in 0.035532 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部