pdfplumber

Plumb a PDF for character-level text, tables, and layout data in Python — with built-in visual debugging tools.

Library
PyPI
v0.11.10
10,702stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
65/100Good
Development Activity48
Maintenance48
Community64
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
85/100Excellent
Architecture82
Code Quality90
Innovation78
Learning Curve90

pdfplumber gives Python developers granular access to the raw contents of a PDF: every character, line, rectangle, curve, image, and annotation is exposed as a plain dictionary with exact positioning, font, and color attributes. Built on top of pdfminer.six’s parsing engine, it adds a much friendlier object model — pdfplumber.open(path) returns a PDF with a list of Page objects, each offering .crop(), .filter(), .within_bbox(), and rich text/table extraction methods.

Its table-extraction engine, adapted from published research on PDF table detection, reconstructs tables from a page’s actual vector lines (or from the alignment of words when no lines are drawn), then lets you inspect exactly which lines and intersections it used via .to_image() and .debug_tablefinder(). This tight feedback loop — extract, visualize, adjust settings, repeat — is what distinguishes pdfplumber from libraries that only return extracted text or tables with no way to see why extraction failed. It works best on machine-generated PDFs (not scanned/OCR’d documents) and ships a pdfplumber CLI alongside the library for quick CSV/JSON/text dumps.

What You Get

  • Direct access to every PDF object (.chars, .lines, .rects, .curves, .images, .annots, .hyperlinks) as plain dicts with exact coordinates, fonts, and colors
  • A configurable table-detection engine (.find_tables(), .extract_table()) driven by graphical lines or word alignment, with dozens of tunable snap/join/intersection tolerances
  • Visual debugging via .to_image() and .debug_tablefinder(), which render the page with detected lines, intersections, and tables overlaid for immediate feedback
  • Page-level transforms — .crop(), .within_bbox(), .outside_bbox(), .filter() — that return derived pages retaining only the objects you care about
  • Text extraction with layout preservation (.extract_text(layout=True)), word-level bounding boxes (.extract_words()), and regex search over positioned text (.search())
  • A pdfplumber command-line tool that dumps a PDF’s objects to CSV, JSON, or plain text without writing any code

Common Use Cases

  • Extracting tabular data from government or corporate reports (e.g. WARN notices, background-check PDFs) into structured rows for analysis
  • Building data pipelines that pull text and figures out of machine-generated invoices, statements, or forms
  • Debugging why an automated table-extraction pass failed, by rendering the page with detected lines/cells highlighted
  • Cropping a PDF to a specific region (e.g. a form field or table) before running text or table extraction on just that area
  • Reading AcroForm field values from fillable PDF forms via pdfplumber’s pdfminer wrappers

Under The Hood

Architecture pdfplumber layers a friendly object model on top of pdfminer.six’s low-level parser. A shared Container base class (container.py) implements lazy, cached properties — PDF (pdf.py) wraps a pdfminer.pdfdocument.PDFDocument/PDFParser pair and exposes .pages as a list of Page instances (page.py, the largest and most central module), each of which interprets the page’s content stream into .chars/.lines/.rects/.curves/.images dictionaries. Derived views — CroppedPage, FilteredPage — subclass Page so that .crop()/.filter() return objects with the identical interface, letting downstream code (text extraction, table-finding) stay agnostic of whether it’s working with a full page or a sliced one. Feature modules build on top of this shared object model rather than touching pdfminer directly: table.py implements a TableFinder that turns edges into intersections into cells into tables purely from the object lists Page already exposes, display.py wraps Pillow to rasterize a page and draw debug overlays, and structure.py independently walks the PDF’s marked-content structure tree. This separation means table detection, visual debugging, and structure parsing can each evolve without touching the parsing layer.

Tech Stack Pure Python (3.10–3.14), with pdfminer.six doing the heavy lifting of PDF parsing and layout analysis, Pillow handling raster image generation for visual debugging and image object metadata, and pypdfium2 used for rendering support. Packaging is classic setuptools (setup.py + setup.cfg, no pyproject.toml), with a console-script entry point (cli.py, built on argparse) registered as the pdfplumber command. No web framework, database, or async runtime is involved — it’s a focused, dependency-light parsing library.

Code Quality The project runs a strict CI lint gate — black --check, isort --check-only, flake8, and mypy --strict --implicit-reexport all block merges, and the package ships a py.typed marker for downstream type-checking. Tests run under pytest with pytest-cov (coverage uploaded to Codecov) across a comprehensive tests/ directory covering table extraction, structure parsing, character deduplication, layout analysis, and PDF repair, backed by a tests/pdfs and tests/comparisons fixture library of real-world problem PDFs used as regression cases. This combination of strict typing, formatting, linting, and fixture-driven regression testing is a strong quality signal for a library that has to handle enormously varied real-world PDF structures.

API Design The public API favors chainable, low-boilerplate calls — pdfplumber.open(path).pages[0].extract_table() — while still exposing the full object model underneath for anyone who needs it. Method names read as verbs on the object they act on (.crop(), .filter(), .extract_text(), .extract_tables()), and the visual-debugging tools (.to_image(), .debug_tablefinder()) turn an otherwise opaque extraction failure into something a developer can literally see, which is unusual among PDF libraries that only expose extracted output with no way to inspect why extraction went wrong. The trade-off is a large surface of tuning parameters for table extraction (a dozen-plus table_settings keys) that require reading documentation to use well.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search