This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /blog/extract-text-from-pdf-using-python.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Extract text from PDFs in Python with pypdf and OCR

Table of contents

    Extract selectable PDF text locally with pypdf, or use Nutrient DWS Processor API for an OCR and JSON extraction workflow. Start by identifying whether your PDF contains text or only scanned images.
    Extract text from PDFs in Python with pypdf and OCR
    TL;DR

    To extract text from a PDF in Python, open it with pypdf.PdfReader and call page.extract_text() for each page. This reads an existing text layer; it doesn’t recognize text in images. For scanned PDFs, run optical character recognition (OCR) first. This tutorial covers local extraction and a Nutrient API workflow with an explicit OCR step.

    Skip the parsing stack: One API call

    If your application needs to extract text from PDFs, including scans, Nutrient’s PDF OCR API returns it in one request, with a free tier and no credit card. Method 2 below shows the Python code; Method 1 covers pypdf.

    What kind of PDF are you parsing?

    The input determines which extraction method you need:

    • Digitally generated PDF — Use pypdf(opens in a new tab) to read the existing text layer. Reading order and spacing can still need cleanup.
    • Image-only scan — Run OCR to recognize the text. Calling extract_text() alone won’t recover words from a page image.
    • Scan with an OCR layer — pypdf can read that layer, but recognition errors from the earlier OCR remain.
    • Password-protected PDF — Supply the authorized password before extraction. Encryption and OCR are separate concerns.

    The examples cover local extraction with pypdf and OCR with Nutrient DWS Processor API. For new cloud extraction workflows, consider Nutrient Data Extraction API. Its Markdown extraction guide includes Python examples for the separate /extraction/parse endpoint. Review cloud-processing requirements before uploading confidential documents.

    Requirements

    Use Python 3.12 or newer and a virtual environment. Create a working folder for this tutorial:

    Terminal window
    mkdir text_extract_pdf
    cd text_extract_pdf
    python3 -m venv .venv
    source .venv/bin/activate

    On Windows, create the environment with py -m venv .venv and activate it with .venv\Scripts\Activate.ps1 in PowerShell. Create app.py in the working folder.

    Install pypdf(opens in a new tab) to read PDFs and extract their text:

    Terminal window
    python -m pip install pypdf

    Use these two test PDFs:

    Save the PDFs beside app.py and update the file names in the examples to match.

    Method 1: Extract text from PDF using pypdf

    To extract text from a PDF in Python, open the file with PdfReader and call .extract_text() on each page. pypdf is a Python library for reading and manipulating PDF files. Here’s how to extract text from each page:

    app.py
    from pypdf import PdfReader
    reader = PdfReader("compressed.tracemonkey-pldi-09.pdf")
    for page in reader.pages:
    print(page.extract_text() or "")

    Run python app.py to print the extracted text in your terminal. Check the result against the PDF: Columns, ligatures, and positioned text can affect order and spacing. The code creates a PdfReader(opens in a new tab) object. Then it loops over the pages with the .pages(opens in a new tab) property and prints each page’s text with the .extract_text(opens in a new tab) method.

    Skipping headers and footers with pypdf

    You can pass pypdf visitor functions, which it calls with each operator or text fragment. The text visitor receives five arguments: the text, the current transformation matrix, the text matrix, the font dictionary, and the font size. Combine the text and current transformation matrices with mult(tm, cm) to calculate the position in page user space.

    The following example filters fragments from one page of this PDF document(opens in a new tab) using a y-coordinate range. It also keeps fragments at y == 0 to preserve line breaks in this file. These conditions are specific to the example. The pypdf extraction guide(opens in a new tab) warns that coordinates can be difficult to interpret in complex documents:

    from pypdf import PdfReader, mult
    reader = PdfReader("GeoBase_NHNC1_Data_Model_UML_EN.pdf")
    page = reader.pages[3]
    parts = []
    def visitor_body(text, cm, tm, font_dict, font_size):
    y = mult(tm, cm)[5]
    if 50 < y < 720 or y == 0:
    parts.append(text)
    page.extract_text(visitor_text=visitor_body)
    print("".join(parts))

    How to extract text from encrypted PDFs in Python

    pypdf can decrypt supported encrypted PDFs when you provide the correct password. The following example checks the decryption result before reading pages.

    To work with encrypted documents, you’ll need to install the cryptography package:

    Terminal window
    python -m pip install cryptography

    Use the .decrypt method to decrypt a PDF file before extracting text from it:

    from pypdf import PdfReader
    reader = PdfReader("encrypted-pdf.pdf")
    if reader.is_encrypted:
    if not reader.decrypt("password"):
    raise ValueError("The PDF password is incorrect.")
    # Extract text from all pages.
    for page in reader.pages:
    print(page.extract_text() or "")

    Method 2: Extract text with Nutrient and OCR

    This example uses the Nutrient DWS Processor API /build workflow and a Processor API key. The request explicitly applies OCR in English and asks for plain text and structured text. Structured text describes text elements and their positions; it isn’t an application-specific invoice or table schema.

    Step 1: Sign up and get your API key

    Create an account(opens in a new tab), verify your email, and retrieve a key from API keys. Store it in the NUTRIENT_API_KEY environment variable rather than in source code.

    Image showing navigation to API keys on Nutrient API’s dashboard

    Step 2: Upload and extract text

    To work with Nutrient Processor API, you’ll need to install the requests package:

    Terminal window
    python -m pip install requests

    After installing the package, you can create a Python script to perform text extraction using the API’s /build endpoint:

    import json
    import os
    from pathlib import Path
    import requests
    api_key = os.environ.get("NUTRIENT_API_KEY")
    if not api_key:
    raise SystemExit("Set NUTRIENT_API_KEY before running this example.")
    instructions = {
    "parts": [{"file": "document"}],
    "actions": [{"type": "ocr", "language": "english"}],
    "output": {
    "type": "json-content",
    "plainText": True,
    "structuredText": True,
    },
    }
    try:
    with open("example.pdf", "rb") as document:
    response = requests.post(
    "https://api.nutrient.io/build",
    headers={"Authorization": f"Bearer {api_key}"},
    data={"instructions": json.dumps(instructions)},
    files={"document": ("example.pdf", document, "application/pdf")},
    timeout=120,
    )
    response.raise_for_status()
    result = response.json()
    except (OSError, requests.RequestException, ValueError) as error:
    raise SystemExit(f"Text extraction failed: {error}") from error
    Path("result.json").write_text(
    json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8"
    )
    for page in result.get("pages", []):
    print(page.get("plainText", ""))

    Save a PDF as example.pdf beside the script. Set NUTRIENT_API_KEY in your shell and run the script. It saves the JSON response to result.json and prints the plainText value from each entry in pages.

    The ocr action makes the recognition step explicit. Change language to match the document; for a PDF with a usable text layer, omit the actions entry if you only need extraction. The file name in parts must match the multipart upload name, document.

    Validate reading order and recognition against your documents. This request doesn’t guarantee perfect layout reconstruction or normalize every encoding problem. For named business fields, evaluate a separate data extraction workflow rather than treating positioned text as a completed schema.

    You can perform many operations using Nutrient Processor API, including text extraction, Office conversion, and OCR. Learn more by reading our documentation.

    pypdf vs. Nutrient: Which should you use?

    RequirementpypdfNutrient DWS Processor API
    Read an existing text layerLocal Python extractionHosted extraction
    Recognize text in scansRequires a separate OCR toolOCR action in the request
    Keep documents on your machineYesDocuments are uploaded
    Output shown in this tutorialText printed by pageJSON with plain and structured text
    Password-protected inputDecrypt with the authorized passwordConfigure password handling for the request

    Use pypdf when local extraction of existing text meets your needs. Choose the API when you need to combine OCR and other document operations in a hosted workflow. Test both against representative PDFs before choosing.

    Troubleshooting PDF text extraction

    • Empty or missing text — Check whether the page is an image-only scan. pypdf needs an existing text layer.
    • Unexpected reading order — PDF drawing order can differ from human reading order, especially in columns and tables. Compare extracted text with the rendered page.
    • Headers remain in the output — Coordinate filters depend on page dimensions and transformations. Inspect positions for your own document.
    • Decryption fails — Confirm the password and encryption support before extracting text.
    • The API returns an error — Check the HTTP status, API key, available usage, and request instructions. Don’t save an error response as a successful extraction result.

    Conclusion

    Use pypdf to extract text that already exists in a PDF. Use OCR for image-only scans, and verify the recognition result before downstream processing.

    To run the Processor example, use the Processor signup(opens in a new tab) and API documentation. For new cloud extraction workflows, try Nutrient Data Extraction API(opens in a new tab) and follow its Python Markdown example. Data Extraction uses /extraction/parse and returns the Markdown string in output.markdown; the Processor example uses /build and a different response format.

    Need help choosing a library? Our Python PDF library comparison compares options for text extraction, merging, OCR, and other PDF tasks.

    FAQ

    Can I parse PDFs in Python without using OCR?

    Yes. If your PDF contains digital (selectable) text, you can extract it using pypdf without OCR. This works best for PDFs exported from Word, LaTeX, or similar tools.

    What if my PDF is a scanned document or image?

    You’ll need OCR to recognize text in page images. pypdf doesn’t perform OCR. The Nutrient example above includes an explicit OCR action before extraction.

    Can I extract structured data like paragraphs or table-like sections?

    The request above returns plain and structured text, including text elements and position information. Table extraction and named business fields need their own output options or extraction workflow.

    Is pypdf enough for enterprise projects?

    It can be, if its extraction behavior, performance, and local deployment match your requirements. Evaluate document complexity, OCR needs, throughput, and support instead of choosing by company size.

    Is the Nutrient API free to try?

    You can create a trial account to evaluate extraction. Check the current allowance and available operations in your dashboard before running a batch.

    Jonathan D. Rhyne

    Jonathan D. Rhyne

    Co-Founder and CEO

    Jonathan joined PSPDFKit in 2014. As Co-founder and CEO, Jonathan defines the company’s vision and strategic goals, bolsters the team culture, and steers product direction. When he’s not working, he enjoys being a dad, photography, and soccer.

    Explore related topics

    Free to start Start extracting structured data