MarkItDown 评测:这款文件转 Markdown 工具,并不是爬虫

最后更新于 August 12, 2026
MarkItDown 评测:这款文件转 Markdown 工具,并不是爬虫
AI 摘要
这篇 MarkItDown 评测明确指出,Microsoft 的工具是文件转 Markdown 转换器,而不是爬虫或浏览器自动化系统。文章测试了现有的 PDF、DOCX、XLSX 和 PPTX 输入,并衡量了安装包体积、导入时间、表格保真度、不同文档规模下的运行时间以及电子表格的内存增长。结论是:MarkItDown 在干净输入下速度快、很实用,但它带来的机器学习运行时依赖体积出人意料,而且能保住表格文字却可能静默丢失列结构。对于需要把文档转换成 Markdown,用于搜索、RAG 或内部知识工作流的团队来说,这是一份很有参考价值的指南。

MarkItDown 经常被归到网页爬虫一类,但这种归类其实不对。它没有爬虫、没有 JavaScript 引擎,也不能抓取 URL 后再把页面里的模板内容清理掉。它真正做的事,是把你手头已经有的字节内容——PDF、Word 文档、表格、演示文稿——转换成适合语言模型读取的 Markdown。

我用一台 Mac 花了几周时间,把 Microsoft 的 MarkItDown 放进一组真实文档里反复测试:每个表格都和我在测试前写好的清单逐项比对,还记录了每次转换耗时。结论先说:在干净输入下,它又快又准;但它的安装包里藏着一个你未必需要的 73 MB 机器学习运行时;而表格转换也会出现一些“文本还在,但列已经错位”的问题,能通过“文字有没有丢”检查,却过不了“数据是否还在正确列里”这一关。下面是完整结果和数据。

MarkItDown 到底是什么

MarkItDown 是 Microsoft 推出的一款 Python 工具,用来把文件和 Office 文档转换成适合 LLM 的 Markdown。你可以把 PDF、.docx.xlsx.pptx、图片、HTML 文件,或其他几种格式交给它,它会返回 Markdown。它提供三种调用方式:命令行(markitdown file.pdf -o out.md,或者从 stdin 管道输入)、Python API(MarkItDown().convert(...)),以及面向 agent 工作流的可选 MCP server。

MarkItDown converts existing files to Markdown and is not a crawler

最关键的一点,是它不做什么。README 里没这么宣称,我在测试里也确认了:它不抓取网页、不渲染 JS、不跟随链接、不翻页,也不会像 readability 那样抽取正文。它是一个整篇文档转换器。你提供字节内容,它负责标准化输出。正是这一区别,决定了它是否适合放进你的技术栈,所以我后面会反复提到这一点。

从 GitHub 的“面子数据”来看,这个仓库算得上重量级——截至 2026 年 7 月中旬,它有 165,282 个 star 和 11,790 个 fork,采用 MIT 许可证,最新版本(v0.1.6)发布于 2026-05-26。不过,这个 star 数更多反映的是 Microsoft 旗下仓库搭上了 LLM 工具热潮,而不是它转换内核已经非常成熟。仓库里还有 833 个开放 issue,其中有几条在你安装之前就值得先看一眼(后面会说)。

HTML 转 Markdown:速度快、内容全,但模板内容也会一起带上

因为我这套网页爬取评测系列本来就使用相同的四个网页样本,所以我把相同的本地 HTML 文件喂给了 MarkItDown——不是为了把它当爬虫打分,而是想看看它的 HTML 转 Markdown 到底做得怎么样。对于结构清晰、标签规范的页面,它的表现确实不错。

这四个页面都能在核心安装环境下直接转换,不需要额外插件,而且正文内容的抽样检查都通过了。Wikipedia 的 “Web scraping” 条目(226 KB)转换后,标题层级基本保持原样——1 个 h1、7 个 h2、12 个 h3,与原文结构一致——并保留了 418 个链接,格式也都正确变成了 [text](url)。Scrape This Site 的 forms 页面 上那张 25×9 的冰球统计表,变成了一个干净的 27 行 GFM pipe table(表头 + 分隔行 + 26 行数据),空单元格也都保留了。速度方面也没什么压力:小型 quotes 页面中位数 48 ms,而 226 KB 的 Wikipedia 页面也只要 352 ms。

但这里有个关键问题,而且这不是 bug,而是设计选择。MarkItDown 不会剥离模板内容。它会把整个 <body> 都转换出来,所以页面外壳内容也会一并带上——而且页面越“花哨”,残留越多。

页面输出字符数标题层级 (h1/h2/h3)链接数页面模板行占比
Books to Scrape10,4781 / 0 / 0940.6% (1/159)
Quotes to Scrape2,9731 / 1 / 0551.2% (1/86)
ScrapeThisSite forms3,3851 / 0 / 0316.7% (5/75)
Wikipedia Web scraping60,1591 / 7 / 1241812.4% (42/338)

在几乎没有模板干扰的 Books 首页里,输出中只有 0.6% 的行属于模板内容。而 Wikipedia 上,这个比例是 12.4%——338 行非空内容里,有 42 行是“跳转到正文”“切换目录”“22 种语言”“检索于”“Cookie 和许可协议页脚”等杂项。Wikipedia 上那些维护提示(比如“本文需要更多引用”)甚至会被原样转成两列表格,所以在一个本来没有真实数据表的页面上,居然能多出 9 行表格内容。

这并不是 MarkItDown 做错了什么。它是整篇文档转换器,不是正文提取器:忠实的 HTML 转 Markdown,和只保留正文的可读性抽取,是两回事。Trafilatura 或 Firecrawl 这类工具的目标,是只返回正文;而 MarkItDown 返回的是整页内容。其底层实现是:_html_converter.py 先去掉 <script><style>,然后把整个 body 交给 markdownify——流程里根本没有正文识别逻辑。如果你只想要文章正文,这层工具就用错了。

它的主场:PDF、DOCX、XLSX、PPTX

文档才是 MarkItDown 真正擅长的领域。我用真实公开文件做了测试:一篇带文本层的 arXiv 论文、Bitcoin 白皮书、一份我特意渲染成无文字内容的纯扫描 PDF,以及 MarkItDown 自带测试套件中的 DOCX/XLSX/PPTX 文件(这些文件里嵌入了 UUID,用来检测是否有静默内容丢失)。

文档输入大小输出字符数检查点命中中位耗时备注
arXiv 1706.03762(带文本层的 PDF)2.2 MB40,1747/73.7 s(warm)标题、“Transformer”、“BLEU”、“References” 都在
Bitcoin 白皮书(9 页 PDF)184 KB22,4856/61.4 s“Satoshi Nakamoto”、“proof-of-work”、“Conclusion” 都在
扫描 PDF(无文本层)89 KB00/415 ms输出为空,无报错,无 OCR
DOCX(test.docx)136 KB4,65170 ms标题 + GFM 表格;嵌入 UUID 完整保留
带公式的 DOCX15 KB240101 msOffice Math 被保留为 LaTeX
XLSX(test.xlsx)12 KB80857 ms每个 sheet → ## SheetName + GFM 表格
PPTX(test.pptx)278 KB2,04752 ms幻灯片编号标记、表格、图表都转成表格

对于带文本层的 PDF,它的文本召回率非常出色——arXiv 的 “Attention Is All You Need” 论文 7 个预设检查点全部命中,Bitcoin 白皮书 6 个检查点也全部通过。而 Office 文件也没有丢失任何 UUID 哨兵,所以在维护者自己的回归样本里,没有出现静默内容丢失。还有一个不错但比较小众的亮点:DOCX 路径(通过 mammoth)能把 Office Math 方程保留成 LaTeX,也就是说,equations.docx 会被转换成真正的 $$...$$ 数学公式。如果你要把包含大量公式的 Word 文档喂给 LLM,这确实是一个很有价值、但不太常被提到的优点。

不过,这片“主场”里有两个发现最容易踩坑,值得单独说。

那个会“消失”的扫描 PDF

如果给 MarkItDown 一个只有图片、没有文本层的 PDF,它返回的就是空字符串。0 个字符,不报错,也不警告——之所以只用了大约 15 ms,是因为根本没东西可提取。MarkItDown 的 PDF 处理路径只做文本抽取(底层依赖 pdfminer 和 pdfplumber),核心安装包和任何 pip extra 里都没有 OCR。

这在批处理里非常要命。假如开发者一次性处理一个 PDF 文件夹,里面既有可选中文本层的文件,也有扫描件,那些扫描文件会悄无声息地变成空结果,而且没有任何信号提示“这个文件被跳过了”。我还直接用 pdfminer 的 extract_text 验证过这个样本不是坏文件——结果确实是 0 个字符,确认没有文本层,所以 MarkItDown 的空输出是真实行为,不是样本异常。这也复现了一个长期未解决的 OCR 回退缺口(#1268)。目前官方文档里提到的可用路径是 Azure Document Intelligence 的可选后端或插件;默认安装都不带。

PDF 输出的是平铺文本,不是结构

在这两份带文本层的 PDF 上,MarkItDown 都没有生成任何 Markdown 标题标记。PDF 本身并没有语义化标题标签,而 MarkItDown 也不会根据字体大小去推断层级,所以所有文本都落在正文级别。文本内容保住了,但结构是扁平的。

这不是我一家之言。第三方公开基准对 MarkItDown 的 PDF 标题层级打分大约是 0.0,而表格保真度约 0.27,明显低于基于 TableFormer 的 Docling 0.88(可参考 MarkItDown vs Docling vs Marker 对比READoc 基准)。我的测试结果和它们一致,这反而增强了证据力度——我的数据和外部来源是对得上的。同一批基准也显示,MarkItDown 的速度大约比 Docling 快 100 倍,这一点也和我的测试吻合:面对需要布局模型处理几分钟的文档,它只要几秒。结论很简单:MarkItDown 能给你干净、快速的 PDF 文本,但不给你 PDF 的结构。如果标题和表格必须完整保留,那你应该用 Docling 或 Marker 这类布局模型工具。

表格:内容通常能保住,但结构不一定

表格是“文字是否保住”和“数据是否还能用”开始分叉的地方。所以我做了一个 13 种场景的矩阵——每个案例一个 <table>,并在运行前按清单逐项评分——专门看哪些结构能稳住,哪些会坏掉。

MarkItDown table fidelity: tokens survive but rowspan can silently shift columns

先说结论:MarkItDown 从来没有丢过表格内容。13 个案例里,预先设定的 token 保留率都是 100%。但结构保真度就分成了三类。13 个里有 7 个输出了完整可用的 GFM 网格(包括普通表格、表头跨列、24 列宽表格、无表头、空单元格、单元格内嵌块元素,以及从右到左的阿拉伯语表格)。有 4 个变得很凌乱,因为 Markdown 本身并不支持跨行/跨列单元格,所以 rowspan、colspan 和格式不规范的源表会产生短行。还有 2 个是直接坏掉的。

这两个坏掉的情况很值得点名。一个嵌套表格(即 <td> 里再套一个 <table>)会被直接扁平化,内部自己的竖线和分隔行会一起灌进父单元格,最后变成一行 14“列”的垃圾数据。另一个问题是:单元格里的字面量 | 不会被转义——比如 a | b 会被拆成两列,x || y 甚至会变成三列——于是一个两列表格会输出成两列、三列、四列混杂的行,下游任何 Markdown 解析器都会读错边界。有意思的是,单元格里的星号和反引号是会被转义的,只有竖线不会。根因在于:MarkItDown 的 HTML 路径使用的是 markdownify 的默认表格处理方式,而它自定义的子类只重写了链接、图片和标题,没有重写单元格。类似的竖线转义问题,在 CSV 转换器里也有一个 公开 issue(#2019),不过那个修复并不会影响我这里测试的 HTML 路径。

其中最隐蔽、也是我最想让数据工程师看到的,是 rowspan。t03 这个案例不只是输出凌乱,而是会静默错位。一个 rowspan=2 的标签(“Fruit”)只会输出一次,而它下面那一行会变成一个短短的两列表格(| Banana | 8 |),于是 “Banana” 会被放到 Group 列,而不是 Item 列。所有 token 都还在,但如果有人天真地“读取第二列”,拿到的值就是错的。这类 bug 能通过“文本没丢”检查,却会悄悄污染数据集。

跨行/跨列的限制本身就是一个已知且被跟踪的设计约束(#1211#1248)——因为平面的 GFM pipe 网格确实无法表达跨列/跨行或嵌套结构,所以转换器只能在结构和内容完整度之间做取舍。不过也有一些表现不错的地方:无表头表格会被补出一个空表头行(这样就不会把数据悄悄提升成表头),空单元格会被保留,而且 <caption> 会作为表格上方的一行文本保留下来。

安装和启动:所谓“轻量工具”没告诉你的代价

这里最让我意外,也正是“轻量级 Python 工具”这个说法悄悄夸大了的地方。

MarkItDown dependency footprint: 161 MB total, onnxruntime 73 MB and numpy 34 MB

第一,别去跑 pip install 'markitdown[all]'。在 Python 3.14 上,它会悄悄回退安装到 markitdown 0.0.2——一个两年前的版本——我在干净虚拟环境里现场复现过。为什么会这样?把版本钉死后就很清楚:pip install 'markitdown[all]==0.1.6' 会报错,因为 [all] 这个 extra 锁定了 youtube-transcript-api~=1.0.0,而当前 PyPI 上这个版本范围里的所有构建都要求 Python <3.14,只有兼容 3.14 的构建又不符合这个版本钉子。所以解析器只能一路回退到最后一个能满足依赖的旧版本。这也对应了一个 上游开放 issue(#2179)。解决办法很直接:先固定主版本,再分别安装 extras——pip install 'markitdown==0.1.6',然后再执行 pip install 'markitdown[pdf,docx,pptx,xlsx,xls]==0.1.6'。这些单独安装都能正常解析;只有打包在一起的 [all] 这个 bundle 带了“有毒”的版本约束。(这个坑和 Python 版本有关——在 Python 3.13 或更早版本上,限制未必会触发,所以 [all] 的解析结果可能不同。)

第二,说说体积。核心安装就已经有 161 MB(13 MB 的空虚拟环境 + 148 MB 的包内容)。其中 onnxruntime(73 MB)和 numpy(34 MB)加起来就有 107 MB,占整个核心体积的 66%,而它们都是被一个硬依赖拉进来的:magika,也就是 Google 的机器学习文件类型检测器。也就是说,这个文本转换器在默认安装里就带着一个 73 MB 的 ONNX 推理运行时,哪怕你还没装任何文档扩展包。把文档扩展都加上后,虚拟环境会涨到 310 MB。它当然比无头浏览器栈轻得多,但如果你以为它是那种 pip install 完就能直接用的微型工具,就要知道它其实还带着一个 ONNX runtime。

第三——也是我这次测试里唯一一个通过所有“新鲜感”检查的发现——即使是干净安装,import markitdown 在这台机器上也要大约 3.35 秒。成本几乎全都花在导入阶段:markitdown._markitdown 会急切导入整套转换器注册表(累计 2.56 秒,占总耗时的 76%),进而拉入 pandas(1.21 秒,通过 XLSX 转换器)、python-pptx(427 ms)、magika(354 ms)和 requests(270 ms)——不管你到底会不会转换这些格式。对于长期运行的服务来说,这个导入开销会被摊薄,几乎可以忽略;但对于 CLI 调用或无服务器冷启动来说,这就是实打实的每进程成本,而“轻量工具”这个标签并不会让你预料到这一点。(公平说明:这只是一次剖析运行,作为单次观察,而不是多次运行后的分布。)

MarkItDown cold start import tax: 3.35 seconds, registry 2.56 seconds

扩展到大规模:不会崩,但 PDF 要预算 CPU,表格要预算内存

我把四个大样本分别放进独立进程里跑,避免前一次运行污染峰值内存。没有崩溃,但资源曲线明显不均衡。

MarkItDown timing scale: arXiv 3.7 seconds, NIST 192.5 seconds, 50K XLSX plus 374 MB

样本输入大小输出字符数中位耗时峰值 RSS 增量
NIST SP 800-53r5(492 页 PDF)6.07 MB1,625,365192.5 s+40 MB
XLSX 50,000 行 × 8 列2.1 MB3,722,95562.1 s+374 MB
arXiv 1706.03762(约 15 页 PDF)2.2 MB40,17412.6 s+25 MB
XLSX 200 行 × 64 列46 KB120,1292.9 s+22 MB

NIST 的 492 页 PDF 中位耗时 192.5 秒——大约 3.2 分钟,也就是 0.39 秒/页——原因是 pdfplumber 会对每一页执行单词位置级的表单检测。峰值 RSS 只增加了 40 MB,所以它是 CPU 密集型,不是内存密集型。就连那篇 15 页的 arXiv PDF,在独立进程里也要 12.6 秒,大约是我文档套件里 warm 状态下同一文件 3.7 秒的 3.4 倍。这个差值就是冷进程成本,也说明真正决定时间的是按页处理,而不是原始字节大小。如果你想给这份 PDF 取一个最具可迁移性的数字,就用独立进程里的 12.6 秒。

电子表格路径则正好相反,瓶颈变成了内存。一个 2.1 MB、5 万行的 XLSX 会涨到 +374 MB 峰值 RSS(输出字符数也达到 370 万),因为转换器会把整张表加载进内存,再拼成一大段 Markdown 字符串。所以实用建议很直接:大 PDF 要预留几分钟 CPU;大电子表格要预留几百 MB 内存。这些数据是在 macOS arm64 和 Python 3.14 上单机测出的,按页和按行的具体常数会受平台影响——但“PDF 慢且吃 CPU,XLSX 吃内存,但都不会崩”的趋势是可迁移的。

Thunderbit 适合放在哪里——又不适合在哪里

试试 Thunderbit 进行网页数据提取

这是最容易被夸大的对比,所以我把边界画清楚:MarkItDown 和 Thunderbit 解决的是相邻问题,不是同一个问题。

MarkItDown 转换的是你已经拿到的文件;Thunderbit 则先抓取网页。Thunderbit 的 /distill 接口 会把一个实时网页转换成干净、适合 LLM 读取的 Markdown——它负责 JS 渲染、反爬处理和动态内容,而这些 MarkItDown 都没有能力处理;它的 /extract 接口返回的是和 schema 匹配的结构化 JSON,而不只是原始 Markdown。对开发者来说,这些能力可以通过同一个 AI 引擎以 API(POST /distill / POST /extract)、MCP server 和 CLI(npx @thunderbit/thunderbit-cli)的形式使用,也就是 10 万+ 用户扩展 背后的同一套引擎。

所以它们只有一项能力重叠——都能输出“适合 LLM 的 Markdown”——但输入域完全不同:Thunderbit 的 distill 输入是开放互联网上的 URL,MarkItDown 输入是本地文件。它们不是可直接互换的替代品,这一点我不会混淆。更现实的方案,是两者一起用:先用 Thunderbit(或类似 Firecrawl 的服务)抓取网页,然后再用 MarkItDown 统一处理本地已有的文档——PDF、演示文稿、表格。一个负责网络,一个负责文件柜。

优缺点总结

优点

  • 对干净 HTML 的正文内容召回完整(4/4 页面),标题层级和链接保留准确
  • PDF/DOCX 文本召回率高(arXiv 7/7,Bitcoin 6/6),且在维护者自带 Office 样本上没有静默丢内容
  • Office Math 公式能保留为 LaTeX——非常实用的小众优势
  • 在各类大样本上都没有崩溃,最高到 492 页 PDF 和 5 万行 XLSX 也能跑完
  • 调用简单:CLI、convert()、stdin 管道输入,以及可选 MCP server
  • MIT 许可,由 Microsoft 维护,issue 响应也比较积极

缺点

  • 会保留模板内容——Wikipedia 上模板行占比最高可达 12.4%;它不是正文提取器
  • 表格在跨行、跨列和单元格内竖线场景会出问题(13 个里 2 个直接坏,4 个结构凌乱),而且 rowspan 会静默错位
  • 扫描件 / 纯图片 PDF 输出为空,没有 OCR,也不会报错
  • PDF 输出没有标题结构(与公开基准一致)
  • 核心安装体积 161 MB,还带着 73 MB 的 ONNX runtime;冷启动导入约 3.35 秒
  • [all] extra 在 Python 3.14 上会悄悄回退到两年前的 0.0.2 版本

谁适合用,谁不适合用

如果你的任务是把一堆本地混合文档——Word、Excel、PowerPoint、带文本层的 PDF——统一标准化成 Markdown,供 LLM 流水线使用,而且你更在意文本完整而不是原结构是否保留,那么 MarkItDown 很合适。作为批处理里的最后一公里转换器,用来给模型喂干净文本,它又快、又稳、还免费。

如果你的工作属于下面这些情况,就别单独用它,或者要配合别的工具一起用:你只需要网页里的正文(那就用 readability 或 Firecrawl 风格工具);你需要 PDF 的标题和表格完整保留下来(那更适合 Docling 或 Marker);你的输入里有需要 OCR 的扫描文档(你得用 Azure 后端,或者换别的工具)。如果你本来以为自己在买“爬虫”——那种负责抓取和爬行网页的工具——那它根本不是那回事。

我按照“爬虫”式评分标准给它做的临时打分是 60/100,而这个分数偏低,本质上是因为拿一个转换器去参加爬虫的考试。回到它自己的主场,它的文本保真度很高;短板主要在结构(表格、PDF 标题)和打包方式(体积、导入时间、[all] 陷阱),不是文本质量。把它当成真正的文件转 Markdown 工具来看,它是一款扎实、维护良好、但有几个锋利边角值得提前知道的工具。

常见问题

MarkItDown 是网页爬虫吗?

不是。它没有爬虫、没有 JavaScript 渲染、不会跟随链接,也不会翻页。它只负责把你已经拥有的文件和文档——PDF、DOCX、XLSX、PPTX、图片、HTML——转换成 Markdown。如果你要抓取并爬行实时网页,你需要的是 Thunderbit 或 Firecrawl 这类抓取工具;MarkItDown 更像是后面的那一步,把抓到的网页或本地文件转成干净的 Markdown。

为什么 pip install markitdown[all] 会装到旧版本?

在 Python 3.14 上,[all] 这个 extra 会锁定 youtube-transcript-api~=1.0.0,而这个范围里的所有构建都要求 Python 版本低于 3.14。解析器无法满足这个约束,就会悄悄回退到 markitdown 0.0.2,一个两年前的版本。解决办法是固定版本后再分别安装 extras:pip install 'markitdown==0.1.6',然后再加上 'markitdown[pdf,docx,pptx,xlsx,xls]==0.1.6'。这个问题已记录在 issue #2179

MarkItDown 会对扫描 PDF 做 OCR 吗?

默认安装不会。它的 PDF 路径只做文本抽取,所以只有图片、没有文本层的 PDF 会返回空字符串——不会报错,也不会警告。要做 OCR,必须使用可选的 Azure Document Intelligence 后端或插件,而这些默认都不带。这是一个长期存在的缺口(issue #1268)。

MarkItDown 处理表格的效果怎么样?

从内容角度看,表现很好——在我 13 种场景的测试里,它保住了 100% 的表格内容。但结构表现取决于表格形状:简单表格、宽表格、无表头表格和空单元格表格都能输出成干净的 GFM 网格;但 rowspan 和 colspan 会变得凌乱(而且 rowspan 可能会把数据静默错位到错误列),嵌套表格会被压平并变成垃圾行,单元格里的字面量竖线也不会被转义。Markdown 这种平面表格格式,本来就无法表达跨列、跨行或嵌套。

MarkItDown 处理大文档够快吗?

它处理大文件不会崩,但资源要按类型预留。492 页 PDF 大约用了 3.2 分钟(约 0.39 秒/页),原因是它会逐页做表单检测,所以它更偏 CPU 密集型。5 万行电子表格大约一分钟内完成,但峰值内存增加了 374 MB,因为它会在内存里拼出一整段 Markdown 字符串。大 PDF 请按分钟级 CPU 来规划;大表格请按几百 MB 内存来规划。

试试 Thunderbit 进行网页数据提取 Get Started Free

Ke
Ke
Thunderbit 首席技术官 | 高级数据科学家与机器学习专家 Ke Shen 拥有近十年的机器学习和数据科学经验,毕业于哥伦比亚大学,曾任 Walmart Labs 高级数据科学家。他在 Python、R、Java 和统计学方面拥有深厚且备受同行认可的专业能力,并分享如何将复杂的 AI 算法从理论落地到生产级架构的实战经验。
目录
Thunderbit · AI 网页数据助手

1 次点击 内提取任意页面的数据

25 万+ 用户信赖
提供免费方案
从网页到表格
描述你需要的内容——Thunderbit 的 AI Agent 会帮你抓取并导出到 Excel、Google Sheets、Airtable 或 Notion。免费即可开始。
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week