从 30 行代码到一个双击就能跑的工具:网页转 Markdown 这件事我做完了
- 2026-09-26 06:10:08

墨池有雨
读完需要
10
分钟
速读 4 分钟
从 30 行代码到一个双击就能跑的工具:网页转 Markdown 这件事我做完了
01缘起
最近在知乎发现了一篇@edmond大佬的有关于自制力的好文,但是涉及很多图片和数学公式,加上文章较长,一下子没法很快看完,于是乎我便从老办法着手,用 SingleFile 浏览器插件将其保存到了本地。

但是我又想在文章中写写画画。HTML 格式保存确实最大程度保留了原网页的格式排版,但是编辑是一个很大的问题,也不便于我喂给 AI。
于是我便找到了我之前写的 html 转 md 的工具(文章是这个 →我把保存的网页变成了可编辑的文档,这个方法太好用了!),遇到了一些使用的问题。加上我习惯把文章导入飞书,在里边写写画画再制作 Anki 卡片,于是乎,便修复了一些 Bug,增加对知乎、数学公式和图片的兼容性,并增加了转换 Word 的功能。
最后做出来的东西,长这样:
图 2:那篇知乎长文导出的 Word 首页
标题居中、字号分级、正文首行缩进两个汉字——这些是导出时按中文文档的习惯调的,不是 Word 默认的样子。
02遇到的坑
本部分为具体解决问题过程,想要直接获取开箱即用的工具可以直接划到最后一部分获取。
坑 1:知乎的图,为什么转出来是坏的
我一开始以为是网络问题。后来打开 HTML 源码才看明白。
知乎正文里的图片,标签长这样:
<img src="data:image/svg+xml,<svg .../>" data-original="https://pic1.zhihu.com/真图.jpg">
src 里根本不是图片,是一段明文的 SVG 占位块——就是图片加载出来之前那个灰色的小方块。真正的图地址藏在 data-original 里。
而我原来的代码是怎么判断的呢?看到 src 以 data:image/ 开头,就当成 base64 图片去解码。
问题在于,base64 解码默认是宽容模式:遇到非法字符不报错,默默丢掉,然后老老实实吐出一小段字节。于是——
•写出了一个 47 字节的 .png,没有魔数,Word 拒绝嵌入,界面上显示成一个破图标;
•更糟的是,代码在这个分支里提前 return 了,data-original 里那张真原图,被整个丢掉;
•最离谱的是,所有占位图长得一模一样,解码出来的文件名也一模一样,于是十几张不同的图互相覆盖,最后只剩一张。
整个过程不抛任何异常。日志里全是"保存成功"。这就是它最气人的地方——它不是失败了,它是骗你说成功了。
现在的做法是:
1.取图一律先走懒加载的真实地址,取不到才考虑内嵌图;
2.解码必须过三重校验——文件头魔数、体积下限、格式白名单;
3.占位图一律不落盘。
换来的结果是实实在在的:拿那篇《如何提高自制力?》的知乎长文回归,原来 26 张图,现在 28 张全部嵌入。多出来的那两张,就是之前被占位图吞掉的。
图 3:同一篇长文,图片全部正常嵌入
坑 2:公式为什么会变成一串重复的乱码
知乎的数学公式是 MathJax 渲染的。而页面上,同一份公式其实存了三份:
•渲染出来的 MathML;
•一份给屏幕阅读器用的隐藏副本;
•还有一份 LaTeX 源码,藏在 data-tex 属性里。
我原来的写法是 get_text() 一把梭——于是三份全被吸进正文,公式的位置上就出现一大串重复的、根本看不懂的文本。
现在只认 data-tex,把 LaTeX 原样写进 Markdown:
行内公式 $E = mc^2$
$$ \sum_{i=1}^{n} x_i $$
这么做的好处是不丢信息。Typora、Obsidian 都能直接渲染;导出 Word 的时候,还能把它编译成 Word 的原生公式——可以选中、可以双击再编辑的那种,不是一张图。
图 4:编译成 Word 原生公式的效果(截图自版式与公式回归样例)
坑 3:WPS 把求和号画成了积分号
这个坑有点好笑。
我在 WPS 里打开导出的 docx,发现所有的求和符号 ∑ 都被画成了积分号 ∫。
查了半天才想明白:Word 公式的底层是一套叫 OMML 的 XML。求和这种带上下限的运算符,靠一个属性告诉渲染器"我是求和,不是积分"。WPS 忽略了这个属性,一律按积分画。顺带,重音符号(比如 x̂)也直接被它丢掉。
改法很土,但管用:
•只有真正的积分 ∫ 走原本的运算符结构;
•其余的求和、求积,改成用上下标结构包住运算符本身;
•重音符号换成组合音标字符。
这件事教给我一个教训,我觉得比修 bug 本身更值钱:
XML 是对的,不代表渲染出来是对的。
后来我专门写了个小工具:Markdown → docx → PDF → 一页一张 PNG,然后肉眼一页一页看。凡是动过排版或者公式,都得先把这组图看一遍才算改完。
03那它现在到底能做什么
一句话:
HTML 进去,Markdown 和 Word 一起出来,图片全部落在你自己电脑上。
它专门伺候从浏览器里存下来的网页:公众号、知乎、掘金,以及大部分普通博客。
转换本身
•转换引擎换成了 DOM 解析,不再靠正则去猜
•正文自动识别:公众号 / 知乎 / 掘金 / 通用博客,谁的内容多认谁
•标题层级、有序无序列表、表格、引用、代码块、超链接、加粗斜体,都按原结构还原
•数学公式转成 LaTeX 源码
•自动清掉 SVG 图标、广告、"相关阅读"导航这些装饰
图片
•懒加载还原(data-original / data-actualsrc / data-src 都认)
•知乎的 720w 缩略图自动换成原图
•base64 内嵌图自动解码落盘
•用 URL 的 MD5 命名,重复图片自动去重
•下载失败自动回退成远程链接,不会让整篇文章崩掉
批量
•整个文件夹一次转完,支持递归子目录
•多线程并行
•跳过已经转过的,重复跑不浪费时间
•目录下放一个 config.yaml,常用选项就记住了
Word 导出
•标题层级、表格、代码块、图片、真正的 Word 超链接(蓝色、不带下划线)
•公式编译成 Word 原生公式
•版式:A4,左右边距 2.8cm,正文 11pt,1.3 倍行距,两端对齐,首行缩进两个汉字
•页脚居中「第 X 页 / 共 Y 页」
04怎么用
先说最省事的那条路:
1.装好 Python 和两个依赖;
2.双击 run.bat;
3.把 HTML 文件拖到 run.bat 的图标上。
结束。
图 5: run.bat的中文菜单
拍摄提示:把窗口拉宽到 800px 左右,深色终端背景,菜单文字清晰即可。
如果你想看细节,命令行是这样:
# 图形界面
python html_to_md_batch.py
# 命令行:单个文件
python html_to_md_batch.py --cli 文章.html
# 命令行:整个文件夹,递归 + 4 线程 + 同时导出 Word
python html_to_md_batch.py --cli E:/笔记/html --recursive --jobs 4 --docx
# 已经有 Markdown 了,只想导出 Word
python md2docx.py E:/笔记/html --recursive
依赖只有三个,而且除了 python-docx(导出 Word 用),其它不装也能跑。
05效果怎么样
还是那篇《如何提高自制力?》,一篇很长的知乎收藏:
•排版收紧之后,79 页变成 70 页;
•26 张图,现在 28 张全部嵌入;
•里面几个带上下限的求和公式,在 WPS 和 Word 里都显示正常。
06它做不到什么
•公式只支持常见的 LaTeX 子集。分式、上下标、根号、积分求和带上下限、希腊字母、重音都行;matrix、cases、aligned 这类多行环境会退回成纯文本,不会崩,但也不好看。
•小众网站的正文识别可能退化成"抓整个 article 或 body",能转,但导航栏和评论可能混进来。
•启动器只有 Windows 版。命令行和图形界面是跨平台的,run.bat 不是。
•正文外的图片(头像、二维码、表情包)不单独处理,跟着正文走。
07为什么坚持做成本地离线的
有人问过,为什么不用现成的在线转换服务。
三个原因:
1.我的资料不想出我的电脑。 收藏的文章里有不少是付费专栏的内容,贴到别的网站上转,心里不舒服。
2.在线服务会关。 我收藏夹里躺着一堆已经打不开的网址,不想再让工具也变成其中一个。
3.不受别人的限。 不用排队、不用登录、不用担心图片被压缩、不用看广告。
所以这个工具没有服务器、没有数据库、不调任何在线接口,也不需要装 pandoc 或者 Office。装好依赖,断网也能用。
08最后
上一篇文章里我说过一句:工具的意义,就是让重复的事情自动化,把时间留给更重要的事。
半年后我还是这句话。只是现在,这个工具终于配得上这句话了。
09获取方式
公众号后台回复 网页转换 获取源码包。
简单来说就是安装python和依赖然后双击run.bat即可


如果你也在攒一个自己的资料库,可以拿去用。有问题留言,我尽量回。
本文来自「棉花糖的神奇口袋」
作者:墨池有雨



