pdfplumber
| Language | Python 3.8+ |
|---|---|
| License | MIT |
| Repository | github.com/jsvine/pdfplumber |
| Documentation | README |
| Depends on | pdfminer.six, pypdfium2 (page images), Pillow |
| Read / write | yes / no |
pdfplumber gives you every character, line, rectangle and curve on a page with its coordinates, font and size, and builds words, text lines and tables from them. Its table finder uses ruling lines or text alignment and is configurable, which makes it the go-to library for extracting tables from reports, statements and invoices. page.to_image() draws what was detected on top of the rendered page, so you can tune settings visually.
It’s slower than PyMuPDF and works only on machine-generated PDFs (scanned pages need OCR first). It doesn’t modify PDFs.
Installation#
pip install pdfplumber
Basic usage: extract text from a PDF#
import pdfplumber
with pdfplumber.open("in.pdf") as pdf:
print(len(pdf.pages), "pages")
for page in pdf.pages:
print(f"--- page {page.page_number} ({page.width} x {page.height}) ---")
print(page.extract_text())
page.extract_text(layout=True) keeps the visual layout with spaces, similar to pdftotext -layout.
How to extract tables from a PDF#
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[0]
for table in page.extract_tables():
for row in table:
print(row) # list of cell strings, None for empty cells
For tables without ruling lines, base the detection on text alignment:
table = page.extract_table({"vertical_strategy": "text", "horizontal_strategy": "text"})
How to get words and characters with positions#
words = page.extract_words()
for w in words[:10]:
print(w["text"], w["x0"], w["top"], w["x1"], w["bottom"])
ch = page.chars[0]
print(ch["text"], ch["fontname"], ch["size"])
Coordinates are in points from the top-left corner of the page (top, bottom), unlike PDF’s bottom-left origin.
How to extract text from part of a page#
# (x0, top, x1, bottom): the top half of the page
top_half = page.crop((0, 0, page.width, page.height / 2))
print(top_half.extract_text())
for match in page.search("Total"):
print(match["text"], match["x0"], match["top"])
How to debug extraction visually#
im = page.to_image(resolution=150)
im.draw_rects(page.extract_words()) # outline every word
im.save("debug.png")
# show the table finder's lines and cells
page.to_image(resolution=150).debug_tablefinder().save("tables.png")
How to read metadata and open encrypted PDFs#
with pdfplumber.open("secret.pdf", password="user") as pdf:
print(pdf.metadata.get("Title"), pdf.metadata.get("Producer"))
Tips#
- Pass
laparams={}topdfplumber.opento get pdfminer’s layout objects (page.textboxhorizontals). page.filter(lambda obj: obj.get("size", 0) > 12)keeps only objects you care about, e.g. headings.- The
pdfplumbercommand line exports characters, words or tables as CSV or JSON:pdfplumber in.pdf --format csv.