PDF extraction is the problem that looks solved right up until you encounter a two-column research paper with footnotes, a scanned contract, or an annual report where the most important data is in a merged-cell table. In 2026, AI-based extraction has finally made these solvable problems — but picking the right tool for the right document type still requires judgment. Here's the complete picture.
What changed in 2026
- Vision-language models made scanned PDFs tractable. Render the page as an image, pass it to Claude Sonnet, GPT-4o Vision, or Gemini, and get structured markdown back. For anything that's not a clean digital PDF, this is now the default approach.
- LlamaParse (LlamaIndex's managed extraction service) matured into a production-grade option: it uses a combination of layout analysis and LLM passes to return markdown with tables, headers, and list structure preserved.
- Azure Document Intelligence v4 and AWS Textract v2 both added semantic element classification — not just text extraction, but labeling of titles, section headers, tables, figures, and key-value pairs.
- Unstructured.io v0.14+ added multimodal chunking: images and figures within PDFs are extracted and captioned alongside text.
Tool landscape
| Tool |
Best for |
Table quality |
Scanned PDFs |
Cost |
| pdfplumber |
Text PDFs, simple tables |
Good |
No |
Free |
| Camelot |
Table-heavy text PDFs |
Excellent |
No |
Free |
| PyMuPDF (fitz) |
Fast text extraction |
Mediocre |
No |
Free |
| LlamaParse |
RAG-ready markdown output |
Very good |
Yes (via vision) |
~$0.003/page |
| AWS Textract |
Enterprise, forms, KV pairs |
Excellent |
Excellent |
~$0.015/page |
| Azure Document Intelligence |
Enterprise, forms, tables |
Excellent |
Excellent |
~$0.01/page |
| GPT-4o Vision (page render) |
Complex layouts, ad hoc |
Excellent |
Excellent |
~$0.01–0.03/page |
| Unstructured.io |
Mixed document pipelines |
Good |
Good (hosted) |
Free/paid tiers |
Text PDFs (digitally created)
For PDFs where the text is digitally embedded (not scanned), pdfplumber and PyMuPDF cover most use cases:
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
for page in pdf.pages:
text = page.extract_text()
tables = page.extract_tables()
pdfplumber's extract_tables() returns nested Python lists — clean and easy to serialize to markdown or CSV. For PDFs where tables are the primary content (financial statements, data sheets), use Camelot instead:
import camelot
tables = camelot.read_pdf("report.pdf", pages="1-5", flavor="lattice")
tables[0].df # pandas DataFrame
Scanned PDFs and image-based documents
Two approaches in 2026:
1. Traditional OCR + layout. Tesseract for text, LayoutParser for document structure detection. Works offline, free, but requires pipeline assembly. AWS Textract and Azure Document Intelligence are the managed versions — higher accuracy, handles handwriting, and returns structured JSON with element types.
2. Multimodal LLM. Render each page to an image (pdf2image + poppler), then pass to a vision model with a structured extraction prompt:
import base64, anthropic
from pdf2image import convert_from_path
client = anthropic.Anthropic()
pages = convert_from_path("contract.pdf", dpi=150)
for page_img in pages:
# convert to bytes, encode base64
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
messages=[{
"role": "user",
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img_b64}},
{"type": "text", "text": "Extract all text and tables as markdown. Preserve table structure."}
]
}]
)
This approach handles any layout including rotated text, handwriting, and complex multi-column structures. Cost: ~$0.01–0.03 per page depending on model and page complexity.
Table extraction deep dive
Tables are where generic extractors fail. Strategies by table type:
| Table type |
Recommended tool |
| Lattice (visible grid lines) |
Camelot flavor="lattice", pdfplumber |
| Stream (whitespace-delimited) |
Camelot flavor="stream" |
| Scanned table (image) |
Vision LLM or AWS Textract |
| Nested/merged cells |
Vision LLM — only reliable option |
| Financial tables with footnotes |
LlamaParse or Azure Doc Intelligence |
Always validate table extraction against the source — common failures include merged cell collapse, column misalignment on multi-page tables, and footnote text merged into the last row.
How to pick
- Digital PDF, no tables? → PyMuPDF or pdfplumber. Fast, free, good enough.
- Digital PDF with tables? → Camelot for table-heavy docs, pdfplumber for mixed.
- Scanned or image-based? → AWS Textract or Azure Document Intelligence for production; vision LLM for ad hoc.
- Building a RAG pipeline? → LlamaParse — it returns chunking-ready markdown with preserved structure.
- Complex layouts, ad hoc extraction? → Vision LLM (GPT-4o, Claude Sonnet). Most flexible, highest quality, most expensive.
Common mistakes
Treating all PDFs as text PDFs. Check if the PDF has extractable text with pdfplumber.open(f).pages[0].extract_text() before assuming. If it returns None or gibberish, it's image-based.
Ignoring page order. Multi-column PDFs return text in reading order by bounding box — but extractors don't always handle this. Validate that extracted text reads coherently.
Losing table structure in RAG pipelines. If tables get flattened to unstructured text before chunking, the data is effectively lost. Always preserve table structure as markdown before chunking.
No extraction quality validation. Sample 20 pages across your corpus and manually verify extraction quality. Problems are document-class specific and won't surface in aggregate metrics.
What to skip
- PyPDF2 — unmaintained and produces worse output than PyMuPDF on every benchmark.
- Using a vision LLM for every page when 90% of your docs are clean digital PDFs — you'll pay 50× more than necessary.
- pdfminer.six as a table extractor — it's a text layer extractor, not a layout-aware tool.
FAQ
How do I handle PDFs with both text and image pages?
Detect text pages with pdfplumber (text extraction returns content), fall back to vision LLM for image pages. Hybrid pipelines handle mixed documents well.
What DPI should I use when rendering for vision models?
150 DPI is the sweet spot — readable for OCR and vision models, but 4× smaller files than 300 DPI. Go to 300 DPI only for dense small text or fine diagrams.
How do I preserve reading order in multi-column documents?
pdfplumber exposes bounding box data — sort text elements by x-position per column then by y-position. Alternatively, use LlamaParse which handles reading order explicitly.
Can I extract embedded images from PDFs?
Yes — PyMuPDF (fitz) extracts embedded images with page.get_images(). For captioning, pass to a vision model. Unstructured.io also handles figure extraction in its pipeline.
Where to go next