Python 将 Markdown 文件转换为 Word(docx)完整实现
在实际开发中,经常会遇到将 Markdown 文档转换为 Word(.docx)的需求,例如:
-
技术文档从 Markdown 迁移到 Word
-
自动生成可下载的 Word 报告
-
与 Dify、FastAPI 等系统结合做文档导出

本文基于 python-docx + markdown + BeautifulSoup ,实现一个不依赖接口、直接读取 Markdown 文件并生成 Word 文件的完整方案,支持常见 Markdown 语法。
一、实现思路说明
整体转换流程如下:
-
使用
markdown库将 Markdown 文本转换为 HTML -
使用
BeautifulSoup解析 HTML 结构 -
遍历 HTML 节点,映射为 Word 中的对应元素
-
使用
python-docx生成并保存.docx文件
支持的 Markdown 元素包括:
-
标题(h1--h6)
-
段落
-
无序 / 有序列表
-
代码块
-
行内代码、加粗、斜体
-
表格
二、依赖安装
bash
pip install python-docx markdown beautifulsoup4
三、完整代码实现
python
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,返回生成的文件名
"""
html = markdown.markdown(
md_text,
extensions=["extra", "tables", "fenced_code"]
)
soup = BeautifulSoup(html, "html.parser")
doc = Document()
for element in soup.contents:
handle_element(doc, element)
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):
if not hasattr(el, "name") or el.name is None:
return
# 标题
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)放到当前目录 -
运行脚本:
bash
python md_to_word.py
- 程序会在
static/目录下生成一个.docx文件,文件名为 UUID
五、适用场景
-
FastAPI / Flask 文档导出
-
Dify 工作流中生成 Word 报告
-
Markdown 文档批量转 Word
-
内部系统自动生成可编辑文档
六、可优化方向
-
增加图片(
img)支持 -
支持代码高亮样式
-
表格列宽自适应
-
自定义标题样式、字体、行距
-
与 FastAPI 接口结合返回下载地址
七、总结
本文实现了一个轻量、可控、易扩展的 Markdown 转 Word 方案 ,不依赖外部接口,适合后端服务或本地脚本使用。
对于需要文档导出、报告生成的场景,这种方式在稳定性和可维护性上都具有明显优势。
如果你后续需要 FastAPI 接口版 、Dify 工作流集成版 或 样式增强版,可以在此基础上直接扩展。