* * * GUIDES * * *

Extract tables from a PDF into pandas.

UPDATED

Rule-based extractors like Camelot and Tabula need a digital PDF with clean lines. If your PDFs are scans or photos, OCR the page into markdown first, then turn each markdown table into a DataFrame. A short parser is all it takes.

01 / INSTALL AND GET A KEY

One dependency. Your first 100 pages are free, no card, at pennyocr.com/dashboard.

pip install pennyocr
export PENNYOCR_API_KEY=pk_live_...

02 / READ THE DOCUMENT

from pennyocr import PennyOCR

result = PennyOCR().ocr("report.pdf")  # markdown, tables preserved
text = result.text

03 / WHAT YOU GET BACK

Tables arrive as markdown tables between the prose. Multi-line cells are joined with <br>:

## Q3 results

| Region | Revenue | Growth |
|---|---:|---:|
| North | 1,204.50 | 12% |
| South | 980.00 | -3% |

Some prose between tables.

| SKU | Description | Qty |
|---|---|---:|
| A-100 | Bolt, M8<br>zinc | 400 |

04 / PARSE EVERY TABLE

Each table comes back as its header row and its body rows:

def markdown_tables(md: str):
    """Yield each markdown table as (header, rows)."""
    block = []
    for line in md.splitlines() + [""]:
        if line.strip().startswith("|"):
            block.append([c.strip().replace("<br>", " ")
                          for c in line.strip().strip("|").split("|")])
        elif block:
            body = [r for r in block[1:] if not set("".join(r)) <= set("-: ")]
            yield block[0], body
            block = []

tables = list(markdown_tables(text))
print(len(tables), "tables")

05 / LOAD INTO PANDAS

Cells arrive as strings, so convert the numeric columns you need:

import pandas as pd

frames = [pd.DataFrame(rows, columns=header) for header, rows in tables]
revenue = frames[0]
revenue["Revenue"] = revenue["Revenue"].str.replace(",", "").astype(float)
print(revenue)

06 / SAVE EACH TABLE AS CSV

One file per table:

for i, df in enumerate(frames, 1):
    df.to_csv(f"table_{i}.csv", index=False)
print("wrote", len(frames), "CSV files")

Cost: $0.00075 per page, tables included, versus about $15 per 1,000 pages for AWS Textract's table feature. For tables split across pages, read result.page_results and join tables with the same header.