PDF to Clean Text or Markdown: 3 Free Commands I Tested (and Where Each Breaks)

PDF to Clean Text or Markdown: 3 Free Commands I Tested (and Where Each Breaks)

Full disclosure: I make PDF Insight, a web app that does PDF → text/summary. This post is mostly about the free command-line options, because for a lot of jobs they’re all you need. I’ll say where each one breaks, including mine. The short version: Plain text, fast: pdftotext -layout file.pdf out.txt (Poppler). Keep -layout on or table rows fall apart. Markdown with headings, in Python: pymupdf4llm.to_markdown("file.pdf"). Good headings, but check your tables. Scanned PDFs (images, no text layer): none of the above work. You need OCR first (ocrmypdf in.pdf out.pdf, then extract). Don’t want to script it / need a summary: a hosted tool (mine is linked at the end, there are others).

免责声明:我开发了 PDF Insight,这是一个执行 PDF 转文本/摘要的 Web 应用。本文主要介绍免费的命令行选项,因为对于许多工作来说,它们已经足够了。我会指出每种工具的缺陷,包括我自己的工具。简而言之:纯文本,快速转换:pdftotext -layout file.pdf out.txt (Poppler)。请务必保留 -layout 参数,否则表格行会错乱。带标题的 Markdown,使用 Python:pymupdf4llm.to_markdown("file.pdf")。标题效果不错,但请检查表格。扫描版 PDF(图像,无文本层):上述工具均无效。你需要先进行 OCR(使用 ocrmypdf in.pdf out.pdf,然后再提取)。如果你不想编写脚本或需要摘要:可以使用托管工具(文末有我的工具链接,也有其他选择)。

The test file: I didn’t want to hand-wave, so I made a tiny PDF with a heading, a paragraph, a 3-row table and a second heading, and ran each tool on it. You can rebuild the same file:

# pip install pymupdf
import pymupdf
html = """<h1>Quarterly Report</h1> <p>Revenue grew in the second quarter while costs stayed flat. The table below lists results by region.</p> <table border="1"><tr><th>Region</th><th>Q1</th><th>Q2</th></tr> <tr><td>North</td><td>120</td><td>140</td></tr> <tr><td>South</td><td>90</td><td>95</td></tr> <tr><td>West</td><td>60</td><td>81</td></tr></table> <h2>Notes</h2><p>West grew fastest because of a new partner. South was flat.</p>"""
story = pymupdf.Story(html=html)
w = pymupdf.DocumentWriter("sample.pdf")
page = pymupdf.paper_rect("a4")
more = 1
while more:
    dev = w.begin_page(page)
    more, _ = story.place(page + (36, 36, -36, -36))
    story.draw(dev)
    w.end_page()
w.close()

Versions used: Poppler pdftotext 25.03.0, PyMuPDF / pymupdf4llm 1.28.2, Linux, October 2026.

测试文件:我不想纸上谈兵,所以我制作了一个微型 PDF,包含一个标题、一个段落、一个 3 行表格和第二个标题,并用每个工具对其进行了测试。你可以重建同一个文件:

# pip install pymupdf
import pymupdf
html = """<h1>Quarterly Report</h1> <p>Revenue grew in the second quarter while costs stayed flat. The table below lists results by region.</p> <table border="1"><tr><th>Region</th><th>Q1</th><th>Q2</th></tr> <tr><td>North</td><td>120</td><td>140</td></tr> <tr><td>South</td><td>90</td><td>95</td></tr> <tr><td>West</td><td>60</td><td>81</td></tr></table> <h2>Notes</h2><p>West grew fastest because of a new partner. South was flat.</p>"""
story = pymupdf.Story(html=html)
w = pymupdf.DocumentWriter("sample.pdf")
page = pymupdf.paper_rect("a4")
more = 1
while more:
    dev = w.begin_page(page)
    more, _ = story.place(page + (36, 36, -36, -36))
    story.draw(dev)
    w.end_page()
w.close()

使用的版本:Poppler pdftotext 25.03.0,PyMuPDF / pymupdf4llm 1.28.2,Linux,2026 年 10 月。

  1. pdftotext (Poppler): the default you probably already have. pdftotext sample.pdf - (print to stdout) or pdftotext -layout sample.pdf - (keep the visual layout). Without -layout, the table came out like this — every cell on its own line, so you can’t tell which number belongs to which region: Region Q1 Q2 North 120 140 South … With -layout the rows stay together: Region Q1 Q2 North 120 140 South 90 95 West 60 81. Watch out for: ligatures. “flat” came out as “flat” (one fl character), which breaks grep flat. Normalise it: import unicodedata; text = unicodedata.normalize("NFKC", text) # 'fl' -> 'fl'. Best for: grepping, quick copy-paste, shell pipelines. What it won’t do: headings or Markdown structure.

  2. pdftotext (Poppler):你可能已经安装的默认工具。pdftotext sample.pdf -(打印到标准输出)或 pdftotext -layout sample.pdf -(保持视觉布局)。如果没有 -layout,表格会变成这样——每个单元格单独占一行,因此你无法分辨哪个数字属于哪个区域:Region Q1 Q2 North 120 140 South … 使用 -layout 后,行保持在一起:Region Q1 Q2 North 120 140 South 90 95 West 60 81。注意:连字问题。“flat”可能会变成“flat”(一个 fl 字符),这会导致 grep flat 失效。请进行规范化处理:import unicodedata; text = unicodedata.normalize("NFKC", text) # 'fl' -> 'fl'。最适合:grep 搜索、快速复制粘贴、Shell 管道操作。它无法实现:标题或 Markdown 结构。

  3. pymupdf4llm: Markdown with real headings. pip install pymupdf4llm. import pymupdf4llm; md = pymupdf4llm.to_markdown("sample.pdf"); print(md). Output on the test file: # **Quarterly Report** ... ## **Notes**. Headings became # / ## and the ligature was already fixed. But on this file the table was flattened into one line. Results vary by how the table was drawn in the PDF, so check tables by eye before you feed the output to an LLM or a search index. Best for: chunking documents for RAG / LLM prompts, where headings matter. What it won’t do: guarantee table structure.

  4. pymupdf4llm:带有真实标题的 Markdown。pip install pymupdf4llm。import pymupdf4llm; md = pymupdf4llm.to_markdown("sample.pdf"); print(md)。测试文件的输出:# **Quarterly Report** ... ## **Notes**。标题变成了 # / ##,连字问题也已修复。但在该文件中,表格被展平为一行。结果取决于 PDF 中表格的绘制方式,因此在将输出提供给 LLM 或搜索索引之前,请务必人工检查表格。最适合:为 RAG / LLM 提示词进行文档分块,其中标题非常重要。它无法实现:保证表格结构。

  5. Scanned PDFs: OCR first. If pdftotext prints nothing (or garbage), the PDF is probably images. Add a text layer, then extract: # apt install ocrmypdf (or brew install ocrmypdf); ocrmypdf scanned.pdf searchable.pdf; pdftotext -layout searchable.pdf out.txt. OCR quality depends on the scan; tables from scans are the hardest case for every tool.

  6. 扫描版 PDF:先进行 OCR。如果 pdftotext 没有输出(或输出乱码),该 PDF 很可能是图像。添加文本层,然后提取:# apt install ocrmypdf (或 brew install ocrmypdf); ocrmypdf scanned.pdf searchable.pdf; pdftotext -layout searchable.pdf out.txt。OCR 质量取决于扫描效果;对于所有工具而言,扫描件中的表格都是最难处理的情况。

  7. Hosted tools. If you don’t want to script it, or you want a summary rather than raw text, a hosted tool saves time. Options include ChatPDF (chat-first), NotebookLM (free, good across several sources at once) and PDF Insight (mine). What PDF Insight does: upload a PDF, get clean Markdown text you can copy or download, plus a short, medium or long AI summary with key points; on Pro you can ask questions and get answers cited from the document. The site says its parser is built for complex layouts, tables and multi-column pages, but I didn’t include it in the test above, so try it on your own file. Free is 1 PDF; Pro is $15/mo billed yearly. Link: PDF Insight.

  8. 托管工具。如果你不想编写脚本,或者想要摘要而不是原始文本,托管工具可以节省时间。选项包括 ChatPDF(以聊天为中心)、NotebookLM(免费,同时处理多个来源效果很好)和 PDF Insight(我的工具)。PDF Insight 的功能:上传 PDF,获取可复制或下载的干净 Markdown 文本,以及包含关键点的短、中、长 AI 摘要;在 Pro 版本中,你可以提问并获得引用文档内容的答案。网站称其解析器专为复杂布局、表格和多栏页面构建,但我没有将其包含在上述测试中,所以请在你的文件上尝试一下。免费版限 1 个 PDF;Pro 版每月 15 美元,按年计费。链接:PDF Insight。

What I’d do today: Run pdftotext -layout first. If the output looks right, stop there. If you need headings (for chunking/RAG), try pymupdf4llm and eyeball every table. If you get nothing back, OCR with ocrmypdf and extract again. If you need a summary or Q&A rather than raw text, use a hosted tool and spot-check its answers against the page.

我今天的做法:首先运行 pdftotext -layout。如果输出看起来没问题,就到此为止。如果你需要标题(用于分块/RAG),请尝试 pymupdf4llm 并人工检查每个表格。如果没有返回任何内容,请使用 ocrmypdf 进行 OCR 并再次提取。如果你需要摘要或问答而不是原始文本,请使用托管工具,并对照页面检查其答案。

FAQ: Why does my extracted table have one cell per line? You ran pdftotext without -layout. Add it. Why can’t I grep a word I can see in the PDF? Often a ligature (fi, fl) or a hyphenated line break. NFKC-normalise and join hyphenated lines. Which is best for feeding an LLM? Markdown with headings (e.g. pymupdf4llm), checked for tables. Headings make chunking much better. Does any of this work on scanned PDFs? Not without OCR. Run ocrmypdf first. Is it safe to upload confidential PDFs to a hosted tool? Read the tool’s privacy policy first; for sensitive files the local commands above keep everything on your machine. Disclosure: I’m the developer of PDF Insight. This post was drafted with an AI assistant; the commands and outputs above were run on a real file.

常见问题解答:为什么我提取的表格每个单元格占一行?你运行 pdftotext 时没有加 -layout。加上它。为什么我无法 grep 到在 PDF 中能看到的单词?通常是连字(fi, fl)或连字符换行。请进行 NFKC 规范化并合并连字符换行。哪种格式最适合提供给 LLM?带有标题的 Markdown(例如 pymupdf4llm),并检查过表格。标题能让分块效果更好。这些方法对扫描版 PDF 有效吗?没有 OCR 则无效。先运行 ocrmypdf。将机密 PDF 上传到托管工具安全吗?请先阅读工具的隐私政策;对于敏感文件,上述本地命令可以将所有内容保留在你的机器上。披露:我是 PDF Insight 的开发者。本文由 AI 助手起草;上述命令和输出是在真实文件上运行的。