多人协作撰写方案、分章节编写报告、各部门分别提交材料------这些场景下,最终往往需要把若干份独立的 Word 文档整合成一个完整文件。如果靠手工复制粘贴,不仅要在多个窗口间反复切换,还容易丢失页眉页脚、页码、分栏这类页面级设置,合并后再逐项修复反而更费时间。
用 Python 自动化合并的价值就在于此:它可以把"复制内容"升级为"搬运结构",让每个文档原有的节设置、样式体系一并被保留下来。同时,脚本化之后还能轻松扩展到批量场景,比如把一个文件夹里的十几份文档按文件名顺序合并成一份。
本文以 Spire.Doc 为例,介绍几种常用的 Word 文档合并方式,包括最简单的整文插入、保留节结构的克隆合并、保持源文档格式的合并,以及把内容合并到同一页的做法。
环境准备
开始前,先通过 pip 安装 Spire.Doc:
bash
pip install Spire.Doc
安装完成后,在脚本顶部引入命名空间。本文的示例全部基于 Document 对象展开,通过它加载文档、访问节集合与正文元素,最后输出合并结果。
python
from spire.doc import *
from spire.doc.common import *
用 InsertTextFromFile 快速合并
如果只关心正文内容、对页面设置没有特殊要求,最省事的方式是 InsertTextFromFile() 方法。它接受一个文件路径,让库自动识别文档格式,并把其中的内容插入到当前文档的末尾。整个过程只需一次调用,适合快速拼接草稿或纯文本性质的材料。
python
from spire.doc import *
from spire.doc.common import *
inputFile1 = "./Data/Sample.docx"
inputFile2 = "./Data/SampleB_1.docx"
outputFile = "SimpleInsertFile.docx"
# 加载作为主体的 Word 文档
doc = Document()
doc.LoadFromFile(inputFile1)
# 将另一个文档的内容插入进来
doc.InsertTextFromFile(inputFile2, FileFormat.Auto)
# 保存结果
doc.SaveToFile(outputFile, FileFormat.Docx2013)
doc.Close()
第二个参数 FileFormat.Auto 表示由库自动判断待插入文件的格式,因此无论是 .doc 还是 .docx 都能正常处理,省去了事先判断类型的麻烦。需要注意的是,这种方式以"内容"为单位合并,第二个文档的节属性、页面方向等设置不会作为独立的节带入结果文档,而是按当前文档的排版规则重新排布。
按节克隆保留原有排版
当被合并的文档各自有不同的页面设置时------比如一份是纵向 A4、另一份是横向表格页------就需要以"节"为单位搬运。Word 中的节(Section)是页面级格式的基本单位,页边距、纸张方向、页眉页脚都挂在节上。通过克隆节并加入目标文档的节集合,可以让这些设置原样保留。
python
from spire.doc import *
from spire.doc.common import *
inputFile1 = "./Data/Sample.docx"
inputFile2 = "./Data/SampleB_1.docx"
outputFile = "merge.docx"
# 加载目标文档
document = Document()
document.LoadFromFile(inputFile1, FileFormat.Docx)
# 加载待合并的文档
documentMerge = Document()
documentMerge.LoadFromFile(inputFile2, FileFormat.Docx)
# 逐节克隆并追加到目标文档
for i in range(documentMerge.Sections.Count):
sec = documentMerge.Sections.get_Item(i)
document.Sections.Add(sec.Clone())
# 保存结果
document.SaveToFile(outputFile, FileFormat.Docx)
document.Close()
documentMerge.Close()
这里的关键是 sec.Clone():直接把另一个文档的节对象加进来会引发归属冲突,克隆则生成一份独立的副本,可以安全地加入目标文档。Sections.Add() 会把新节追加到末尾,因此合并后的顺序就是循环遍历的顺序。
这种方式下,每个节都保留了自己的页面设置,合并结果中横向页和纵向页可以共存,页眉页脚也各自独立,非常适合拼接结构差异较大的正式文档。
合并时保持源文档格式
按节克隆虽然保留了页面设置,但样式层面仍可能出现偏差:如果两份文档定义了同名的样式(比如都叫"正文"但字体不同),合并后目标文档的样式定义可能覆盖源文档的设定,导致段落外观发生变化。遇到这种情况,可以在合并前开启 KeepSameFormat 属性。
python
from spire.doc import *
from spire.doc.common import *
inputFile1 = "./Data/Sample.docx"
inputFile2 = "./Data/SampleB_1.docx"
outputFile = "KeepSameFormat.docx"
# 加载源文档与目标文档
srcDoc = Document()
srcDoc.LoadFromFile(inputFile1)
destDoc = Document()
destDoc.LoadFromFile(inputFile2)
# 让源文档在合并时保持自身格式
srcDoc.KeepSameFormat = True
# 将源文档的节复制到目标文档
for i in range(srcDoc.Sections.Count):
section = srcDoc.Sections.get_Item(i)
destDoc.Sections.Add(section.Clone())
# 保存结果
destDoc.SaveToFile(outputFile, FileFormat.Docx2013)
srcDoc.Close()
destDoc.Close()
KeepSameFormat 需要设置在源文档 对象上,它的作用是告诉库:在把内容搬过去时,连同样式定义一起携带,而不是改投目标文档的样式体系。这个属性必须在执行克隆操作之前设置才会生效。
如果合并后仍发现个别段落的字体不对,通常是因为两份文档使用了同名的样式但定义不同。这种情况下除了开启 KeepSameFormat,也可以在源文档中重命名冲突样式,从根源上避免覆盖。
合并到同一页
前面几种方式都会带来节与节之间的分隔,内容默认从新的一页开始。但有时我们希望两份文档的内容连续排布,中间不产生分页------比如把一段补充说明直接续在正文后面。这种情况下需要绕过节,直接在正文元素层面搬运内容。
python
from spire.doc import *
from spire.doc.common import *
inputFile1 = "./Data/Insert.docx"
inputFile2 = "./Data/TableOfContent.docx"
outputFile = "MergeDocsOnSamePage.docx"
# 加载源文档与目标文档
document = Document()
document.LoadFromFile(inputFile1)
destinationDocument = Document()
destinationDocument.LoadFromFile(inputFile2)
# 遍历源文档的节,再遍历节正文中的每个对象
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
for j in range(section.Body.ChildObjects.Count):
obj = section.Body.ChildObjects.get_Item(j)
# 逐个克隆到目标文档第一节的正文中
destinationDocument.Sections[0].Body.ChildObjects.Add(obj.Clone())
# 保存结果
destinationDocument.SaveToFile(outputFile, FileFormat.Docx)
document.Close()
destinationDocument.Close()
这段代码用两层循环深入到了 Body.ChildObjects,也就是段落、表格、图片这些具体的正文元素。由于没有新建节,所有内容都被放进目标文档的第一节,因而会自然地连续排列,不会因为节的分隔而另起一页。与之相对,前面按节克隆的方式每加一个节通常就会带来分页效果。
实用技巧
批量合并整个文件夹
把按节克隆的写法包装一下,配合 os 模块就能把一个文件夹里的文档按名称顺序合并成一份。下面的示例先对文件名排序,再依次追加,保证合并顺序可预期。
python
import os
from spire.doc import *
from spire.doc.common import *
input_dir = "./Data/Chapters"
outputFile = "Merged.docx"
# 按文件名排序,确保合并顺序稳定
files = sorted([f for f in os.listdir(input_dir) if f.lower().endswith(".docx")])
# 以第一份文档作为合并的基座
merged = Document()
merged.LoadFromFile(os.path.join(input_dir, files[0]))
# 依次把其余文档的节追加进来
for name in files[1:]:
doc = Document()
doc.LoadFromFile(os.path.join(input_dir, name))
for i in range(doc.Sections.Count):
merged.Sections.Add(doc.Sections.get_Item(i).Clone())
doc.Close()
merged.SaveToFile(outputFile, FileFormat.Docx2013)
merged.Close()
先用 sorted() 排序很重要,因为 os.listdir() 返回的顺序取决于文件系统,并不保证按名称排列。以第一份文档作为基座、其余依次追加的写法,也能自然地保留首份文档的样式与页面设置作为整篇的基准。
合并方式的选用建议
四种方式各有适用场景,可以按需选择:只拼接内容、不在意页面设置时用 InsertTextFromFile(),代码最少;需要保留各自的纸张方向、页边距、页眉页脚时按节克隆;两份文档样式体系不同、担心格式被覆盖时开启 KeepSameFormat;希望内容连续排布、中间不分页时则下沉到 ChildObjects 层面搬运。
另外提醒一点:合并后如果文档里出现了多余的分页符,通常是因为源文档最后一节恰好以分页结束。这时可以先在源文档中删除末尾的空段落,再执行合并,输出会更加干净。
小结
本文介绍了使用 Python 合并 Word 文档的四种做法:
InsertTextFromFile()--- 一行调用完成内容插入,FileFormat.Auto自动识别格式,适合快速拼接- 按节克隆 --- 通过
Sections.Add(sec.Clone())保留各文档独立的页面设置与页眉页脚 KeepSameFormat = True--- 设置在源文档上,避免同名样式被目标文档覆盖ChildObjects层面搬运 --- 绕过节结构,让内容连续排布而不产生分页
再配合 os 模块与 sorted() 做批量处理,就能把多份分散的文档稳定地整合成一份。实际使用时,建议先明确"要不要保留各自的页面设置"和"要不要连续排版"这两个问题,据此选择对应方式,合并效率与输出质量都会更有保障。