Back to Blog
Python

Python pypdf: Extract Text, Merge, Split, and Rotate PDFs

python pypdf extract text merge split and rotate pdf: Learn to use pypdf in Python for extracting text, merging multiple PDFs, splitting pages, and rotating pages with...

pypdfPDF manipulationtext extractionPDF mergingPDF splittingpage rotation
Illustration of a Python script manipulating PDF pages with pypdf, showing text extraction, merging, splitting, and rotation icons.

python pypdf extract text merge split and rotate pdf requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

Working with PDFs in Python often means reaching for pypdf, a pure-Python library that can extract text, merge documents, split pages, and rotate pages. This article walks through the core operations you'll need for common PDF processing tasks using pypdf, from a minimal script to a combined workflow.

Installing pypdf and Loading a PDF

Install pypdf with pip:

pip install pypdf

pypdf is the successor to PyPDF2, so most code written for PyPDF2 works with pypdf after a minor import change. The primary classes are PdfReader for reading and PdfWriter for writing. To load an existing PDF:

from pypdf import PdfReader reader = PdfReader("input.pdf") print(f"Page count: {len(reader.pages)}")

The PdfReader object gives access to the document's metadata and pages. Each page is a PageObject that supports the operations described below. Loading a PDF does not automatically extract text or render pages; it only parses the file structure, so the initial cost is relatively low.

Extracting Text from PDF Pages

Text extraction is one of the most common reasons to use pypdf. The extract_text() method on a page object returns the text content as a string:

from pypdf import PdfReader reader = PdfReader("report.pdf") for page in reader.pages: text = page.extract_text() print(text)

You can also target a specific page by index (zero-based):

first_page_text = reader.pages[0].extract_text()

extract_text() relies on the text information embedded in the PDF. If the PDF contains scanned images without an OCR layer, the method returns an empty string or garbled output. For such documents, you need OCR tools like Tesseract in combination with image extraction. pypdf does not perform OCR.

Another limitation is that text extraction order may not match the visual reading order for complex layouts with multiple columns or text boxes. For simple, linear documents, the result is usually accurate. If you need precise layout preservation, consider a library like pdfplumber or PyMuPDF.

Merging Multiple PDFs

Merging PDFs with pypdf involves creating a PdfWriter and adding pages from one or more readers. The simplest approach is to use writer.append() to add all pages from a file:

from pypdf import PdfWriter writer = PdfWriter() writer.append("part1.pdf") writer.append("part2.pdf") writer.write("combined.pdf")

append() accepts a file path, a file-like object, or a PdfReader instance. It adds every page in order. For more control, you can add individual pages manually:

from pypdf import PdfReader, PdfWriter writer = PdfWriter() reader1 = PdfReader("part1.pdf") reader2 = PdfReader("part2.pdf") for page in reader1.pages: writer.add_page(page) # Add only the first two pages from part2 for page in reader2.pages[:2]: writer.add_page(page) writer.write("partial_merge.pdf")

add_page() accepts a PageObject from any reader. The page object is copied into the writer, so you can mix pages from different sources without affecting the original files.

When merging many large PDFs, consider the memory footprint. PdfWriter holds references to the page objects, and the underlying data may be loaded into memory. If you are merging hundreds of files, process them in batches or use writer.append() with file paths, which streams the data more efficiently than manually adding each page.

Splitting a PDF into Separate Pages

Splitting a PDF means extracting one or more pages into a new file. The same PdfWriter and add_page() mechanism works for this. To split every page into its own PDF:

from pypdf import PdfReader, PdfWriter reader = PdfReader("original.pdf") for i, page in enumerate(reader.pages): writer = PdfWriter() writer.add_page(page) with open(f"page_{i+1}.pdf", "wb") as f: writer.write(f)

You can also extract a range of pages into a single file:

writer = PdfWriter() for page in reader.pages[2:5]: # pages 3-5 writer.add_page(page) with open("selected.pdf", "wb") as f: writer.write(f)

Splitting is memory-efficient if you create a new writer for each page and write it immediately. Holding all pages in one writer before writing can consume a lot of memory for large documents.

Rotating Pages

Page rotation is a property of the page object. You can set it with the rotate() method, which accepts a multiple of 90 degrees (positive for clockwise, negative for counter-clockwise):

from pypdf import PdfReader, PdfWriter reader = PdfReader("input.pdf") writer = PdfWriter() for page in reader.pages: page.rotate(90) # rotate clockwise writer.add_page(page) with open("rotated.pdf", "wb") as f: writer.write(f)

rotate() modifies the page object in place and returns the same object. The rotation is applied to the page's display orientation, not to the content itself. The underlying text and images are not re-rendered, so the file size remains similar.

You can also rotate a single page by its index:

page = reader.pages[0] page.rotate(-90) writer.add_page(page)

Note that rotate() accumulates: calling it twice with 90 results in a 180-degree rotation. If you need to set an absolute rotation, use page.rotation = 180 directly. The rotation property is an integer representing degrees clockwise.

Combining Operations in a Realistic Workflow

In practice, you often need to combine these operations. For example, you might want to extract text from only the rotated pages, or merge a subset of pages after rotating them. Here's a workflow that rotates the first page, extracts text from the second, and merges the result with another file:

from pypdf import PdfReader, PdfWriter # Load source documents source = PdfReader("source.pdf") other = PdfReader("other.pdf") # Rotate the first page of source source.pages[0].rotate(90) # Extract text from the second page text = source.pages[1].extract_text() print("Extracted:", text) # Build a new PDF with the rotated page and all pages from other writer = PdfWriter() writer.add_page(source.pages[0]) for page in other.pages: writer.add_page(page) with open("combined_output.pdf", "wb") as f: writer.write(f)

This example shows how PdfReader and PdfWriter work together. You can reuse the same writer to build a complex document from multiple sources while applying transformations like rotation.

One important detail: when you call extract_text() on a page that has been rotated, the text extraction may reflect the original orientation because the text is stored in the content stream. Rotation is a display property, so the extracted text order might not match the visual order after rotation. If you need text that matches the rotated appearance, you may need to render the page to an image first, which pypdf does not do directly.

Performance and Memory Considerations

pypdf is a pure-Python implementation, so it is generally slower than libraries that use native C bindings, such as PyMuPDF (fitz) or pdfium. For simple text extraction or merging a few files, the difference is negligible. For processing thousands of pages, you may notice a significant slowdown.

Memory usage is a more critical concern. PdfReader loads the entire file structure into memory when you instantiate it. For very large PDFs (hundreds of megabytes), this can exhaust available RAM. The PdfWriter also accumulates page objects until you call write(). To reduce memory pressure:

  • Use append() with file paths instead of manually adding pages when you don't need to modify each page.
  • Write intermediate results to disk and clear the writer periodically.
  • Process pages in chunks and reuse a single writer by writing and then resetting it.

For example, to split a large PDF into smaller files without holding all pages in memory:

from pypdf import PdfReader, PdfWriter reader = PdfReader("huge.pdf") chunk_size = 10 for start in range(0, len(reader.pages), chunk_size): writer = PdfWriter() for page in reader.pages[start:start + chunk_size]: writer.add_page(page) with open(f"chunk_{start // chunk_size}.pdf", "wb") as f: writer.write(f)

This approach limits the number of pages held in the writer at any time. The reader still holds the full document structure, but that is unavoidable with pypdf. If memory becomes a hard constraint, consider using a streaming PDF library or an external command-line tool like qpdf or pdfseparate.

Another operational consideration is file size. When you merge or rotate pages, pypdf copies the original content streams without recompressing them. The output file size is typically close to the sum of the inputs, but it can increase if the original PDFs used different compression schemes. There is no built-in compression in pypdf, so if you need to reduce file size, you may need to post-process with another tool.

Finally, be aware of encryption. pypdf can read encrypted PDFs if you provide the password, but it cannot remove encryption. If you need to process password-protected files, pass the password to PdfReader:

reader = PdfReader("encrypted.pdf") if reader.is_encrypted: reader.decrypt("password")

After decryption, the reader behaves like a normal PDF. The same applies to PdfWriter if you want to encrypt the output, though that is a separate topic.

python pypdf extract text merge split and rotate pdf: Practi | RYUSLOG DEV