Convert PDF to Markdown in Python: 4 Libraries + API Compared
Published 2026-07-09
The short answer: for clean digital PDFs, pymupdf4llm gets you to Markdown in four lines of Python. For scanned pages, complex tables, or LaTeX math, local libraries plateau fast — that's where a VLM-based parsing API earns its keep. Here's working code for every option, with honest failure modes.
Option 1: pymupdf4llm (best local default)
pip install pymupdf4llm
import pymupdf4llm
md = pymupdf4llm.to_markdown("paper.pdf")
with open("paper.md", "w", encoding="utf-8") as f:
f.write(md)
Built on PyMuPDF, designed specifically for LLM ingestion: it detects headings by font size, renders tables as pipe tables, and can emit page chunks for RAG (page_chunks=True).
Where it breaks: scanned PDFs (no OCR), math (formulas come out as garbled Unicode), and merged-cell or cross-page tables.
Option 2: MarkItDown (Microsoft)
pip install markitdown
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("paper.pdf")
print(result.text_content)
Microsoft's Swiss-army converter (PDF, Office, images → Markdown). Convenient when PDFs are one of many input formats in your pipeline.
Where it breaks: its PDF path is text-extraction based — same weaknesses as above, with less layout awareness than pymupdf4llm.
Option 3: Marker (best open-source quality)
pip install marker-pdf
marker_single paper.pdf --output_dir out/
Marker runs a pipeline of ML models (layout detection, OCR via Surya, equation handling) and produces notably better structure than pure-text extractors, including decent math support.
Where it breaks: heavy dependencies and GPU appetite — practical for batch jobs on your own hardware, annoying inside a lightweight service. Tables with merged cells still fail regularly.
Option 4: pdfplumber (when you need coordinates, not Markdown)
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
for page in pdf.pages:
print(page.extract_text())
for table in page.extract_tables():
print(table)
Not a Markdown converter — a precision instrument for pulling specific tables and text regions when you know the document's geometry. Great for invoices with fixed layouts; wrong tool for general conversion.
Option 5: VLM parsing API (when quality is the requirement)
Everything above reads the PDF's text layer. A Visual Language Model reads the page image — which is why it survives scans, multi-column reading order, merged cells, and math. KolmoPDF's PDF parsing API wraps that in one call:
import requests
resp = requests.post(
"https://www.kolmopdf.com/api/pdf-to-markdown-proxy/parse",
headers={"Authorization": "Bearer sk-xxx"}, # get a key at /api-keys
files={"file": open("paper.pdf", "rb")},
)
markdown = resp.json()
Output is GitHub-Flavored Markdown with LaTeX math in $/$$ delimiters, pipe tables, and fenced code blocks. Pricing is per page (2 credits/page) with free signup credits — try it in the browser first with the PDF to Markdown converter.
Head-to-head: what actually fails where
| Input | pymupdf4llm | MarkItDown | Marker | VLM API |
|---|---|---|---|---|
| Clean single-column text | ✅ | ✅ | ✅ | ✅ |
| Two-column paper | ⚠️ order issues | ⚠️ | ✅ | ✅ |
| Tables (simple) | ✅ | ⚠️ | ✅ | ✅ |
| Tables (merged cells / cross-page) | ❌ | ❌ | ⚠️ | ✅ |
| LaTeX math | ❌ | ❌ | ⚠️ | ✅ |
| Scanned PDF | ❌ | ❌ | ✅ (slow) | ✅ |
| Runs fully offline | ✅ | ✅ | ✅ | ❌ |
Recommendation by use case
- RAG over clean digital PDFs:
pymupdf4llm, no contest — free, fast, local. - Mixed-format ingestion (Office + PDF + images): MarkItDown for uniformity.
- Batch conversion on your own GPU: Marker.
- Papers, textbooks, scans, anything with math or serious tables: VLM API. The cost of bad parsing shows up later as bad retrieval — if the documents matter, parse them properly once.
A common production pattern: route by document type. Text-layer extraction for born-digital simple PDFs; VLM parsing for scans and technical documents. The four-line check: if pymupdf4llm's output looks scrambled, escalate that file to the API.
FAQ
What's the fastest way to convert PDF to Markdown in Python?
pymupdf4llm.to_markdown("file.pdf") — one line after install. Speed isn't the bottleneck; quality on hard documents is.
How do I convert a scanned PDF to Markdown in Python? Local: Marker (bundles OCR). Hosted: a VLM API that treats every page as an image, so scans need no special handling.
Why does my extracted Markdown have formulas like "x2+y2=r2"?
The PDF text layer stores rendered glyphs, not LaTeX source. Only vision-based parsing can reconstruct $x^2 + y^2 = r^2$.
Which output is best for LLM / RAG pipelines? Markdown with real heading hierarchy — headings become chunk boundaries. That's the argument for parsers that get structure right, whichever one you pick.