python將Markdown文件格式轉(zhuǎn)為Word文檔的示例代碼
一、核心方案說(shuō)明
要實(shí)現(xiàn) Markdown 文件 → Word(.docx) 文件 的格式轉(zhuǎn)換,核心思路是:
- 先用
python-markdown庫(kù)把 Markdown 文本/文件解析成 HTML 格式; - 再用
python-docx庫(kù)將解析后的 HTML 內(nèi)容,逐節(jié)點(diǎn)渲染到 Word 文檔中,完成最終轉(zhuǎn)換。
二、完整環(huán)境安裝(一鍵執(zhí)行)
該方案依賴 3 個(gè)核心庫(kù),直接在終端執(zhí)行以下命令安裝所有依賴:
pip install python-markdown python-docx beautifulsoup4
python-markdown:核心 Markdown 解析庫(kù),負(fù)責(zé) MD → HTML;python-docx:核心 Word 操作庫(kù),負(fù)責(zé)生成/編輯 .docx 文檔;beautifulsoup4:輔助解析 HTML 節(jié)點(diǎn),方便精準(zhǔn)提取內(nèi)容渲染到 Word。
三、完整可運(yùn)行代碼(直接復(fù)用)
版本1:基礎(chǔ)版(支持絕大多數(shù) MD 語(yǔ)法,滿足日常需求)
支持標(biāo)題(1-6級(jí))、段落、加粗、斜體、有序列表、無(wú)序列表、超鏈接、圖片、換行等核心語(yǔ)法,代碼可直接復(fù)制運(yùn)行:
import markdown
from docx import Document
from docx.shared import Pt, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
from bs4 import BeautifulSoup
import os
def markdown_to_word(md_file_path, docx_file_path=None):
"""
Markdown文件轉(zhuǎn)Word文檔核心函數(shù)
:param md_file_path: 源Markdown文件路徑(必填,如:./test.md)
:param docx_file_path: 輸出Word文件路徑(可選,默認(rèn)同目錄同名.docx)
"""
# 1. 校驗(yàn)源文件是否存在
if not os.path.exists(md_file_path):
print(f"錯(cuò)誤:源文件 {md_file_path} 不存在!")
return
# 2. 默認(rèn)輸出路徑(同目錄、同名,后綴替換為.docx)
if docx_file_path is None:
docx_file_path = os.path.splitext(md_file_path)[0] + ".docx"
# 3. 讀取Markdown文件內(nèi)容(指定UTF-8編碼,避免中文亂碼)
with open(md_file_path, "r", encoding="utf-8") as f:
md_content = f.read()
# 4. Markdown → HTML(啟用擴(kuò)展,支持更完整語(yǔ)法)
html_content = markdown.markdown(
md_content,
extensions=[
'extra', # 支持表格、代碼塊、腳注等擴(kuò)展語(yǔ)法
'sane_lists', # 優(yōu)化列表解析規(guī)則
'nl2br' # 換行符\n轉(zhuǎn)為HTML的<br>標(biāo)簽
],
extension_configs={}
)
# 5. 初始化Word文檔對(duì)象
doc = Document()
# 6. 全局樣式配置(統(tǒng)一字體、避免中文宋體異常)
doc.styles['Normal'].font.name = '宋體'
doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')
doc.styles['Normal'].font.size = Pt(12) # 正文字號(hào)12號(hào)
# 7. 解析HTML并渲染到Word
soup = BeautifulSoup(html_content, "html.parser")
parse_html_node(soup, doc)
# 8. 保存Word文檔
doc.save(docx_file_path)
print(f"轉(zhuǎn)換成功!Word文件已保存至:{docx_file_path}")
def parse_html_node(node, doc):
"""遞歸解析HTML節(jié)點(diǎn),映射為Word對(duì)應(yīng)樣式"""
# 處理標(biāo)題(h1-h6)
if node.name in [f'h{i}' for i in range(1,7)]:
level = int(node.name[1])
p = doc.add_paragraph()
run = p.add_run(node.get_text(strip=True))
# 標(biāo)題樣式:字號(hào)隨級(jí)別遞減,加粗
run.font.size = Pt(20 - level * 2)
run.font.bold = True
run.font.name = '黑體'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑體')
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
# 處理段落
elif node.name == 'p':
p = doc.add_paragraph()
parse_inline_content(node, p)
# 處理無(wú)序列表
elif node.name == 'ul':
for li in node.find_all('li', recursive=False):
p = doc.add_paragraph(style='List Bullet')
parse_inline_content(li, p)
# 處理有序列表
elif node.name == 'ol':
for li in node.find_all('li', recursive=False):
p = doc.add_paragraph(style='List Number')
parse_inline_content(li, p)
# 處理?yè)Q行
elif node.name == 'br':
doc.add_paragraph()
# 遞歸處理子節(jié)點(diǎn)(兼容嵌套結(jié)構(gòu))
for child in node.children:
if child.name:
parse_html_node(child, doc)
def parse_inline_content(node, paragraph):
"""解析行內(nèi)元素(加粗、斜體、超鏈接等),添加到指定段落"""
for content in node.contents:
if isinstance(content, str):
# 純文本內(nèi)容
run = paragraph.add_run(content)
run.font.name = '宋體'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')
run.font.size = Pt(12)
elif content.name == 'strong':
# 加粗文本(MD:**內(nèi)容**)
run = paragraph.add_run(content.get_text())
run.font.bold = True
run.font.name = '宋體'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')
elif content.name == 'em':
# 斜體文本(MD:*內(nèi)容*)
run = paragraph.add_run(content.get_text())
run.font.italic = True
run.font.name = '宋體'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')
elif content.name == 'a':
# 超鏈接(MD:[文本](鏈接))
text = content.get_text()
link = content.get('href', '')
run = paragraph.add_run(f"{text}({link})")
run.font.color.rgb = None # 可自定義鏈接顏色
run.font.name = '宋體'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')
# ------------------- 調(diào)用示例 -------------------
if __name__ == "__main__":
# 替換為你的Markdown文件路徑(相對(duì)路徑/絕對(duì)路徑均可)
INPUT_MD_FILE = "./test.md"
# 可選:指定輸出Word路徑,如 "./轉(zhuǎn)換結(jié)果.docx"
OUTPUT_DOCX_FILE = None
markdown_to_word(INPUT_MD_FILE, OUTPUT_DOCX_FILE)
版本2:增強(qiáng)版(額外支持 表格、代碼塊、圖片 語(yǔ)法)
日常使用中表格、代碼塊、圖片是高頻 MD 語(yǔ)法,在基礎(chǔ)版上擴(kuò)展該能力,滿足更復(fù)雜的轉(zhuǎn)換需求:
import markdown
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from bs4 import BeautifulSoup
import os
def markdown_to_word(md_file_path, docx_file_path=None):
if not os.path.exists(md_file_path):
print(f"錯(cuò)誤:源文件 {md_file_path} 不存在!")
return
if docx_file_path is None:
docx_file_path = os.path.splitext(md_file_path)[0] + ".docx"
with open(md_file_path, "r", encoding="utf-8") as f:
md_content = f.read()
# 啟用表格、代碼塊擴(kuò)展
html_content = markdown.markdown(
md_content,
extensions=['extra', 'sane_lists', 'nl2br', 'codehilite'],
extension_configs={}
)
doc = Document()
doc.styles['Normal'].font.name = '宋體'
doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')
doc.styles['Normal'].font.size = Pt(12)
soup = BeautifulSoup(html_content, "html.parser")
parse_html_node(soup, doc)
doc.save(docx_file_path)
print(f"轉(zhuǎn)換成功!Word文件已保存至:{docx_file_path}")
def parse_html_node(node, doc):
# 基礎(chǔ)節(jié)點(diǎn)(標(biāo)題、段落、列表)- 同基礎(chǔ)版,此處省略,完整代碼包含
if node.name in [f'h{i}' for i in range(1,7)]:
level = int(node.name[1])
p = doc.add_paragraph()
run = p.add_run(node.get_text(strip=True))
run.font.size = Pt(20 - level * 2)
run.font.bold = True
run.font.name = '黑體'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑體')
elif node.name == 'p':
p = doc.add_paragraph()
parse_inline_content(node, p)
elif node.name == 'ul':
for li in node.find_all('li', recursive=False):
p = doc.add_paragraph(style='List Bullet')
parse_inline_content(li, p)
elif node.name == 'ol':
for li in node.find_all('li', recursive=False):
p = doc.add_paragraph(style='List Number')
parse_inline_content(li, p)
# 新增:處理表格
elif node.name == 'table':
rows = node.find_all('tr')
row_count = len(rows)
col_count = len(rows[0].find_all(['th', 'td'])) if row_count > 0 else 0
if row_count == 0 or col_count == 0: return
# 創(chuàng)建Word表格
table = doc.add_table(rows=row_count, cols=col_count)
table.alignment = WD_TABLE_ALIGNMENT.CENTER
for r_idx, row in enumerate(rows):
cells = row.find_all(['th', 'td'])
for c_idx, cell in enumerate(cells):
tc = table.cell(r_idx, c_idx)
tc.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
p = tc.paragraphs[0]
parse_inline_content(cell, p)
# 表頭樣式加粗
if cell.name == 'th':
for run in p.runs:
run.font.bold = True
# 新增:處理代碼塊
elif node.name == 'pre':
code_node = node.find('code')
if code_node:
p = doc.add_paragraph()
run = p.add_run(code_node.get_text())
run.font.name = 'Consolas' # 代碼專用等寬字體
run.font.size = Pt(10)
run.font.color.rgb = RGBColor(0, 0, 0) # 黑色
# 新增:處理圖片(MD:)
elif node.name == 'img':
img_src = node.get('src', '')
img_alt = node.get('alt', '圖片')
if os.path.exists(img_src):
try:
doc.add_picture(img_src, width=Inches(4)) # 限制圖片寬度
p = doc.add_paragraph(img_alt)
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
except Exception as e:
doc.add_paragraph(f"圖片加載失?。簕img_src} | 錯(cuò)誤:{str(e)}")
else:
doc.add_paragraph(f"圖片不存在:{img_src}(描述:{img_alt})")
for child in node.children:
if child.name:
parse_html_node(child, doc)
def parse_inline_content(node, paragraph):
# 行內(nèi)元素(加粗、斜體、超鏈接)- 同基礎(chǔ)版
for content in node.contents:
if isinstance(content, str):
run = paragraph.add_run(content)
run.font.name = '宋體'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')
run.font.size = Pt(12)
elif content.name == 'strong':
run = paragraph.add_run(content.get_text())
run.font.bold = True
elif content.name == 'em':
run = paragraph.add_run(content.get_text())
run.font.italic = True
elif content.name == 'a':
text = content.get_text()
link = content.get('href', '')
run = paragraph.add_run(f"{text}({link})")
# ------------------- 調(diào)用示例 -------------------
if __name__ == "__main__":
INPUT_MD_FILE = "./test.md" # 替換為你的MD文件路徑
markdown_to_word(INPUT_MD_FILE)
四、使用方法(3步極簡(jiǎn)操作)
步驟1:準(zhǔn)備源文件
將需要轉(zhuǎn)換的 Markdown 文件(如 test.md)放在代碼同目錄下,或填寫(xiě)絕對(duì)路徑(如 C:/文檔/我的筆記.md)。
步驟2:修改文件路徑
在代碼末尾的 if __name__ == "__main__": 塊中,替換 INPUT_MD_FILE 為你的 MD 文件路徑:
INPUT_MD_FILE = "./你的文件.md" # 相對(duì)路徑 # 或 INPUT_MD_FILE = "D:/project/note.md" # 絕對(duì)路徑
步驟3:運(yùn)行代碼
直接執(zhí)行該 Python 文件,終端輸出 轉(zhuǎn)換成功! 即完成,轉(zhuǎn)換后的 Word 文件會(huì)保存在同目錄(默認(rèn))或你指定的路徑下。
五、關(guān)鍵優(yōu)化點(diǎn)(解決常見(jiàn)坑)
坑1:中文亂碼/字體異常
- 解決方案:為所有文字節(jié)點(diǎn)指定中文字體(宋體/黑體),通過(guò)
qn('w:eastAsia')強(qiáng)制生效; - 核心代碼:
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')。
坑2:Markdown 語(yǔ)法解析不全
解決方案:?jiǎn)⒂?python-markdown 的擴(kuò)展庫(kù)(extra/codehilite),支持表格、代碼塊、腳注等擴(kuò)展語(yǔ)法。
坑3:列表嵌套/格式錯(cuò)亂
解決方案:用 recursive=False 限制列表子節(jié)點(diǎn)解析層級(jí),配合 Word 內(nèi)置的 List Bullet/List Number 樣式,保證列表格式統(tǒng)一。
坑4:圖片加載失敗
解決方案:增加圖片路徑校驗(yàn),若路徑不存在則在 Word 中提示錯(cuò)誤信息,避免程序崩潰。
六、支持的 Markdown 語(yǔ)法清單
基礎(chǔ)語(yǔ)法(基礎(chǔ)版+增強(qiáng)版均支持)
- 標(biāo)題:
# 一級(jí)標(biāo)題~###### 六級(jí)標(biāo)題 - 段落:自然換行/空行分隔
- 加粗:
**加粗內(nèi)容** - 斜體:
*斜體內(nèi)容* - 無(wú)序列表:
- 列表項(xiàng)1/* 列表項(xiàng)1 - 有序列表:
1. 列表項(xiàng)1/2. 列表項(xiàng)2 - 超鏈接:
[鏈接文本](鏈接地址)
擴(kuò)展語(yǔ)法(僅增強(qiáng)版支持)
- 表格:
| 表頭1 | 表頭2 |+|---|---|+| 內(nèi)容1 | 內(nèi)容2 | - 代碼塊:
python 代碼內(nèi)容 - 圖片:
 - 換行:
\n或<br>
七、備選方案(更輕量化,一行命令轉(zhuǎn)換)
如果需要極簡(jiǎn)、無(wú)代碼的轉(zhuǎn)換方案,推薦使用成熟工具 pandoc,比手動(dòng)開(kāi)發(fā)的腳本支持的語(yǔ)法更全、兼容性更強(qiáng):
1. 安裝 pandoc
- Windows:
winget install pandoc - Mac:
brew install pandoc - Linux:
sudo apt install pandoc
2. 一行命令轉(zhuǎn)換
pandoc -s 你的文件.md -o 輸出文件.docx
優(yōu)勢(shì):支持所有 Markdown 語(yǔ)法(公式、腳注、目錄、引用等),無(wú)需編寫(xiě)代碼,轉(zhuǎn)換速度極快。
總結(jié)
- 手動(dòng)開(kāi)發(fā)方案(python-markdown + python-docx):適合需要自定義轉(zhuǎn)換規(guī)則(如字體、樣式、格式)的場(chǎng)景,代碼可靈活擴(kuò)展;
- 工具方案(pandoc):適合快速批量轉(zhuǎn)換,無(wú)需開(kāi)發(fā),開(kāi)箱即用,兼容性最優(yōu);
- 核心避坑:處理中文時(shí)必須指定中文字體 + UTF-8 編碼,解析列表時(shí)限制遞歸層級(jí)。
兩種方案均可滿足 Markdown → Word 的轉(zhuǎn)換需求,可根據(jù)實(shí)際場(chǎng)景選擇。
到此這篇關(guān)于python將Markdown文件格式轉(zhuǎn)為Word文檔的示例代碼的文章就介紹到這了,更多相關(guān)python Markdown轉(zhuǎn)Word內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python將Markdown文件轉(zhuǎn)換為Word(docx)完整教學(xué)
- 基于Python實(shí)現(xiàn)Markdown與Word高保真互轉(zhuǎn)
- 使用Python實(shí)現(xiàn)Markdown轉(zhuǎn)Word工具
- 使用Python將Markdown文件轉(zhuǎn)換為Word的三種方法
- Python實(shí)現(xiàn)快速提取Word表格并轉(zhuǎn)Markdown
- Python使用pypandoc將markdown文件和LaTex公式轉(zhuǎn)為word
- Python將Word文檔轉(zhuǎn)換為Markdown格式
- Python文檔轉(zhuǎn)換之Markdown轉(zhuǎn)Word的高效實(shí)戰(zhàn)指南
相關(guān)文章
Python+Selenium實(shí)現(xiàn)瀏覽器的控制操作
這篇文章主要為大家詳細(xì)介紹了Python+Selenium如何實(shí)現(xiàn)常見(jiàn)的瀏覽器控制操作,例如:瀏覽器參數(shù)設(shè)置、控制瀏覽器前進(jìn)/后退等,感興趣的可以了解一下2022-09-09
Python爬蟲(chóng)實(shí)現(xiàn)爬取京東手機(jī)頁(yè)面的圖片(實(shí)例代碼)
下面小編就為大家分享一篇Python爬蟲(chóng)實(shí)現(xiàn)爬取京東手機(jī)頁(yè)面的圖片實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
python實(shí)現(xiàn)反轉(zhuǎn)部分單向鏈表
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)反轉(zhuǎn)部分單向鏈表,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09
python實(shí)現(xiàn)RSA加密(解密)算法
RSA是目前最有影響力的公鑰加密算法,它能夠抵抗到目前為止已知的絕大多數(shù)密碼攻擊,已被ISO推薦為公鑰數(shù)據(jù)加密標(biāo)準(zhǔn),下面通過(guò)本文給大家介紹python實(shí)現(xiàn)RSA加密(解密)算法,需要的朋友參考下2016-02-02
Python開(kāi)源自動(dòng)化工具Playwright安裝及介紹使用
playwright-python是一個(gè)強(qiáng)大的Python庫(kù),僅用一個(gè)API即可自動(dòng)執(zhí)行Chromium、Firefox、WebKit等主流瀏覽器自動(dòng)化操作,本文就詳細(xì)的介紹一下如何使用,感興趣的可以了解一下2021-12-12
python實(shí)現(xiàn)將Word文檔中的文字轉(zhuǎn)換成語(yǔ)音的操作步驟
Python實(shí)現(xiàn)朗讀在線音頻和本地音頻

