脚本专家 发表于 3 天前

Python用Free Spire.Doc批量设置Word页眉页

在批量生成或归档 Word 报告时,页眉页脚的统一是典型脚本化需求:页码便于引用定位,公司标识与密级标注承担识别和防泄密职能。手工处理几十份文档时,容易出现封面显示页码、双面打印页码不靠外侧、页眉格式不一致等问题。本文使用 Free Spire.Doc for Python 演示一条完整的页眉页脚配置链路,包括基础文字页眉与页码域、封面页独立、奇偶页不同、Logo 行内/浮动页眉、跨文档 Clone 统一格式,以及分发前锁定页眉。安装命令如下:


pip install spire.doc.free


演示输入为两份文件:季度业务报告.docx(4 页,第 1 页为封面,后 3 页为正文,含一个财务数据表格)和 2025年度报告.docx(2 页历史文档,没有任何页眉页脚)。

先弄清两个默认值。页眉页脚排版由 PageSetup 上的 HeaderDistance 和 FooterDistance 控制,前者是页眉起点距页顶的距离,后者是页脚起点距页底的距离,新建文档默认值都是 36.0 pt。正文区从上边距 72 pt 处开始,页眉从 36 pt 处开始,二者之间约 36 pt 就是页眉实际可用高度。单行 9 pt 小字页眉加分隔线没有问题;放入高图片时,页眉区放不下就会把正文整体下移,这也是后面 Logo 两种放法差异的来源。

基础页眉页脚可以用 Section.HeadersFooters 下的 Header 和 Footer 容器完成。各自 AddParagraph 后按普通段落排版,页码用域字段插入,FieldPage 是当前页码,FieldNumPages 是总页数。示例代码如下:


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

document = Document()
document.LoadFromFile('季度业务报告.docx')
section = document.Sections

# 页眉:公司标识 + 报告名,灰色 9pt,底部单线
header_paragraph = section.HeadersFooters.Header.AddParagraph()
tr = header_paragraph.AppendText('星河科技 · 2026 年第三季度业务报告')
tr.CharacterFormat.FontName = '微软雅黑'
tr.CharacterFormat.FontSize = 9
tr.CharacterFormat.TextColor = Color.FromArgb(255, 110, 116, 124)
header_paragraph.Format.Borders.Bottom.BorderType = BorderStyle.Single
header_paragraph.Format.Borders.Bottom.Space = 1.0

# 页脚:第 X 页,共 Y 页(域字段),右对齐,顶部单线
footer_paragraph = section.HeadersFooters.Footer.AddParagraph()
footer_paragraph.Format.HorizontalAlignment = HorizontalAlignment.Right
footer_paragraph.AppendText('第 ')
footer_paragraph.AppendField('page number', FieldType.FieldPage)
footer_paragraph.AppendText(' 页,共 ')
footer_paragraph.AppendField('number of pages', FieldType.FieldNumPages)
footer_paragraph.AppendText(' 页')


域字段的文字属性需要单独处理。AppendField 返回的是域对象而不是 TextRange,混排时“第”“页”等通过 AppendText 返回值设置格式,域本身的字体则要在插入后遍历段落的 ChildObjects,对 DocumentObjectType.TextRange 类型对象逐个设置,因为域求值后的文字也属于 TextRange:


for k in range(footer_paragraph.ChildObjects.Count):
    obj = footer_paragraph.ChildObjects.get_Item(k)
    if obj.DocumentObjectType == DocumentObjectType.TextRange:
      obj.CharacterFormat.FontName = '微软雅黑'
      obj.CharacterFormat.FontSize = 9
      obj.CharacterFormat.TextColor = Color.FromArgb(255, 110, 116, 124)


页码必须用域,不能写死。这份报告 4 页,手工填“1 / 4”看似可行,但正文增删一页后所有页码都会错;域字段在每次打开或渲染时重新求值,页码始终正确。渲染输出里页脚显示“2 / 4”,说明两个域都已正确求值。

封面页需要保持空白。带封面的报告不应在封面出现页眉和页码,打开 PageSetup.DifferentFirstPageHeaderFooter 后,第 1 页改用 FirstPageHeader 和 FirstPageFooter 两个独立容器,其余页面继续使用常规 Header / Footer。示例:


document = Document()
document.LoadFromFile('季度业务报告_基础页眉页脚.docx')
section = document.Sections

# 打开“首页不同”开关
section.PageSetup.DifferentFirstPageHeaderFooter = True

# FirstPageHeader / FirstPageFooter 不添加任何内容,封面即保持空白


这里不需要执行清除操作。FirstPageHeader 是独立容器,留空就是空白封面,常规页眉不受影响。保存后检查,FirstPageHeader 与 FirstPageFooter 的段落数都是 0,封面页渲染确认无页眉线、无页码,第 2 页起的页眉页脚原样保留。

奇偶页不同用于双面打印。报告双面打印装订时,页码应始终靠外侧:奇数页(右手页)靠右,偶数页(左手页)靠左,翻阅时页码位置固定。密级标注也常只放偶数页页眉。这需要打开第二个开关 DifferentOddAndEvenPagesHeaderFooter,两个开关可以叠加:


document = Document()
document.LoadFromFile('季度业务报告_基础页眉页脚.docx')
section = document.Sections

# 封面空白 + 奇偶页不同,两个开关叠加
section.PageSetup.DifferentFirstPageHeaderFooter = True
section.PageSetup.DifferentOddAndEvenPagesHeaderFooter = True

# 开关打开后,原 Header/Footer 只作用于奇数页
# 偶数页页眉:密级标注,右对齐(靠外侧)
even_header = section.HeadersFooters.EvenHeader.AddParagraph()
even_header.Format.HorizontalAlignment = HorizontalAlignment.Right
tr = even_header.AppendText('星河科技 · 机密')
tr.CharacterFormat.FontName = '微软雅黑'
tr.CharacterFormat.FontSize = 9
tr.CharacterFormat.TextColor = Color.FromArgb(255, 110, 116, 124)
even_header.Format.Borders.Bottom.BorderType = BorderStyle.Single

# 偶数页页脚:页码左对齐(靠外侧)
even_footer = section.HeadersFooters.EvenFooter.AddParagraph()
even_footer.Format.HorizontalAlignment = HorizontalAlignment.Left
even_footer.AppendField('page number', FieldType.FieldPage)
even_footer.AppendText(' / ')
even_footer.AppendField('number of pages', FieldType.FieldNumPages)


开关语义容易误解:打开奇偶开关后,之前设置在 Header / Footer 上的内容只作用于奇数页,偶数页必须单独往 EvenHeader / EvenFooter 里写。漏写时偶数页页眉会直接消失,而不是继承奇数页设置。渲染确认:第 2 页(偶数页)页眉为“星河科技 · 机密”、页码“2 / 4”居左;第 3 页(奇数页)页眉为报告名、页码“3 / 4”居右。

Logo 页眉有行内与浮动两种放法,效果差别很大。AppendPicture 返回的 DocPicture 支持 Width / Height 设置显示尺寸,源图 800 × 200 px 按 1/4 缩放为 200 × 50 pt。行内图片参与页眉段落的文字排版,页眉行高会被撑到图片高度:


header_paragraph = section.HeadersFooters.Header.AddParagraph()
pic = header_paragraph.AppendPicture('星河科技_Logo.png')
pic.Width = 200.0# 显示尺寸 200 × 50 pt
pic.Height = 50.0
header_paragraph.Format.Borders.Bottom.BorderType = BorderStyle.Single


浮动图片把环绕方式设为 Behind(衬于文字下方),定位基准改为页面,图片就脱离文字流,不再占用页眉行高:


pic = header_paragraph.AppendPicture('星河科技_Logo.png')
pic.TextWrappingStyle = TextWrappingStyle.Behind
pic.HorizontalOrigin = HorizontalOrigin.Page# 水平定位基准:页面左缘
pic.VerticalOrigin = VerticalOrigin.Page      # 垂直定位基准:页面顶缘
pic.VerticalAlignment = ShapeVerticalAlignment.Top
pic.Width = 200.0
pic.Height = 50.0


两种放法渲染后的差异可以用正文起始位置量化:行内版正文第一行墨迹出现在页面渲染图第 61 行像素,浮动版在第 13 行。行内 Logo 的 50 pt 高度全部转化为正文下移,浮动 Logo 则完全不占版面空间。如果 Logo 只是页眉的装饰性元素,用浮动;如果页眉就是要展示完整的企业标识横幅,行内更直观。源图按显示尺寸的整数倍准备(这里 4 倍)可以避免缩放锯齿。

跨文档统一时,Clone 是必须的。存量文档没有页眉,一份份重配不现实,规范做法是把一份做好的文档当模板,把页眉页脚对象复制过去:


source = Document()
source.LoadFromFile('季度业务报告_基础页眉页脚.docx')
src_header = source.Sections.HeadersFooters.Header
src_footer = source.Sections.HeadersFooters.Footer

target = Document()
target.LoadFromFile('2025年度报告.docx')

for i in range(target.Sections.Count):
    section = target.Sections.get_Item(i)
    for j in range(src_header.ChildObjects.Count):
      obj = src_header.ChildObjects.get_Item(j)
      section.HeadersFooters.Header.ChildObjects.Add(obj.Clone())
    for j in range(src_footer.ChildObjects.Count):
      obj = src_footer.ChildObjects.get_Item(j)
      section.HeadersFooters.Footer.ChildObjects.Add(obj.Clone())


跨文档复制必须调用 Clone()。页眉段落对象归属于源文档的对象树,直接 Add 原对象会让两个文档共享同一块内存,保存时内容错乱;Clone 生成深拷贝,各自独立。本次运行复制了页眉对象 1 个、页脚对象 1 个(各是一个段落),2025年度报告.docx 渲染确认第 1 页出现页眉线与页脚“1 / 2”。

分发前还需要锁定页眉。页眉页脚做好后,文档正文可能仍需要他人补充数据,但密级标注和 Logo 不应被随手改动。用窗体保护配合节级豁免可以实现“正文可编辑、页眉页脚锁定”:


document = Document()
document.LoadFromFile('季度业务报告_基础页眉页脚.docx')
section = document.Sections

# 全文按“只能填写窗体”保护(此类型下页眉页脚不可编辑)
document.Protect(ProtectionType.AllowOnlyFormFields, 'XH2026')

# 第 1 节豁免窗体保护:正文保持可编辑
section.ProtectForm = False


Protect 的第一个参数选 AllowOnlyFormFields 而不是 ReadOnly,是因为前者允许配合节级豁免:ProtectForm = False 的节里正文仍可自由编辑,而页眉页脚不在豁免范围,保持锁定。保存后重新加载验证,GetProtectionType() 返回 AllowOnlyFormFields,第 1 节 ProtectForm 为 False,与设置一致;渲染外观与未保护版本完全相同,保护不影响文档显示。

这条配置链路适合两类场景。一是报告批量生成的末端环节:上游系统产出正文后,按文档类型套用对应页眉配置,对外报告用 Logo 浮动页眉加页码域,内部资料用密级标注加奇偶页页码。二是存量文档规范化:交接、归档或应付审计前,用 Clone 复制方式把历史文档统一到同一套页眉模板,不用逐份打开手工设置。配置本身建议与代码分离:页眉文字、字体颜色、Logo 路径、启用哪些开关,放进 JSON 或 YAML 配置文件,脚本读取后按文档类型选择模板,新增报告规格时只改配置不改代码。锁定环节只在文档即将外发时执行,密码由分发流程统一管理。

本文涉及的全部操作与渲染输出在 Free Spire.Doc for Python 环境实测通过;文档加载、页眉页脚读写、图片插入与保护均为免费版可用功能。

热心网友3 发表于 3 天前

Re: Python用Free Spire.Doc批量设置Word页眉页

这个整理挺实用的,尤其是把 HeaderDistance 和 FooterDistance 默认 36 pt、正文上边距 72 pt 的关系讲清楚了,之前页眉放图导致正文整体下移,一直没往页眉可用高度这方面想。页码域那段也提醒到我了,AppendField 返回的不是 TextRange,混排时得遍历 ChildObjects 去设置字体,不然“第”“页”和页码的字体很容易不一致。封面页用 DifferentFirstPageHeaderFooter 后把 FirstPageHeader 和 FirstPageFooter 留空,这个做法确实干净,比先写再清更省事。期待后面奇偶页不同、Logo 行内/浮动、跨文档 Clone 和分发前锁定页眉的部分,双面打印页码靠外侧这个场景很常见,想看看具体怎么配置。

热心网友3 发表于 3 天前

Re: Python用Free Spire.Doc批量设置Word页眉页

感谢分享,这篇把批量处理 Word 页眉页脚的关键点讲得挺清楚。我最关注的是 HeaderDistance 和 FooterDistance 默认 36 pt、正文从 72 pt 开始这段,一下解释了页眉可用高度和放高 Logo 会把正文往下挤的原因,实际排版时很实用。页码用 FieldPage 和 FieldNumPages 而不是手填,也很关键,批量报告只要页面增减,写死页码就会错。首页不同用 DifferentFirstPageHeaderFooter 后让 FirstPageHeader 和 FirstPageFooter 留空,比先写再清更稳妥。奇偶页不同对应双面打印页码靠外侧、密级只放偶数页,这部分也很贴合真实装订场景。后面 Logo 行内与浮动、跨文档 Clone 和分发前锁定页眉如果继续展开就更好,尤其想看 Clone 时格式和图片会不会有坑。整体思路清楚,收藏了。

热心网友3 发表于 3 天前

Re: Python用Free Spire.Doc批量设置Word页眉页

楼主这个整理得很实用,尤其是把 HeaderDistance 和 FooterDistance 默认 36 pt、以及页眉可用高度和正文起始位置的关系讲清楚了,以前放 Logo 时正文莫名下移,现在知道是页眉区撑开的原因。页码用 FieldPage 和 FieldNumPages 域而不是手写,文档增删页后不会错,这点对批量报告很重要。域字段的文字格式要遍历 ChildObjects 里的 TextRange 单独设,这个细节也提醒得好,不然混排时“第”“页”和域数字样式容易不一致。封面页用 DifferentFirstPageHeaderFooter,再把 FirstPageHeader 和 FirstPageFooter 留空,比手动清除省事,也不会影响常规页眉。奇偶页不同那段正好是双面打印的常见需求,页码靠外侧、密级只放偶数页页眉都很合理。期待后续把跨文档 Clone 统一格式和分发前锁定页眉的部分补完,这块在批量归档里应该很关键。
页: [1]
查看完整版本: Python用Free Spire.Doc批量设置Word页眉页