Extract text from password-protected (encrypted) PDFs in Python
Direct answer: To extract text from a password-protected PDF in Python, decrypt it first with pikepdf — pikepdf.open("file.pdf", password="yourpass").save("decrypted.pdf") — then run extraction on the decrypted file with pdfmux. The catch most people miss: there are two kinds of PDF password. A user password is required to open the file at all; an owner password lets anyone open it but blocks copying or printing. They need different handling, and 90% of “I can’t extract text” cases are actually the second kind — the file opens fine, but a permissions flag is silently blocking text extraction. This guide covers both, plus AES-256 encryption and batch decryption.
The two kinds of PDF password
Before writing any code, understand which problem you actually have. The PDF spec defines two distinct passwords, and they behave completely differently:
- User password (open password). The file is genuinely locked. You cannot open it, render it, or read a single byte of content without the password. Your PDF viewer prompts you before showing anything.
- Owner password (permissions password). The file opens normally — no prompt — but it carries permission flags that restrict copying text, printing, or editing. Many “secured” statements and reports use this. The file isn’t really hidden from you; a flag is just asking software to refuse certain actions.
This distinction matters because the failure looks identical from the outside: “my extractor returns empty text.” For a user-password file, you need the password. For an owner-password file, you already have full access — you just have to strip the restriction flag before your extraction library will cooperate.
import pikepdf
def diagnose(path: str) -> str:
try:
with pikepdf.open(path) as pdf:
# Opened with no password → not user-encrypted
if pdf.is_encrypted:
return "owner-password (opens freely, has permission restrictions)"
return "not encrypted"
except pikepdf.PasswordError:
return "user-password (cannot open without the password)"
print(diagnose("document.pdf"))
Decrypting a user-password PDF with pikepdf
pikepdf wraps the battle-tested qpdf C++ library and is the most reliable option in Python. It handles every encryption scheme PDFs use in 2026 — RC4 (legacy), AES-128, and AES-256 — transparently. You supply the password once; saving produces a clean, unencrypted file.
import pikepdf
def decrypt(path: str, password: str, out_path: str) -> None:
with pikepdf.open(path, password=password) as pdf:
pdf.save(out_path) # saved without encryption
decrypt("locked.pdf", "s3cret", "unlocked.pdf")
If the password is wrong, pikepdf raises pikepdf.PasswordError — catch it and prompt again rather than letting it crash:
import getpass
import pikepdf
def decrypt_interactive(path: str, out_path: str, max_tries: int = 3) -> bool:
for attempt in range(1, max_tries + 1):
pw = getpass.getpass(f"Password for {path} (attempt {attempt}/{max_tries}): ")
try:
with pikepdf.open(path, password=pw) as pdf:
pdf.save(out_path)
return True
except pikepdf.PasswordError:
print(" Wrong password.")
return False
To be clear on scope: this is about decrypting PDFs you are authorized to open — your own statements, reports your employer issued you, documents a client sent you. It is not about cracking passwords you don’t have. There is no password-guessing code here, and there shouldn’t be in yours either.
Stripping owner-password restrictions
This is the more common case. The file opens with no password at all, but a permission flag blocks text extraction. Because you can already open it, pikepdf reads it freely — and re-saving without encryption drops the restriction:
import pikepdf
with pikepdf.open("restricted.pdf") as pdf: # no password needed
if pdf.is_encrypted:
pdf.save("unrestricted.pdf") # saves with permissions cleared
Only do this for documents you have a legitimate right to use. Removing owner restrictions on a file you don’t own — to bypass a publisher’s copy protection, for instance — may breach the document’s terms or local law. The technical capability and the right to use it are separate questions.
Extracting the text once decrypted
With a clean file in hand, extraction is the easy part. Run pdfmux on the decrypted PDF:
from pdfmux import process
result = process("unlocked.pdf", quality="standard")
print(result.text) # clean Markdown
print(f"Confidence: {result.confidence:.0%}")
pdfmux’s self-healing pipeline handles whatever the decrypted file turns out to be — digital text, tables, or scanned pages that need OCR. On the opendataloader-bench of 200 real-world PDFs it scores 0.905 overall, the best of any free tool, so the output is clean Markdown with structure intact rather than a wall of run-together text.
You can chain decryption and extraction into a single function so callers never touch the intermediate file:
import tempfile
import pikepdf
from pdfmux import process
from pathlib import Path
def extract_encrypted(path: str, password: str | None = None):
"""Decrypt (if needed) and extract text in one step."""
with pikepdf.open(path, password=password or "") as pdf:
if not pdf.is_encrypted:
return process(path, quality="standard")
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp:
pdf.save(tmp.name)
tmp_path = tmp.name
try:
return process(tmp_path, quality="standard")
finally:
Path(tmp_path).unlink(missing_ok=True) # don't leave a decrypted copy on disk
result = extract_encrypted("statement.pdf", password="2026")
print(result.text)
Note the finally block: an unencrypted copy of a sensitive document is a liability the moment it lands on disk. Delete it as soon as extraction finishes.
The PyMuPDF alternative
If you already use PyMuPDF elsewhere, it can authenticate and extract in one library without a separate decrypt-and-save step. The API is slightly different: needs_pass tells you if a user password is required, and authenticate() returns a non-zero integer on success.
import fitz # PyMuPDF
doc = fitz.open("locked.pdf")
if doc.needs_pass:
if doc.authenticate("s3cret") == 0:
raise ValueError("Wrong password")
text = "\n".join(page.get_text() for page in doc)
The trade-off: PyMuPDF’s get_text() gives you raw text with no table reconstruction, heading detection, or OCR fallback. It’s fine for a quick digital-text dump, but for anything with tables or scanned pages you’ll want pdfmux on the decrypted file — the same reason pdfmux routes pages instead of using one extractor for everything.
Decrypting a folder of PDFs in batch
In practice you rarely have one locked file — you have a folder of monthly statements that all share one password. Decrypt and extract them in a loop, logging failures rather than crashing the whole run:
import pikepdf
from pdfmux import process
from pathlib import Path
def batch_decrypt_extract(folder: str, password: str) -> dict:
results, failures = {}, []
for pdf_path in Path(folder).glob("*.pdf"):
try:
with pikepdf.open(pdf_path, password=password) as pdf:
out = pdf_path.with_suffix(".decrypted.pdf")
pdf.save(out)
results[pdf_path.name] = process(str(out), quality="standard")
out.unlink() # clean up the decrypted copy
except pikepdf.PasswordError:
failures.append(pdf_path.name)
if failures:
print(f"{len(failures)} file(s) had a different password: {failures}")
return results
extracted = batch_decrypt_extract("statements/", "shared-password")
print(f"Extracted {len(extracted)} documents")
For larger collections, pdfmux also offers process_batch with parallel workers once the files are decrypted — useful when you’re ingesting hundreds of pages, as covered in batch PDF processing in Python.
Which approach to use
| Scenario | Tool | Why |
|---|---|---|
| User password, need clean structured text | pikepdf → pdfmux | Reliable decrypt + best-in-class extraction |
| Owner-password restrictions only | pikepdf re-save | Clears permission flags, no password needed |
| Quick digital-text dump, already on PyMuPDF | PyMuPDF authenticate | One library, no temp file |
| Folder sharing one password | pikepdf batch loop | Decrypt + extract + log failures |
| Scanned, encrypted statement | pikepdf → pdfmux[ocr] | OCR runs after decryption, on CPU |
A note on encryption strength
Modern PDFs (since the 2.0 spec) use AES-256, which is genuinely strong — there is no shortcut around a user password you don’t have, and pikepdf will not pretend otherwise. Older files may use 40-bit or 128-bit RC4, which is cryptographically weak by today’s standards, but “weak” still means you need the password; pikepdf simply decrypts faster once you supply it. The takeaway: encryption strength affects nothing about this workflow as long as you have legitimate access. You provide the password, the library does the rest.
FAQ
Do I need the password to remove owner-password restrictions? No. An owner-password (permissions) PDF opens with no password — the restriction is just a flag. Re-saving with pikepdf clears it. You only need a password for user-password (open) protection.
What if I don’t know which type of password the file has?
Run the diagnose() function above. It opens the file with no password: success with is_encrypted == True means owner-password; a PasswordError means user-password.
Can pdfmux open encrypted PDFs directly? Decrypt first, then extract. Separating the steps keeps the extraction pipeline simple and means the same decrypt logic works regardless of which extractor you run afterward.
Is the decrypted file a security risk?
Yes, if you leave it lying around — it’s the document with its protection removed. Write it to a temp file and delete it in a finally block, as shown above, so a plaintext copy never persists.
Does this work on scanned encrypted PDFs?
Yes. Decrypt with pikepdf, then extract with pdfmux[ocr]. OCR runs on CPU with no GPU or API keys after the file is unlocked.
Is removing PDF protection legal? For documents you own or are authorized to access — your statements, reports issued to you — yes. Bypassing protection on third-party copyrighted material may violate terms of use or law. The capability isn’t the permission.
Keep reading
- What self-healing PDF extraction actually looks like — the extract-audit-repair pipeline that runs after decryption
- Detecting scanned PDFs in Python — tell digital from scanned before you OCR
- Batch PDF processing in Python — parallel extraction across a folder
- PyMuPDF vs marker vs Docling — why page routing beats a single extractor
Last updated: June 2026. Benchmark figures are from the opendataloader-bench (200 real-world PDFs).