Word 书签可以理解为文档里的命名变量:先在模板中标记位置,程序运行时按名称写入文本、表格或图片。使用 Free Spire.Doc for Python 可以把“模板 + 数据 = 文档”的流程自动化,定位比全文查找替换更精确,也支持嵌套书签。先安装:
- pip install spire.doc.free
复制代码
一、创建书签模板
书签由 AppendBookmarkStart 和 AppendBookmarkEnd 成对定义,名称必须一致,End 位于 Start 之后。下面创建报告模板,并在待填充位置插入书签:
- from spire.doc import *
- from spire.doc.common import *
- document = Document()
- section = document.AddSection()
- p = section.AddParagraph()
- p.AppendText('Project Phase Report')
- p.ApplyStyle(BuiltinStyle.Heading1)
- p.Format.HorizontalAlignment = HorizontalAlignment.Center
- fields = [
- ('Project Name: ', 'ProjectName'),
- ('Client: ', 'ClientName'),
- ('Report Date: ', 'ReportDate'),
- ('Project Phase: ', 'ProjectPhase'),
- ]
- for label, bm in fields:
- p = section.AddParagraph()
- p.AppendText(label)
- p.AppendBookmarkStart(bm)
- p.AppendText('(to be filled)')
- p.AppendBookmarkEnd(bm)
- # Summary、MilestoneTable、RiskLevel、RiskDetail、Signature 同理添加
- document.SaveToFile('template.docx', FileFormat.Docx)
- document.Close()
复制代码
风险与建议部分可用嵌套书签:外层 RiskSection 包裹内层 RiskLevel 和 RiskDetail。内层可单独替换,外层也可整体操作。生成模板后包含 10 个书签:ProjectName、ClientName、ReportDate、ProjectPhase、Summary、MilestoneTable、RiskSection、RiskLevel、RiskDetail、Signature。
二、替换书签内容
BookmarksNavigator 是书签操作核心类。MoveToBookmark 按名称定位,ReplaceBookmarkContent 替换书签覆盖的内容。第二个参数控制是否保留原有字符格式:False 使用默认格式,True 继承书签内原文本的字体、字号、颜色等属性。
- doc = Document()
- doc.LoadFromFile('template.docx')
- navigator = BookmarksNavigator(doc)
- navigator.MoveToBookmark('ProjectName')
- navigator.ReplaceBookmarkContent('Smart City Data Platform Phase II', False)
- navigator.MoveToBookmark('ClientName')
- navigator.ReplaceBookmarkContent('Orient Municipal Group', False)
- navigator.MoveToBookmark('ReportDate')
- navigator.ReplaceBookmarkContent('September 28, 2026', False)
- navigator.MoveToBookmark('ProjectPhase')
- navigator.ReplaceBookmarkContent('Phase II - Mid-term Acceptance', False)
- navigator.MoveToBookmark('Summary')
- navigator.ReplaceBookmarkContent(
- 'This phase completed a comprehensive upgrade of the data collection module...', False)
- navigator.MoveToBookmark('RiskLevel')
- navigator.ReplaceBookmarkContent('Medium', False)
- doc.SaveToFile('step2_text.docx', FileFormat.Docx)
- 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:
- table = Table(doc, True)
- table.ResetCells(6, 4)
- data = [
- ['Milestone', 'Planned Date', 'Actual Date', 'Status'],
- ['Requirements', '2026-07-15', '2026-07-14', 'Completed'],
- ['Architecture', '2026-07-30', '2026-07-30', 'Completed'],
- ['Core Development', '2026-08-31', '2026-09-02', 'Completed (2-day delay)'],
- ['Integration Test', '2026-09-20', '—', 'In Progress (85%)'],
- ['Mid-term Review', '2026-09-28', '2026-09-28', 'Passed'],
- ]
- for i in range(6):
- for j in range(4):
- cell = table.Rows[i].Cells[j]
- para = cell.AddParagraph()
- txtRange = para.AppendText(data[i][j])
- if i == 0:
- txtRange.CharacterFormat.Bold = True
- navigator = BookmarksNavigator(doc)
- navigator.MoveToBookmark('MilestoneTable')
- part = TextBodyPart(doc)
- part.BodyItems.Add(table)
- navigator.ReplaceBookmarkContent(part)
- doc.SaveToFile('step3_table.docx', FileFormat.Docx)
- doc.Close()
复制代码
Table(doc, True) 的第二个参数启用固定布局模式,列宽由 ResetCells 自动分配。TextBodyPart 用于承载表格、多段落等结构化内容。
三、在书签位置插入图片
AppendPicture 必须在段落上调用,而书签位置不一定有现成空段落。可先在临时 section 中创建带图片的段落,再用 InsertParagraph 插入书签位置,最后移除临时 section:
- doc = Document()
- doc.LoadFromFile('step3_table.docx')
- bn = BookmarksNavigator(doc)
- bn.MoveToBookmark('Signature', True, True)
- section0 = doc.AddSection()
- paragraph = section0.AddParagraph()
- paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
- picture = paragraph.AppendPicture('signature.png')
- picture.Width = 150.0
- picture.Height = 150.0
- bn.InsertParagraph(paragraph)
- doc.Sections.Remove(section0)
- doc.SaveToFile('step4_image.docx', FileFormat.Docx)
- doc.Close()
复制代码
MoveToBookmark 的后两个 True 分别控制是否区分大小写、是否向前搜索。Width 和 Height 单位为磅,150 磅约等于 5.3 厘米,适合签章图片;横幅图片可按比例设置,如 Width=400.0、Height=100.0。
四、提取与列举书签内容
document.Bookmarks 是书签集合,支持按索引和按名称访问:
- doc = Document()
- doc.LoadFromFile('step4_image.docx')
- for i in range(doc.Bookmarks.Count):
- bm = doc.Bookmarks[i]
- print(f'{i+1}. {bm.Name}')
- bookmark = doc.Bookmarks['ProjectName']
- print(bookmark.Name)
复制代码
GetBookmarkContent 返回书签内容对象,遍历 BodyItems 可取出文本。若书签包含表格,还需用 isinstance 判断 Table 类型:
- navigator = BookmarksNavigator(doc)
- targets = ['ProjectName', 'ClientName', 'Summary', 'RiskLevel', 'RiskDetail']
- for name in targets:
- navigator.MoveToBookmark(name)
- content = navigator.GetBookmarkContent()
- text = ''
- for i in range(content.BodyItems.Count):
- item = content.BodyItems.get_Item(i)
- if isinstance(item, Paragraph):
- for j in range(item.ChildObjects.Count):
- child = item.ChildObjects.get_Item(j)
- if isinstance(child, TextRange):
- text += child.Text
- display = text[:80] + '...' if len(text) > 80 else text
- print(f'[{name}] {display}')
复制代码
五、删除书签与书签内容
只删除书签标记、保留内容,可用 Bookmarks.Remove:
- doc = Document()
- doc.LoadFromFile('step4_image.docx')
- bookmark = doc.Bookmarks['RiskSection']
- doc.Bookmarks.Remove(bookmark)
- doc.SaveToFile('step6a_remove_mark.docx', FileFormat.Docx)
- doc.Close()
复制代码
删除后剩余 9 个书签,适合报告定稿时清理标记。若要同时删除书签及其内容,需要定位 BookmarkStart 和 BookmarkEnd 在段落子对象中的索引,再循环移除两者之间的元素:
- bookmark = doc.Bookmarks['Signature']
- para = bookmark.BookmarkStart.Owner
- startIndex = para.ChildObjects.IndexOf(bookmark.BookmarkStart)
- para2 = bookmark.BookmarkEnd.Owner
- endIndex = para2.ChildObjects.IndexOf(bookmark.BookmarkEnd)
- for i in range(startIndex + 1, endIndex):
- para.ChildObjects.RemoveAt(startIndex + 1)
- doc.Bookmarks.Remove(bookmark)
- doc.SaveToFile('step6b_remove_content.docx', FileFormat.Docx)
- 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 按名称查找;删除元素时注意集合索引变化;图片尺寸单位为磅。 |