转换Word文档到Markdown:Python工具
在技术写作和博客创作中,Markdown因其简洁的语法和跨平台兼容性备受青睐。然而,从Word文档转换到Markdown往往面临格式丢失、图片处理繁琐等问题。本文将介绍一款自主开发的Python工具docx2md
,实现Word文档(包含文本、图片、表格)到Markdown的自动化转换,大幅提升内容迁移效率。
一、工具核心功能解析
1. 全面的格式支持
- 文本格式:自动识别标题(Heading 1-9)、加粗(加粗)、斜体(斜体),下划线通过HTML标签
<u>下划线</u>
兼容 - 多媒体处理:智能提取Word中的嵌入式图片,生成独立
images
文件夹并自动添加Markdown图片引用 - 表格转换:支持复杂表格结构,自动生成Markdown表格语法(含表头分隔线)
- 结构保留:维持原文档的段落顺序和层次结构
2. 可视化操作界面
基于Tkinter开发的图形化界面(GUI),无需记忆命令行参数:
- 文件选择对话框智能过滤.docx文件
- 输出目录可选(默认使用原文件目录)
- 实时反馈转换结果,成功/错误信息弹窗提示
二、环境准备与安装
1. 依赖库安装
pip install python-docx>=0.8.10 # 核心文档解析库
提示:Tkinter为Python内置标准库,无需额外安装
2. 系统兼容性
- 支持Windows/macOS/Linux全平台
- Python版本要求:使用3.9.13编写,其他版本自行测试
三、三步完成转换流程
1. 启动工具
python docx2md.py
首次运行会显示极简主窗口(自动隐藏,仅保留对话框)
2. 选择目标文件
在弹出的文件对话框中选择需要转换的.docx文档(支持中文文件名)
3. 配置输出路径
- 推荐使用默认路径(与原文件同目录)
- 自定义目录时支持中文路径和多级目录
4. 等待转换完成
- 转换进度通过弹窗反馈
- 成功后自动定位Markdown文件保存路径
四、输出结果规范
1. 文件结构
目标目录/
├─ 原文件名.md # 生成的Markdown文件
└─ images/ # 图片资源文件夹
├─ image_0.png
├─ image_1.png
└─ ...
2. 格式示例
标题转换
Heading 1 → # 标题1
Heading 2 → ## 标题2
...
文本格式
Word格式 | Markdown |
---|---|
加粗 | 加粗文本 |
斜体 | 斜体文本 |
下划线 | 下划线文本 |
图片引用
自动生成:
表格转换
表头1 | 表头2 |
---|---|
内容1 | 内容2 |
五、使用注意事项
- 格式限制:
- 暂不支持复杂样式(如脚注、批注、修订痕迹)
- 嵌套表格/艺术字/公式等特殊元素可能无法正确解析
- 最佳实践:
- 转换前建议清理冗余格式(通过Word的「清除格式」功能)
- 复杂文档转换后建议通过Typora等工具进行格式校验
- 错误处理:
- 转换过程中错误会在控制台输出具体段落/表格编号
- 严重错误会弹出详细报错信息,便于定位问题
六、完整源代码(docx2md.py)
import os
import re
import sys
import docx
import base64
import tkinter as tk
from tkinter import filedialog, messagebox
from docx.shared import Pt
from docx.oxml.ns import qn
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.style import WD_STYLE_TYPE
from docx.opc.constants import RELATIONSHIP_TYPE as RT
from docx.oxml import OxmlElement
def extract_images(doc):
"""从Word文档中提取所有图片"""
image_dict = {}
image_index = 0
# 遍历文档中的关系
for rel in doc.part.rels.values():
# 检查关系类型是否为图片
if rel.reltype == RT.IMAGE:
# 获取图片数据
image_data = rel.target_part.blob
# 生成图片文件名
image_name = f"image_{image_index}.png"
image_index += 1
# 存储图片数据和关系ID
image_dict[rel.rId] = {
"data": image_data,
"name": image_name
}
return image_dict
def save_images(image_dict, output_dir):
"""保存提取的图片到指定目录"""
img_dir = os.path.join(output_dir, "images")
os.makedirs(img_dir, exist_ok=True)
for rel_id, img_info in image_dict.items():
img_path = os.path.join(img_dir, img_info["name"])
with open(img_path, "wb") as f:
f.write(img_info["data"])
return img_dir
def convert_paragraph_to_markdown(paragraph, image_dict):
"""将段落转换为Markdown格式"""
md_text = ""
# 处理段落样式(标题识别)
if paragraph.style.name.startswith('Heading'):
level = paragraph.style.name.replace('Heading ', '')
try:
level = int(level)
md_text += "#" * level + " "
except ValueError:
pass # 处理异常样式
# 处理段落中的文本和图片
for run in paragraph.runs:
text = run.text
# 加粗处理
if run.bold:
text = f"**{text}**"
# 斜体处理
if run.italic:
text = f"*{text}*"
# 下划线处理(Markdown不原生支持,使用HTML标签)
if run.underline:
text = f"<u>{text}</u>"
md_text += text
# 检查段落是否包含图片(通过关系ID在XML中存在性判断)
for rel_id, img_info in image_dict.items():
if rel_id in paragraph._element.xml:
md_text += f"\n\n![{img_info['name']}](images/{img_info['name']})\n\n"
return md_text
def convert_table_to_markdown(table):
"""将表格转换为Markdown格式"""
md_table = "\n"
# 处理表头
header_row = table.rows[0]
md_table += "|" + "|".join([cell.text for cell in header_row.cells]) + "|\n"
# 添加分隔行
md_table += "|" + "|".join(["---" for _ in header_row.cells]) + "|\n"
# 处理表格内容行
for row in table.rows[1:]:
md_table += "|" + "|".join([cell.text for cell in row.cells]) + "|\n"
return md_table + "\n"
def docx_to_markdown(docx_path, output_dir=None):
"""核心转换函数:Word文档转Markdown"""
if output_dir is None:
output_dir = os.path.dirname(docx_path) # 使用原文件目录
doc = docx.Document(docx_path)
image_dict = extract_images(doc)
# 保存图片(如果有的话)
if image_dict:
save_images(image_dict, output_dir)
# 生成Markdown文件路径
md_filename = os.path.splitext(os.path.basename(docx_path))[0] + ".md"
md_path = os.path.join(output_dir, md_filename)
md_content = ""
# 处理段落
for i, paragraph in enumerate(doc.paragraphs):
try:
md_content += convert_paragraph_to_markdown(paragraph, image_dict) + "\n\n"
except Exception as e:
print(f"段落处理错误({i}): {str(e)}")
continue # 跳过错误段落
# 处理表格
for i, table in enumerate(doc.tables):
try:
md_content += convert_table_to_markdown(table)
except Exception as e:
print(f"表格处理错误({i}): {str(e)}")
continue # 跳过错误表格
# 写入文件
with open(md_path, "w", encoding="utf-8") as f:
f.write(md_content)
return md_path
def main():
# 初始化GUI
root = tk.Tk()
root.title("Word转Markdown工具")
root.geometry("500x300")
root.withdraw() # 隐藏主窗口,仅显示对话框
# 选择Word文件
docx_path = filedialog.askopenfilename(
title="选择待转换的Word文档",
filetypes=[("Word文档", "*.docx"), ("所有文件", "*.*")]
)
if not docx_path:
sys.exit(0) # 用户取消操作
if not os.path.exists(docx_path):
messagebox.showerror("错误", f"文件不存在:{docx_path}")
sys.exit(1)
# 选择输出目录
output_dir = filedialog.askdirectory(
title="选择输出目录(取消则使用原文件目录)"
)
if not output_dir:
output_dir = None # 使用默认目录
# 执行转换
try:
md_path = docx_to_markdown(docx_path, output_dir)
messagebox.showinfo("成功", f"转换完成!\n保存路径:{md_path}")
except Exception as e:
messagebox.showerror("错误", f"转换失败:{str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()
七、扩展与改进建议
- 功能增强:
- 添加对脚注、公式(如Mermaid图表)的支持
- 增加命令行参数模式(非GUI版本)
- 支持更多图片格式(如JPEG、GIF)
- 错误处理:
- 增加详细的日志记录功能
- 实现转换进度条显示
- 格式优化:
- 支持列表(有序/无序列表)转换
- 改进标题层级识别逻辑
通过这款工具,我们可以快速将Word文档转换为结构清晰的Markdown文件,尤其适合技术文档迁移、博客内容复用等场景。建议在复杂文档转换后进行格式校验,确保最佳显示效果。欢迎在评论区分享你的使用体验或提出改进建议!