查看: 219|回复: 0

Python操作Word书签:Free Spire.Doc替换与插图

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
Word 书签可以理解为文档里的命名变量:先在模板中标记位置,程序运行时按名称写入文本、表格或图片。使用 Free Spire.Doc for Python 可以把“模板 + 数据 = 文档”的流程自动化,定位比全文查找替换更精确,也支持嵌套书签。先安装:
  1. pip install spire.doc.free
复制代码

一、创建书签模板

书签由 AppendBookmarkStart 和 AppendBookmarkEnd 成对定义,名称必须一致,End 位于 Start 之后。下面创建报告模板,并在待填充位置插入书签:
  1. from spire.doc import *
  2. from spire.doc.common import *
  3. document = Document()
  4. section = document.AddSection()
  5. p = section.AddParagraph()
  6. p.AppendText('Project Phase Report')
  7. p.ApplyStyle(BuiltinStyle.Heading1)
  8. p.Format.HorizontalAlignment = HorizontalAlignment.Center
  9. fields = [
  10.     ('Project Name: ', 'ProjectName'),
  11.     ('Client: ', 'ClientName'),
  12.     ('Report Date: ', 'ReportDate'),
  13.     ('Project Phase: ', 'ProjectPhase'),
  14. ]
  15. for label, bm in fields:
  16.     p = section.AddParagraph()
  17.     p.AppendText(label)
  18.     p.AppendBookmarkStart(bm)
  19.     p.AppendText('(to be filled)')
  20.     p.AppendBookmarkEnd(bm)
  21. # Summary、MilestoneTable、RiskLevel、RiskDetail、Signature 同理添加
  22. document.SaveToFile('template.docx', FileFormat.Docx)
  23. document.Close()
复制代码

风险与建议部分可用嵌套书签:外层 RiskSection 包裹内层 RiskLevel 和 RiskDetail。内层可单独替换,外层也可整体操作。生成模板后包含 10 个书签:ProjectName、ClientName、ReportDate、ProjectPhase、Summary、MilestoneTable、RiskSection、RiskLevel、RiskDetail、Signature。

二、替换书签内容

BookmarksNavigator 是书签操作核心类。MoveToBookmark 按名称定位,ReplaceBookmarkContent 替换书签覆盖的内容。第二个参数控制是否保留原有字符格式:False 使用默认格式,True 继承书签内原文本的字体、字号、颜色等属性。
  1. doc = Document()
  2. doc.LoadFromFile('template.docx')
  3. navigator = BookmarksNavigator(doc)
  4. navigator.MoveToBookmark('ProjectName')
  5. navigator.ReplaceBookmarkContent('Smart City Data Platform Phase II', False)
  6. navigator.MoveToBookmark('ClientName')
  7. navigator.ReplaceBookmarkContent('Orient Municipal Group', False)
  8. navigator.MoveToBookmark('ReportDate')
  9. navigator.ReplaceBookmarkContent('September 28, 2026', False)
  10. navigator.MoveToBookmark('ProjectPhase')
  11. navigator.ReplaceBookmarkContent('Phase II - Mid-term Acceptance', False)
  12. navigator.MoveToBookmark('Summary')
  13. navigator.ReplaceBookmarkContent(
  14.     'This phase completed a comprehensive upgrade of the data collection module...', False)
  15. navigator.MoveToBookmark('RiskLevel')
  16. navigator.ReplaceBookmarkContent('Medium', False)
  17. doc.SaveToFile('step2_text.docx', FileFormat.Docx)
  18. doc.Close()
复制代码

示例摘要对应的事实数据包括:新增 320 个传感器接入点,日吞吐从 1.2 亿提升到 3.5 亿条记录,集成交通、环境、安全、水务、市政 5 个子系统,API 平均响应 87ms,可用性 99.6%,中期验收 14 项通过 13 项,剩余实时告警延迟预计 10 月 15 日达标。风险详情可写 Kafka 集群高峰消息堆积,峰值延迟 4.2 秒,超过 2 秒 SLA,扩容到 6 节点预计 10 月 10 日完成。嵌套书签内层可独立定位替换,MoveToBookmark 不关心嵌套层级。

替换为表格时,先构建 Table,再用 TextBodyPart 包装后传给 ReplaceBookmarkContent:
  1. table = Table(doc, True)
  2. table.ResetCells(6, 4)
  3. data = [
  4.     ['Milestone', 'Planned Date', 'Actual Date', 'Status'],
  5.     ['Requirements', '2026-07-15', '2026-07-14', 'Completed'],
  6.     ['Architecture', '2026-07-30', '2026-07-30', 'Completed'],
  7.     ['Core Development', '2026-08-31', '2026-09-02', 'Completed (2-day delay)'],
  8.     ['Integration Test', '2026-09-20', '—', 'In Progress (85%)'],
  9.     ['Mid-term Review', '2026-09-28', '2026-09-28', 'Passed'],
  10. ]
  11. for i in range(6):
  12.     for j in range(4):
  13.         cell = table.Rows[i].Cells[j]
  14.         para = cell.AddParagraph()
  15.         txtRange = para.AppendText(data[i][j])
  16.         if i == 0:
  17.             txtRange.CharacterFormat.Bold = True
  18. navigator = BookmarksNavigator(doc)
  19. navigator.MoveToBookmark('MilestoneTable')
  20. part = TextBodyPart(doc)
  21. part.BodyItems.Add(table)
  22. navigator.ReplaceBookmarkContent(part)
  23. doc.SaveToFile('step3_table.docx', FileFormat.Docx)
  24. doc.Close()
复制代码

Table(doc, True) 的第二个参数启用固定布局模式,列宽由 ResetCells 自动分配。TextBodyPart 用于承载表格、多段落等结构化内容。

三、在书签位置插入图片

AppendPicture 必须在段落上调用,而书签位置不一定有现成空段落。可先在临时 section 中创建带图片的段落,再用 InsertParagraph 插入书签位置,最后移除临时 section:
  1. doc = Document()
  2. doc.LoadFromFile('step3_table.docx')
  3. bn = BookmarksNavigator(doc)
  4. bn.MoveToBookmark('Signature', True, True)
  5. section0 = doc.AddSection()
  6. paragraph = section0.AddParagraph()
  7. paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
  8. picture = paragraph.AppendPicture('signature.png')
  9. picture.Width = 150.0
  10. picture.Height = 150.0
  11. bn.InsertParagraph(paragraph)
  12. doc.Sections.Remove(section0)
  13. doc.SaveToFile('step4_image.docx', FileFormat.Docx)
  14. doc.Close()
复制代码

MoveToBookmark 的后两个 True 分别控制是否区分大小写、是否向前搜索。Width 和 Height 单位为磅,150 磅约等于 5.3 厘米,适合签章图片;横幅图片可按比例设置,如 Width=400.0、Height=100.0。

四、提取与列举书签内容

document.Bookmarks 是书签集合,支持按索引和按名称访问:
  1. doc = Document()
  2. doc.LoadFromFile('step4_image.docx')
  3. for i in range(doc.Bookmarks.Count):
  4.     bm = doc.Bookmarks[i]
  5.     print(f'{i+1}. {bm.Name}')
  6. bookmark = doc.Bookmarks['ProjectName']
  7. print(bookmark.Name)
复制代码

GetBookmarkContent 返回书签内容对象,遍历 BodyItems 可取出文本。若书签包含表格,还需用 isinstance 判断 Table 类型:
  1. navigator = BookmarksNavigator(doc)
  2. targets = ['ProjectName', 'ClientName', 'Summary', 'RiskLevel', 'RiskDetail']
  3. for name in targets:
  4.     navigator.MoveToBookmark(name)
  5.     content = navigator.GetBookmarkContent()
  6.     text = ''
  7.     for i in range(content.BodyItems.Count):
  8.         item = content.BodyItems.get_Item(i)
  9.         if isinstance(item, Paragraph):
  10.             for j in range(item.ChildObjects.Count):
  11.                 child = item.ChildObjects.get_Item(j)
  12.                 if isinstance(child, TextRange):
  13.                     text += child.Text
  14.     display = text[:80] + '...' if len(text) > 80 else text
  15.     print(f'[{name}] {display}')
复制代码

五、删除书签与书签内容

只删除书签标记、保留内容,可用 Bookmarks.Remove:
  1. doc = Document()
  2. doc.LoadFromFile('step4_image.docx')
  3. bookmark = doc.Bookmarks['RiskSection']
  4. doc.Bookmarks.Remove(bookmark)
  5. doc.SaveToFile('step6a_remove_mark.docx', FileFormat.Docx)
  6. doc.Close()
复制代码

删除后剩余 9 个书签,适合报告定稿时清理标记。若要同时删除书签及其内容,需要定位 BookmarkStart 和 BookmarkEnd 在段落子对象中的索引,再循环移除两者之间的元素:
  1. bookmark = doc.Bookmarks['Signature']
  2. para = bookmark.BookmarkStart.Owner
  3. startIndex = para.ChildObjects.IndexOf(bookmark.BookmarkStart)
  4. para2 = bookmark.BookmarkEnd.Owner
  5. endIndex = para2.ChildObjects.IndexOf(bookmark.BookmarkEnd)
  6. for i in range(startIndex + 1, endIndex):
  7.     para.ChildObjects.RemoveAt(startIndex + 1)
  8. doc.Bookmarks.Remove(bookmark)
  9. doc.SaveToFile('step6b_remove_content.docx', FileFormat.Docx)
  10. doc.Close()
复制代码

RemoveAt 后列表会前移,因此循环中始终删除 startIndex + 1 位置,而不是递增索引。删除后同样剩余 9 个书签。

六、关键类与方法

常用类包括 Document、Section、Paragraph、TextRange、Table、TextBodyPart、BookmarksNavigator、Bookmarks。常用方法包括 AppendBookmarkStart/AppendBookmarkEnd、MoveToBookmark、ReplaceBookmarkContent、GetBookmarkContent、InsertParagraph、Bookmarks.Remove。

适用场景主要是项目报告、月报、合同、通知等模板化文档。典型流程是:创建带书签模板、替换文本书签、替换表格书签、在书签位置插入图片、保存输出;定稿阶段再按需删除书签标记。嵌套书签适合一个区域内多个字段独立填充,格式保留参数适合占位文本已预设样式的模板。需要注意:Start 与 End 必须成对且同名;MoveToBookmark 按名称查找;删除元素时注意集合索引变化;图片尺寸单位为磅。
回复

使用道具 举报

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

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

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

官方核心成员

关注微信公众号

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

GMT+8, 2026-10-3 13:39 , Processed in 0.025794 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部