先明确一个结论:不能完全保持。
docxcompose能保留段落样式、字体、列表层级和图片位置,但页眉页脚、分节符、文本框、表格嵌套样式、OLE对象(比如嵌入的Excel图表)大概率会丢失或错位。如果你的文档里头有页码、奇偶页不同、封面独立节,那合并后这些统统失效——这几乎是必然的,因为它本质上是“内容拼接”,不是“文档叠加”。
说得直接点,这种方案适合的场景是:多个结构相似、没有复杂排版的报告、简报或实验记录合并。但如果你要处理的是合同终稿、带审批痕迹的公文、或者需要打印装订的正式材料,那还是绕道吧。

docxcompose 能否真正保持原始格式?
答案已经说了:不能完全保持。它会保留的是段落样式、字体、列表层级和图片位置,但页眉页脚、分节符、文本框、表格嵌套样式、OLE对象(如Excel图表)大概率丢失或错位。如果你的文档含页码、奇偶页不同、封面独立节,docxcompose 合并后这些全部失效——它本质是“内容拼接”,不是“文档叠加”。
适用场景:多个结构相似、无复杂排版的报告/简报/实验记录合并;不适用:合同终稿、带审批痕迹的公文、需打印装订的正式材料。
安装与基础合并代码怎么写?
先确认 Python ≥ 3.7,然后用 pip 安装两个依赖:
pip install python-docx docxcompose
注意:docxcompose 不维护了(最后更新 2019),它依赖旧版 python-docx(≤ 0.8.10)。若你已装新版 python-docx(如 1.0+),必须降级,否则运行时报 AttributeError: 'Document' object has no attribute 'element':
pip uninstall python-docx -y && pip install python-docx==0.8.11
基础合并示例(按文件名顺序拼接):
from docxcompose.composer import Composer
from docx import Document
master = Document() # 空文档作容器
composer = Composer(master)
for doc_path in ["a.docx", "b.docx", "c.docx"]:
doc = Document(doc_path)
composer.append(doc)
composer.sa ve("merged.docx")为什么合并后标题编号乱了、样式变样?
因为 docxcompose 不继承源文档的 styles.xml 和编号定义(numbering.xml),所有样式都 fallback 到 master 文档的默认样式。结果就是:原 Heading 1 可能变成普通正文,多级列表编号重置为 1, 1, 1…
缓解办法只有两个:
- 手动在
master = Document()后,用master.styles.add_style(...)预定义好所有要用的样式(麻烦且难对齐) - 改用
master = Document("template.docx"),其中template.docx是你导出的一个含完整样式的空模板——这是最实际的做法
另外,每个被 append 的文档开头会自动加一个分页符,无法关闭;若不想分页,得在 append 前手动删掉源文档最后一段的 paragraph._element 分页属性(不推荐,易出错)。
有没有更稳的替代方案?
有,但要接受取舍:
- 用 Windows + Word COM 自动化(仅限 Windows):调
win32com.client打开 Word 实例,执行InsertFile,格式保留度最高,但慢、需本地装 Word、不能跑在服务器 - 用 Pandoc + 自定义参考文档:转成 Markdown 再转回 DOCX,配合
--reference-doc指向样式模板,适合纯文字为主、样式较统一的场景 - 放弃“零修改合并”,改用
python-docx手动读取每份文档的document.paragraphs和document.tables,逐个 clone 到新文档——可控性强,但页眉页脚、脚注、题注仍需额外处理
真正容易被忽略的一点:所有方案都无法还原“修订模式”下的批注和删除线。如果源文档开启了跟踪更改,合并后那些红色批注全消失,且不可逆。