Python Central HubSign in

Automation and Scripting / Phase 2: Office & Productivity Automation

Extracting Text from PDFs

Extract text from PDF files and learn when OCR is needed.

Text extraction is tricky

Some PDFs contain real text.

Others are scans (images), which require OCR.

Extract with pypdf

Python
from pypdf import PdfReader
 
reader = PdfReader("input.pdf")
 
text_parts = []
for page in reader.pages:
    text_parts.append(page.extract_text() or "")
 
text = "\n".join(text_parts)
print(text[:1000])

When you need OCR

If extract_text() returns empty or garbage:

  • use OCR tools (like Tesseract)
  • or use specialized PDF extractors

Why extraction is unreliable

A PDF is not a text document. It is a set of drawing instructions: put these glyphs at these coordinates on this page. There is no built-in notion of a paragraph, a table, or reading order. A library like pypdf has to guess how the glyphs group into lines, and the guess can be wrong.

There are three kinds of PDF, and the right tool depends on which you have:

  1. Text PDFs made from Word, LaTeX, or a web page. extract_text() works, though layout may be messy.
  2. Scanned PDFs where each page is a picture. extract_text() returns an empty string. You need OCR.
  3. Protected PDFs that require a password. reader.is_encrypted is True, and you call reader.decrypt(password) first.

Checking the result

Never assume the text came out. A small check catches scans early.

Python
from pathlib import Path
from pypdf import PdfReader
 
 
def extract_pdf_text(path: Path) -> str:
    reader = PdfReader(path)
    if reader.is_encrypted:
        raise ValueError(f"{path.name} is password protected")
 
    pages = []
    for number, page in enumerate(reader.pages, start=1):
        text = (page.extract_text() or "").strip()
        if not text:
            print(f"page {number}: no text found, may be a scan")
        pages.append(text)
    return "\n\n".join(pages)
 
 
text = extract_pdf_text(Path("input.pdf"))
print(len(text), "characters")
print(text[:500])

The or "" matters because some versions return None for an empty page. Counting pages with no text tells you whether the whole file is a scan or only a few pages are.

Cleaning the text

Extracted text often has line breaks in the middle of sentences, hyphenated words split across lines, and repeated headers and footers. Typical fixes are to join lines that do not end in a full stop, to remove a known footer with str.replace, and to use a regular expression for values you need, such as invoice numbers or dates. For tables, extract the text first and see what you get. If the columns do not line up, a table-aware tool such as pdfplumber is a better choice.

Adding OCR

For scans, render each page to an image and run OCR on it. The usual combination is pdf2image (needs the Poppler tool installed) with pytesseract (needs Tesseract installed). It is slower and less accurate than text extraction, so check a sample by eye.

Common mistakes

  • Trusting the output. Always look at a sample page.
  • Using the old PyPDF2 name in new code. pypdf is the maintained project.
  • Forgetting to handle encrypted files.
  • Loading hundreds of large PDFs into one string. Process and write out one file at a time.

Adapting it

Loop over a folder of PDFs, save each as a .txt with the same stem, and search the text files with the earlier search lesson. Or pull invoice numbers with re.findall into a CSV file.

๐Ÿงช Try It Yourself

Exercise 1 โ€“ List Files with os.listdir

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 2 โ€“ Join Paths with os.path.join

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 3 โ€“ Write and Read a File

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Was this page helpful?

Let us know how we did