Parsing PDFs and messy documents
Retrieval can only find what parsing got right. A PDF stores where to draw letters, not paragraphs, so structure has to be recovered on purpose.
Words on this page (5)
- retrieval
- : Finding the most relevant pieces of text for a query.
- tool
- : A function the model can ask your program to run, described by a name, description and argument schema.
- OCR
- : Optical character recognition: turning an image of text into real text.
- chunk
- : A small piece of a document, sized for indexing and retrieval.
- embedding
- : A list of numbers that represents the meaning of a piece of text or an image, so similar things sit close together.
What it is
A PDF file says "draw this character at this spot". It does not say "this is a paragraph" or "this is a table". Plain text extraction often gives broken lines, repeated page headers, tables flattened into one long row and two-column pages read straight across. A scanned PDF is only a picture, so a normal parser returns nothing.
A parser tries to recover the structure: headings, paragraphs, tables and the reading order. Simple libraries such as PyMuPDF and pdfplumber work on PDFs that contain real text. such as Docling and Unstructured also detect the layout. (optical character recognition) reads text out of scanned images, and some vision models can read a page image directly.
A worked example
A report page has two columns and a small table. Plain extraction reads across the page, so the first column's sentence "Net revenue rose 4 percent" is interleaved with the second column's text about shipping. The makes no sense, and its is a blur of both topics. A layout-aware parser returns column one in full, then column two, and turns the table into rows such as "| Year | Revenue |". Now a question about revenue finds the table row.
How to check it
Before you index thousands of pages, parse ten and put them beside the originals. Look for tables that fell apart, text in the wrong order, footers repeated on every page and pages that came back empty. Strip repeated headers and footers. Keep the page number and the section title with each chunk, so answers can cite where they came from.
How a parser rebuilds structure
A PDF with a text layer stores each character with an x and y position on the page. A parser works in steps:
- Group characters into words and lines by their positions.
- Group lines into blocks, using the gaps between them.
- Decide the reading order, for example all of column one before column two.
- Detect tables from aligned columns or ruled lines, and write them out as rows.
- Drop or tag repeated headers and footers.
Simple libraries do the first steps. Layout-aware tools add a model that looks at the page shape and labels each region as heading, paragraph, table or figure.
A second example: a scanned page
A scanned contract has no characters at all, only pixels. OCR finds regions that look like text, then guesses each character. It makes typical mistakes: a zero read as the letter O, or "rn" read as "m". A clause number or an amount can change without any warning. Some vision models read the page image directly, but they can also misread digits or tidy up wording, so check amounts against the original.
Trade-offs
Simple libraries are fast and free but ignore layout. Layout-aware tools are slower and need more computing power. Vision models handle messy pages best and cost the most per page. Choose by document type: clean exported PDFs rarely need more than a simple library, while scans and multi-column reports do.
What goes wrong
The failures are quiet. A table becomes one long line, so no chunk holds a clean row. Page numbers appear in the middle of sentences. A page returns almost nothing because it was an image.
To confirm, count characters per page. Any page with fewer than about 20 characters deserves a look. Then pick one known phrase from the original and search the parsed text for it. If you cannot find it, the parser lost it.
Common mistake
Treating "I extracted the text" as the end of ingestion. A scanned file that quietly returns an empty string will never be retrieved, and nobody notices until a user asks about it.
A team indexes their company handbook and the bot cannot answer a question about holiday pay. The answer is in a table on page 14. The parser had flattened the table into one run-on line, so no chunk ever contained a clean "holiday pay" row. Fixing the parser fixed the bot, and the model never changed.
Check yourself
Why can plain text extraction from a two-column PDF hurt retrieval?
Not quite. Reading straight across the page interleaves the columns, so each chunk mixes unrelated sentences and its embedding becomes a blur.
A scanned PDF returns empty text from your parser. What is the most likely cause?
Not quite. A scan has no text layer. OCR or a vision model has to read the page image.
You will index 5,000 pages. What is the most useful quick check first?
Not quite. Looking at real parsed pages catches broken tables, wrong order and empty pages while they are cheap to fix.
You got 0 of 3 right.
Go deeper
- RepoDoclingRepo
IBM Research · Converts PDFs and Office files into clean structured text and tables.
- RepoUnstructuredRepo
Unstructured · Parses many document types into labelled elements ready for chunking.
- RepoPyMuPDFRepo
Artifex · Fast text and image extraction for PDFs that contain real text.
- DocsPDF supportDocs
Anthropic · Sending a PDF straight to a model that reads both the text and the page images.
Spotted a mistake or something unclear? Report it on GitHub.