pdfplumber vs PyMuPDF vs pypdf (PyPDF2): Which to Use
pdfplumber vs PyMuPDF vs pypdf: pick by tables, speed, and license. PyPDF2 is now pypdf. MIT vs AGPL, find_tables, and when to use both.
Table of Contents10 sections
Use PyMuPDF for speed, images, and page rendering. Use pdfplumber for tables and an MIT license. Use pypdf (the current name for PyPDF2) to split, merge, or pull basic text. Most production pipelines I build use pdfplumber and PyMuPDF together. pypdf stays in the stack for merge, split, and rotate.
The URL still says PyPDF2 because that is the name people typed when this page first ranked. The live package is pypdf. import fitz is PyMuPDF under its old name.
Quick comparison
| pdfplumber | PyMuPDF (fitz) |
pypdf (was PyPDF2) | |
|---|---|---|---|
| Text extraction | Good, layout-aware | Excellent | Basic |
| Table extraction | Built-in, strongest | find_tables() since 1.23 |
None |
| Layout / coordinates | Character, word, line | Blocks, spans, bbox | Limited |
| Image extraction | Limited | Excellent | None |
| Speed | Slowest (pure Python) | Fastest (C / MuPDF) | Fine for merge/split |
| Scanned PDFs | Text layer only | Text layer; can render for OCR | Text layer only |
| Markdown / RAG | DIY | pymupdf4llm |
DIY |
| License | MIT | AGPL-3.0 or paid | BSD |
pdfplumber vs PyMuPDF
These two overlap on text, then diverge.
pdfplumber sits on pdfminer.six. It sees every character, word, and line, with coordinates. That is why its table finder works: it reconstructs rows and columns from geometry. PDFs do not have tables. It is slower because that work happens in Python.
PyMuPDF binds the MuPDF C engine. Text comes out faster, images extract cleanly, and you can render a page to a pixmap for OCR. Table support arrived later as page.find_tables(), inspired by pdfplumber. On clean, ruled grids it is usable. On borderless or messy financial tables, I still reach for pdfplumber.
I use pdfplumber when the page is a table, I need debug_tablefinder(), or AGPL is off the table. I use PyMuPDF when volume, images, or rendering matter more than perfect cells. Mixed documents (invoices with line items plus letters, scans, logos) get both: table pages to pdfplumber, everything else to PyMuPDF.
Text extraction
import pdfplumber
with pdfplumber.open("invoice.pdf") as pdf:
for page in pdf.pages:
text = page.extract_text()
print(text)
extract_text() walks left-to-right, top-to-bottom. On a single-column letter that is enough. Multi-column layouts and tightly packed forms often need a crop or word-level filtering instead.
import pymupdf
doc = pymupdf.open("invoice.pdf")
for page in doc:
print(page.get_text())
For headers vs body vs labels, ask for the dict:
for page in doc:
for block in page.get_text("dict")["blocks"]:
if block["type"] != 0:
continue
for line in block["lines"]:
for span in line["spans"]:
print(span["text"], span["bbox"], span["size"])
import fitz still works. It is the same package. Current docs prefer import pymupdf.
Tables: extract_tables() vs find_tables()
pdfplumber is still the one I use when the table is the product.
with pdfplumber.open("invoice.pdf") as pdf:
page = pdf.pages[0]
tables = page.extract_tables()
for table in tables:
for row in table:
print(row)
Borderless tables need a text strategy, not the default line strategy:
table_settings = {
"vertical_strategy": "text",
"horizontal_strategy": "text",
"intersection_tolerance": 5,
}
tables = page.extract_tables(table_settings)
For cropping, merged cells, multi-page stitches, and debug_tablefinder(), use the table extraction guide.
PyMuPDF, since 1.23:
import pymupdf
doc = pymupdf.open("invoice.pdf")
page = doc[0]
found = page.find_tables()
for table in found:
print(table.extract())
# df = table.to_pandas()
# print(table.to_markdown())
find_tables() exists, so yes, PyMuPDF extracts tables. On the invoices and lab reports I see, pdfplumber still wins the ugly cases. I have also seen find_tables() run slower than pdfplumber on some pages. The C engine helps get_text(), not every table heuristic.
Images and rendering
PyMuPDF is the tool for embedded images and for turning a page into pixels:
doc = pymupdf.open("report.pdf")
for page_num, page in enumerate(doc):
for img_index, img in enumerate(page.get_images(full=True)):
xref = img[0]
info = doc.extract_image(xref)
with open(f"page{page_num}_img{img_index}.png", "wb") as f:
f.write(info["image"])
pdfplumber can render a page debug image. It is not an image-extraction library.
Speed
I don’t have timings of my own for this post. PyMuPDF is a C binding; pdfplumber walks characters in Python via pdfminer.six. On a handful of pages you will not care. On thousands of documents a day, PyMuPDF is the default for text and I keep pdfplumber for the table pages.
If someone quotes “10×” or “50×”, treat it as order of magnitude, not a number you can put in an SLA. Throughput on your PDFs depends on page count, image density, and whether you are extracting text or reconstructing tables.
pypdf vs PyMuPDF vs pdfplumber
pypdf is the library people still install first, often under the old name.
It is the right tool for merging, splitting, rotating, cropping, and encrypting PDFs. Text extraction is a side effect, and a weak one: multi-column pages and odd spacing come out garbled. It has no table API.
pypdf vs PyMuPDF: PyMuPDF wins extraction, rendering, and images. pypdf wins a permissive BSD license and a pure-Python install. If you only need to concatenate 400 statements into one file, pypdf is enough and simpler to deploy.
pypdf vs pdfplumber: pdfplumber wins anything that looks like data. pypdf wins file surgery. Do not extract invoice line items with pypdf.
pypdf vs PyPDF2: PyPDF2 was merged back into pypdf. Development continues on pypdf. New code should pip install pypdf. The import change for the common path is:
from pypdf import PdfReader # was: from PyPDF2 import PdfReader
reader = PdfReader("invoice.pdf")
for page in reader.pages:
print(page.extract_text())
People still search PyPDF2, so the old name stays in the title. For a new project, type pypdf.
License: pdfplumber MIT vs PyMuPDF AGPL
Check the license before you pip install.
pdfplumber is MIT. You can use it in a closed-source commercial product. Read the file in the repo if your legal team needs the text.
pypdf is BSD. Permissive, fine in proprietary software.
PyMuPDF is AGPL-3.0. If you ship a closed-source product that includes PyMuPDF (including a SaaS that lets users upload PDFs), AGPL’s copyleft is a problem unless you buy a commercial license from Artifex. Plenty of teams only discover this at security review.
If the product cannot take AGPL and you need tables, pdfplumber is the default. If you need PyMuPDF’s speed in a proprietary stack, budget for the paid license rather than hoping AGPL “probably doesn’t apply.”
fitz vs PyMuPDF
They are the same library. The PyPI package is pymupdf. For years the Python import was fitz, the historical name of MuPDF’s binding. You will still see import fitz in older code and in Stack Overflow answers.
import pymupdf
# equivalent: import fitz
pip install fitz is a different, unrelated package. Install pymupdf.
Scanned PDFs
None of these three reads text that is only pixels. If page.extract_text() or page.get_text() comes back empty on a page you can clearly see, the PDF is almost certainly a scan (or a hybrid with scanned pages).
The usual path is render with PyMuPDF, then OCR:
import io
import pymupdf
import pytesseract
from PIL import Image
doc = pymupdf.open("scanned_report.pdf")
for page in doc:
pix = page.get_pixmap(matrix=pymupdf.Matrix(300 / 72, 300 / 72))
img = Image.open(io.BytesIO(pix.tobytes("png")))
print(pytesseract.image_to_string(img))
Detecting scanned pages, DPI, and what to do after OCR is in extract data from scanned PDFs.
Markdown, RAG, and pymupdf4llm
If the output is Markdown for an LLM, PyMuPDF4LLM wraps to_markdown() around PyMuPDF. That is a better starting point than reconstructing headings from pdfplumber word lists.
Markdown is still raw extraction. For invoices, CoAs, and anything you will load into a database, I still want a Pydantic schema and validation, not a pile of Markdown. Use pymupdf4llm for retrieval. Use a schema when a field has to be right.
Other names you will hit
- pdfminer.six: what pdfplumber wraps. Use pdfplumber unless you need the lower-level API.
- Camelot: another table specialist. Worth a look when pdfplumber’s merged-cell behaviour is the blocker.
- pypdfium2: PDFium bindings. Fast rendering alternative to PyMuPDF; different license story.
- Docling: layout-aware parsing aimed at LLM pipelines. Heavier than these three. Relevant when rule-based tables are not enough.
When the PDF layout itself keeps shifting across suppliers, see handling layout variations.
Decision framework
In production I usually import both pdfplumber and PyMuPDF. pypdf only if the pipeline also mutates files.
FAQ
Is pdfplumber or PyMuPDF better?
PyMuPDF is better for speed, images, and rendering. pdfplumber is better for tables and for a permissive MIT license. If you have to pick one library for mixed business PDFs, start with both and route by page type.
Does PyMuPDF extract tables?
Yes. page.find_tables() has been in PyMuPDF since 1.23, and it was inspired by pdfplumber’s table finder. It is fine on simple ruled tables. For borderless or irregular tables I still use pdfplumber.
Is PyPDF2 deprecated?
The project was merged into pypdf. Install pypdf and import PdfReader from there. Old PyPDF2 code often ports with a one-line import change.
Can I use PyMuPDF commercially?
You can use it if you comply with AGPL-3.0 (which usually means open-sourcing the product that includes it) or you buy a commercial license from Artifex. pdfplumber (MIT) and pypdf (BSD) do not have that constraint.
Is pdfplumber free for commercial use?
Yes. MIT license. That is the main reason it stays in proprietary pipelines even when PyMuPDF would be faster.
What is the difference between fitz and PyMuPDF?
fitz is the old import name for PyMuPDF. Use pip install pymupdf. Do not pip install fitz.
Why does extract_text() return None?
On a page that visibly has content, you are probably looking at a scanned image with no text layer. Confirm with PyMuPDF: empty get_text() plus images on the page. Then OCR. Details in the scanned PDF guide.
Should I use pdfplumber and PyMuPDF together?
Yes, for production document mix. PyMuPDF for text, images, and scans-to-raster. pdfplumber for table pages. I do this on invoice and lab-report pipelines; the cost of two dependencies is small next to bad rows.
Is pymupdf4llm a replacement for pdfplumber?
No. pymupdf4llm produces Markdown for RAG. pdfplumber produces tables and coordinates.
Last updated on