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)
# 3. 生成带 UUID 的文件名并保存
filename = f"{uuid.uuid4().hex}.docx"
file_path = os.path.join(FILE_DIR, filename)
doc.save(file_path)
return filename
def handle_element(doc, el):
"""根据 HTML 标签类型调用对应的处理方法"""
if not hasattr(el, "name") or el.name is None:
return
# 标题 (h1-h6)
if el.name in ["h1", "h2", "h3", "h4", "h5", "h6"]:
doc.add_heading(el.get_text(), level=int(el.name[1]))
return
# 段落
if el.name == "p":
p = doc.add_paragraph()
add_inline_text(p, el)
return
# 无序列表
if el.name == "ul":
for li in el.find_all("li", recursive=False):
p = doc.add_paragraph(style="List Bullet")
add_inline_text(p, li)
return
# 有序列表
if el.name == "ol":
for li in el.find_all("li", recursive=False):
p = doc.add_paragraph(style="List Number")
add_inline_text(p, li)
return
# 代码块
if el.name == "pre":
code_el = el.find("code")
code = code_el.get_text() if code_el else el.get_text()
p = doc.add_paragraph()
run = p.add_run(code)
run.font.name = "Courier New"
run.font.size = Pt(10)
return
# 表格
if el.name == "table":
rows = el.find_all("tr")
cols = rows[0].find_all(["th", "td"])
table = doc.add_table(rows=len(rows), cols=len(cols))
table.style = "Table Grid"
for r, row in enumerate(rows):
for c, cell in enumerate(row.find_all(["th", "td"])):
paragraph = table.rows[r].cells[c].paragraphs[0]
run = paragraph.add_run(cell.get_text())
if cell.name == "th":
run.bold = True
def add_inline_text(paragraph, el):
"""处理行内样式:加粗、斜体、行内代码"""
for node in el.contents:
if isinstance(node, str):
paragraph.add_run(node)
else:
run = paragraph.add_run(node.get_text())
if node.name == "strong":
run.bold = True
elif node.name == "em":
run.italic = True
elif node.name == "code":
run.font.name = "Courier New"
run.font.size = Pt(10)
def md_to_word_from_file(md_file_path: str) -> str:
"""从 Markdown 文件生成 Word"""
with open(md_file_path, "r", encoding="utf-8") as f:
md_text = f.read()
return md_to_word(md_text)
if __name__ == "__main__":
md_path = "jd.md" # 替换为你的 Markdown 文件路径
filename = md_to_word_from_file(md_path)
print("生成的 Word 文件:", filename)
运行说明
- 确保当前目录下有 Markdown 文件(例如
jd.md)。 - 运行脚本:
python script_name.py - 程序会在
static/目录下生成一个.docx文件,文件名由 UUID 随机生成。
后续优化方向
这个方案已经覆盖了大部分基础场景,如果项目需要更精细的控制,可以考虑以下扩展点:
- 图片支持:目前未处理
<img>标签,需额外编写图片下载与插入逻辑。 - 样式增强:自定义字体、行距、页眉页脚或特定标题样式。
- 代码高亮:引入 Pygments 等库对代码块进行着色。
- Web 集成:封装成 FastAPI 接口,供前端触发下载。
总结
这套方案轻量、可控且易于扩展,特别适合后端服务或本地脚本使用。相比依赖在线转换 API,这种方式在数据隐私和稳定性上更有优势。如果你需要在现有系统中增加文档导出功能,可以直接在此基础上调整。


