python-docx无法直接解析html,需用pandoc命令行工具转换,调用时须加--standalone和--variable mainfont指定中文字体,并用subprocess.run安全执行。

用 python-docx 直接写 Word?不行,它不解析 HTML
想靠 python-docx 把 HTML 字符串塞进去生成 .docx?会报错或只显示纯文本。python-docx 只管构造 Word 的底层 XML 结构,根本不认识 <div>、<code><table> 这些标签。它不是渲染引擎,也不是 HTML 转换器。
<p>真正能吃 HTML 并转成 Word 文档的库,目前稳定可用的是 <code>docxtpl(配合模板)或更直接的 weasyprint + PDF 中转,但最轻量、最贴近“HTML 原样转 Word”需求的,其实是 pandoc 命令行工具 —— 它背后调用的是成熟的文档转换管道。
-
pandoc支持直接读取 HTML 文件并输出.docx,保留基本样式(标题、列表、表格、链接) - 不需要写 Python 脚本也能跑通,适合 CI/CD 或临时批量处理
- 如果必须在 Python 里调用,用
subprocess.run()启动pandoc即可,别自己造解析轮子
pandoc 转换时字体/中文乱码怎么解决
默认导出的 .docx 经常出现中文字体缺失、段落缩进错乱、甚至整个文档变成等宽字体 —— 这不是 HTML 写得有问题,而是 pandoc 默认不嵌入 CSS 样式,也不指定 Word 主题字体。
- 必须加参数
--standalone,否则只生成片段,Word 打开会提示“内容已损坏” - 中文显示异常?加
--variable mainfont="Microsoft YaHei"(或你系统里实际存在的中文字体名) - 如果 HTML 里用了内联
style或外部 CSS,pandoc默认忽略;想部分生效,得用--css=xxx.css,且 CSS 规则要简单(只支持有限属性,比如color、font-weight,不支持flex或grid) - 导出前先用浏览器打开 HTML 确认能正常渲染,
pandoc不会执行 JS,也不会加载远程字体链接
Python 脚本里安全调用 pandoc 的几个硬约束
别用 os.system() 拼接路径和文件名,HTML 文件名带空格或中文就直接失败;也别假设用户一定装了 pandoc —— 缺少时错误信息是 FileNotFoundError,不是 “pandoc not found”。
立即学习“前端免费学习笔记(深入)”;
- 用
shutil.which("pandoc")先检查是否存在,不存在就明确报错:"pandoc not found. Install it from https://pandoc.org/installing.html" - 输入 HTML 路径用
pathlib.Path处理,传给subprocess.run()时拆成list:例如["pandoc", str(html_path), "-o", str(docx_path), "--standalone", "--variable", "mainfont=SimSun"] - 务必捕获
subprocess.CalledProcessError:pandoc解析失败时返回非 0 状态码,但不会抛异常,除非你加check=True - 别把 HTML 内容通过 stdin 传给
pandoc,除非你手动处理编码(pandoc默认按 UTF-8 读,但 Windows 控制台可能用 GBK)
为什么不用浏览器自动化(Puppeteer / Selenium)导出 Word
有人试过用 Puppeteer 打开 HTML,再调用 document.execCommand("saveAs") —— 这条命令早已被 Chrome 废弃,现在连触发都不行。Selenium 更没法绕过浏览器沙箱去访问本地文件系统。
- 浏览器只能另存为
.html或.pdf,没有原生导出 .docx 的 API - 强行截图+OCR+再排版?延迟高、格式全丢、表格变图片、搜索失效,属于典型高成本低收益
- 如果你的 HTML 是从富文本编辑器(如 TinyMCE、Quill)导出的,建议导出时就选“Word 兼容 HTML”模式,而不是标准 HTML,能显著提升
pandoc转换质量
真正卡住的点往往不是技术选型,而是没意识到:Word 的 .docx 本质是 ZIP 包裹的一堆 XML,而 HTML 到 XML 的映射没有唯一解。表格嵌套、CSS 优先级、自定义字体路径……这些细节在转换链路里每一环都可能塌方。动手前先用最简 HTML(一个 <h1></h1> 加一段 <p></p>)跑通 pandoc,比堆一堆 Python 封装有用得多。











