Python 将 Markdown 文件转换为 Word(docx)完整实现
在实际开发中,经常需要将 Markdown 文档导出为 Word(.docx),比如技术文档迁移、自动生成可下载的报告,或者在 FastAPI 等后端服务里集成文档导出功能。

这里分享一个不依赖外部接口、直接读取本地 Markdown 文件并生成 Word 文件的方案。核心思路是利用 markdown 库转 HTML,再用 BeautifulSoup 解析结构,最后通过 python-docx 映射到 Word 元素。支持标题、段落、列表、代码块、表格以及加粗斜体等常见语法。
环境准备
先安装必要的依赖库:
pip install python-docx markdown beautifulsoup4
核心逻辑与代码
整体流程是:Markdown → HTML → DOM 树遍历 → Docx 对象构建。
下面是一个完整的脚本示例,包含文件读取、内容解析和保存逻辑。为了便于维护,我把处理不同元素的函数拆分开了。
from docx import Document
from docx.shared import Pt
from bs4 import BeautifulSoup
import markdown
import uuid
import os
# 输出目录配置
FILE_DIR = "static"
os.makedirs(FILE_DIR, exist_ok=True)
def md_to_word(md_text: str) -> str:
"""
将 Markdown 文本转换为 Word,返回生成的文件名
"""
# 1. Markdown 转 HTML,开启 extra 扩展支持更多语法
html = markdown.markdown(
md_text, extensions=["extra", "tables", "fenced_code"]
)
soup = BeautifulSoup(html, "html.parser")
doc = Document()
# 2. 遍历 HTML 节点,映射为 Word 元素
for element in soup.contents:
handle_element(doc, element)
filename =
file_path = os.path.join(FILE_DIR, filename)
doc.save(file_path)
filename
():
(el, ) el.name :
el.name [, , , , , ]:
doc.add_heading(el.get_text(), level=(el.name[]))
el.name == :
p = doc.add_paragraph()
add_inline_text(p, el)
el.name == :
li el.find_all(, recursive=):
p = doc.add_paragraph(style=)
add_inline_text(p, li)
el.name == :
li el.find_all(, recursive=):
p = doc.add_paragraph(style=)
add_inline_text(p, li)
el.name == :
code_el = el.find()
code = code_el.get_text() code_el el.get_text()
p = doc.add_paragraph()
run = p.add_run(code)
run.font.name =
run.font.size = Pt()
el.name == :
rows = el.find_all()
cols = rows[].find_all([, ])
table = doc.add_table(rows=(rows), cols=(cols))
table.style =
r, row (rows):
c, cell (row.find_all([, ])):
paragraph = table.rows[r].cells[c].paragraphs[]
run = paragraph.add_run(cell.get_text())
cell.name == :
run.bold =
():
node el.contents:
(node, ):
paragraph.add_run(node)
:
run = paragraph.add_run(node.get_text())
node.name == :
run.bold =
node.name == :
run.italic =
node.name == :
run.font.name =
run.font.size = Pt()
() -> :
(md_file_path, , encoding=) f:
md_text = f.read()
md_to_word(md_text)
__name__ == :
md_path =
filename = md_to_word_from_file(md_path)
(, filename)


