python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python生成Word文档

Python从零快速生成带页码页眉的Word文档教程

作者:大丸子

这篇文章主要为大家详细介绍了Python如何从零快速生成带页码页眉的Word文档,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解下

在代码里创建 Word 文档,操作的不是一段连续的文本流,而是一棵对象树。这个区别决定了很多 API 的形态:页边距设置落在 Section 上而非 Paragraph 上,图片的尺寸要在 DocPicture 对象上设,表格的行列需要通过 Rows 和 Cells 逐级访问。把这棵树的结构理清,创建文档就变成按顺序往正确的节点上挂内容。

用 Spire.Doc for Python 从零装配一份两页的项目交付报告:封面、概览、里程碑表格、指标列表与签署段落,配页眉、页脚与"Page X of Y"页码。

pip install Spire.Doc.Free

演示产物是一份英文的项目交付报告(Northwind Pay App v3.2),封面页加一页正文,含 5 行 3 列的里程碑表格与 4 条编号指标。

Document、Section 与 Paragraph

三个层级自上而下:Document 是文档容器,Section 提供页面级设置并承载内容,Paragraph 是块级单位。

from spire.doc import *
from spire.doc.common import *

doc = Document()
section = doc.AddSection()

title = section.AddParagraph()
title.AppendText("Delivery Report").CharacterFormat.FontSize = 22
title.Format.HorizontalAlignment = HorizontalAlignment.Center

heading = section.AddParagraph()
heading.AppendText("Overview")
heading.ApplyStyle(BuiltinStyle.Heading1)

body = section.AddParagraph()
run = body.AppendText("The release was delivered on 2026-10-20 with all acceptance tests passed.")
run.CharacterFormat.FontName = "Calibri"
run.CharacterFormat.FontSize = 11
# 1.5 倍行距:先设规则,再按磅赋值(单倍 = 12 磅,1.5 倍写 18.0)
body.Format.LineSpacingRule = LineSpacingRule.Multiple
body.Format.LineSpacing = 18.0
body.Format.SetFirstLineIndent(21.0)

doc.SaveToFile("basic_document.docx", FileFormat.Docx2016)
print(f"paragraphs={doc.Sections[0].Paragraphs.Count} pages={doc.GetPageCount()}")
doc.Close()

AddSection() 之后,所有内容都通过 section.AddParagraph() 进入文档。AppendText() 的返回值是一个 TextRange 对象——文本本身是段落里的一个子对象,字符级格式(字体、字号、颜色)就设在它上面。段落级格式(对齐、行距、缩进)设在 paragraph.Format 上。两层分开,是后面很多设置能各归其位的原因。

实测输出:

paragraphs=4 pages=1

SetFirstLineIndent 的单位是磅。中文正文常用的首行缩进两个字符,在 10.5 磅字号下就是 21 磅。

字符格式与段落格式

字符格式挂在 TextRange.CharacterFormat,段落格式挂在 paragraph.Format。

run.CharacterFormat.FontName = "Calibri"
run.CharacterFormat.FontNameFarEast = "SimSun"
run.CharacterFormat.FontSize = 11
run.CharacterFormat.Bold = True
run.CharacterFormat.TextColor = Color.FromArgb(255, 31, 78, 121)

para.Format.HorizontalAlignment = HorizontalAlignment.Justify
para.Format.LineSpacingRule = LineSpacingRule.Multiple
para.Format.LineSpacing = 18.0
para.Format.BeforeSpacing = 6.0
para.Format.AfterSpacing = 6.0
para.Format.SetFirstLineIndent(21.0)

行距由两个属性共同决定:LineSpacingRule 给出规则,LineSpacing 在该规则下取值。LineSpacingRule.Multiple 时取值以磅计——单倍行距为 12 磅,1.5 倍写 18.0,保存后文档里对应 w:line="360" w:lineRule="auto"。段前段后间距(BeforeSpacing / AfterSpacing)同样以磅为单位,与行距一起决定段落之间的疏密:正文段落给 8 磅段后间距,相邻两段之间就有明确的间隔。

段落样式则用来一次性把整套格式应用到段落。ApplyStyle(BuiltinStyle.Heading1) 引用 Word 的内置样式;要改这套内置样式的定义,在文档级用 doc.AddStyle() 取回样式对象再改:

heading_style = doc.AddStyle(BuiltinStyle.Heading1)
heading_style.CharacterFormat.FontName = "Calibri"
heading_style.CharacterFormat.FontSize = 16
heading_style.CharacterFormat.Bold = True
heading_style.CharacterFormat.TextColor = Color.FromArgb(255, 31, 78, 121)

这里有一个只有实际跑过才清楚的优先级:直接设在 CharacterFormat 上的值优先于段落样式提供的值,段落样式只负责补上没被显式指定的项。实测中先 ApplyStyle(BuiltinStyle.Heading2),再把该段落的 TextRange 字号改成 13,保存后读回是 13——样式里的字号不会覆盖直接设置。需要"样式打底、个别段落微调"时,这个顺序正好合用。

图片与表格

图片通过 AppendPicture() 插入,返回一个 DocPicture 对象。

picture_paragraph = section.AddParagraph()
picture = picture_paragraph.AppendPicture("assets/logo.png")
picture.Width = 150.0
print(f"original 240.0 x 75.0 -> set to {picture.Width} x {picture.Height}")

DocPicture 默认保持原始宽高比:只设 Width,Height 会按原图比例推算出来。实测输出:

original 240.0 x 75.0 -> set to 150.0 x 46.875

原图 240×75,宽缩到 150(比例 0.625),高相应变成 46.875。只给一个维度、让另一个维度自动跟随,是避免图标被拉伸变形的省事做法;若需精确指定两个维度,先把 AspectRatioLocked 置 False 再赋值。

表格用 AddTable() 创建,ResetCells() 一次性划定行列,之后通过 Rows 和 Cells 逐格填充。

table = section.AddTable(True)
table.ResetCells(5, 3)

header_row = table.Rows[0]
header_row.IsHeader = True
header_row.RowFormat.BackColor = Color.get_LightBlue()
for i, name in enumerate(["Milestone", "Owner", "Date"]):
    header_row.Cells[i].CellFormat.VerticalAlignment = VerticalAlignment.Middle
    cell_paragraph = header_row.Cells[i].AddParagraph()
    cell_paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
    cell_paragraph.AppendText(name).CharacterFormat.Bold = True

单元格里的内容是段落,所以每个格子的文字同样通过 AddParagraph().AppendText() 写入——表格本质上是嵌在段落树里的子文档。Rows[0].IsHeader 把首行标为表头行,可随表格跨页重复;底纹用 RowFormat.BackColor 设置。这份五行的表实测为 table rows=5 cols=3 pages=1。

页面设置、页眉页脚与页码

页面相关的参数都挂在 section.PageSetup 上。

section.PageSetup.PageSize = PageSize.A4()
section.PageSetup.Orientation = PageOrientation.Portrait
section.PageSetup.Margins.Top = 72.0
section.PageSetup.Margins.Bottom = 72.0
section.PageSetup.Margins.Left = 89.85
section.PageSetup.Margins.Right = 89.85

边距单位同样是磅,1 磅约 0.3528 毫米,72 磅正好是一英寸。页眉页脚从 section.HeadersFooters 取,Header / Footer 各返回一个区域,往里 AddParagraph() 即可。

section.PageSetup.DifferentFirstPageHeaderFooter = True
hf = section.HeadersFooters

header = hf.Header.AddParagraph()
header_text = header.AppendText("Northwind Pay App v3.2 — Delivery Report")
header_text.CharacterFormat.FontSize = 9
header_text.CharacterFormat.TextColor = Color.get_Gray()
header.Format.Borders.Bottom.BorderType = BorderStyle.Single

footer = hf.Footer.AddParagraph()
footer.AppendText("Page ")
footer.AppendField("page number", FieldType.FieldPage)
footer.AppendText(" of ")
footer.AppendField("num pages", FieldType.FieldNumPages)
footer.Format.HorizontalAlignment = HorizontalAlignment.Center

DifferentFirstPageHeaderFooter = True 让首页使用独立的页眉页脚,封面因此保持干净、不出现页眉线和页码。页码用域字段实现:AppendField(..., FieldType.FieldPage) 插入"当前页",FieldType.FieldNumPages 插入"总页数",合起来呈现"Page X of Y";域在文档打开时求值,页数随内容自动更新。

封面与分页部分:

cover = section.AddParagraph()
cover.AppendText("Northwind Pay App v3.2").CharacterFormat.FontSize = 26
cover.Format.HorizontalAlignment = HorizontalAlignment.Center
cover.Format.BeforeSpacing = section.PageSetup.PageSize.Height / 2 - 3 * section.PageSetup.Margins.Top

section.AddParagraph().AppendBreak(BreakType.PageBreak)

用 PageSize.Height 减去边距算出垂直居中的前置间距,比手工试一个固定数字稳。AppendBreak(BreakType.PageBreak) 在段落里插入分页符,把封面与正文隔开。这份带页眉页脚与分页的文档实测为 pages=2。

交付报告封面

一份对象、多种格式

装配好的 Document 可以直接保存为多种格式,目标格式由 FileFormat 指定。

targets = [
    ("convert_2013.docx", FileFormat.Docx2013),
    ("convert_2016.docx", FileFormat.Docx2016),
    ("convert_2019.docx", FileFormat.Docx2019),
    ("convert_legacy.doc", FileFormat.Doc),
    ("convert_export.pdf", FileFormat.PDF),
]
for name, fmt in targets:
    doc.SaveToFile(name, fmt)

同一份对象连续保存多格式,输出大小实测如下:

convert_2013.docx  6118 bytes
convert_2016.docx  6118 bytes
convert_2019.docx  6118 bytes
convert_legacy.doc  9216 bytes
convert_export.pdf  37009 bytes

三种 docx 版本产出同样大小,基础内容的编码一致;旧式 .doc 采用二进制容器而偏大,PDF 则把排版完整固化成固定页面。把封面、正文各块与页眉页脚合到一份文档里,实测交付报告为 paragraphs=14 tables=1 pages=2 bytes=16664。

要在保存前确认页数,用 doc.GetPageCount();要预览版式而不打开 Word,用 doc.SaveImageToStreams(i, ImageType.Bitmap) 把第 i 页渲成位图,实测两页分别输出 16593 与 44399 字节。

交付报告正文页

适用场景与版本说明

从零创建适合"结构固定、内容随批次变化"的文档:项目周报与交付报告、合同与对账单、带封面的方案书、批量生成的通知函。这类文档的版式在模板阶段就定好,运行时只需往既定节点填数据,脚本可重复执行、结果一致。

嵌入流程时,把封面、正文各块、页眉页脚分别封装成函数,输入换成一个数据字典,一份生成脚本就能覆盖同模板下的所有批次。页数与表格行数随数据变化,用 GetPageCount() 在保存后校验,能把格式异常的文档挡在流程之外。

版本方面,Free Spire.Doc for Python 单份文档以 500 个段落、25 个表格为限,超出时改用商业版即可;上面的段落、字符与段落格式、图片、表格、页眉页脚、页码域与多格式保存都能在 Free 版完成。

到此这篇关于Python从零快速生成带页码页眉的Word文档教程的文章就介绍到这了,更多相关Python生成Word文档内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文