pypdf — чистая Python-библиотека для чтения и правки PDF, прямая наследница PyPDF2. Ставится командой pip install pypdf, текст со страницы забирается тремя строками. Актуальная версия на PyPI — 6.16.1 от 14 августа 2026, лицензия BSD-3-Clause. На Python 3.11 и выше библиотека не тянет за собой ни одного стороннего пакета.

from pypdf import PdfReader

reader = PdfReader("otchet.pdf")
print(len(reader.pages))
print(reader.pages[0].extract_text())

Что важно знать до того, как вы напишете первую строчку:

  • примеры с PdfFileReader, getPage и extractText сегодня падают с ошибкой — эти вызовы удалены ещё в PyPDF2 3.0.0;
  • pypdf отдаёт текст, метаданные, склейку страниц и пароли, но метода для разбора таблиц у него нет вовсе;
  • таблицы забирает pdfplumber, скорость даёт PyMuPDF — у последнего лицензия AGPL, и это решает больше, чем миллисекунды;
  • скан без текстового слоя не прочитает ни одна из трёх библиотек: мы проверили, все три вернули ноль символов;
  • на нашем замере на одном и том же файле самая быстрая библиотека обогнала самую медленную более чем в пятнадцать раз.

Всё, что ниже, прогнано в чистом venv на Python 3.14.3 под Windows 11 с pypdf 6.16.1, pdfplumber 0.11.10 и PyMuPDF 1.28.2. Числа в тексте — вывод скрипта, который приведён целиком, а не оценка на глаз.

Если после разбора файлов нужно собрать документы обратно, у нас есть отдельный разбор про объединение PDF-файлов на Python. А когда вытащенные строки поедут в отчёт, пригодится пошаговое руководство по Яндекс Таблицам.

Почему код с PyPDF2 падает и как переписать его на pypdf

Библиотеку переименовали. На странице PyPDF2 в PyPI стоит официальная пометка: «The PyPDF2 project is going back to its roots. PyPDF2==3.0.X will be the last version of PyPDF2. Development will continue with pypdf==3.1.0». Последний релиз PyPDF2 — 3.0.1 от 31 декабря 2022 года, с тех пор разработка идёт только в пакете pypdf.

Заодно в версии 3.0.0 удалили старый camelCase-API. Мы поставили PyPDF2 3.0.1 в тот же venv и выполнили четыре вызова, которые кочуют по русскоязычным руководствам. Вот дословные ответы интерпретатора:

DeprecationError: PdfFileReader is deprecated and was removed in PyPDF2 3.0.0. Use PdfReader instead.
DeprecationError: reader.getPage(pageNumber) is deprecated and was removed in PyPDF2 3.0.0. Use reader.pages[page_number] instead.
DeprecationError: extractText is deprecated and was removed in PyPDF2 3.0.0. Use extract_text instead.
DeprecationError: getDocumentInfo is deprecated and was removed in PyPDF2 3.0.0. Use metadata instead.

Это не предупреждение в консоли, а исключение: скрипт останавливается. Таблица перевода на актуальный синтаксис:

Старый вызов Что писать в pypdf
PyPDF2.PdfFileReader(file) pypdf.PdfReader("file.pdf")
reader.numPages len(reader.pages)
reader.getPage(0) reader.pages[0]
page.extractText() page.extract_text()
reader.getDocumentInfo() reader.metadata
PdfFileWriter() PdfWriter()

Открывать файл через open(..., 'rb') тоже больше не обязательно: PdfReader принимает путь строкой, читает содержимое в память и файл открытым не держит — сразу после чтения его можно переименовать или удалить (проверили переименованием). Если проект застрял на PyPDF2, замена сводится к переименованию импорта и шести вызовов из таблицы — ломающих изменений в логике чтения нет.

ОНЛАЙН-ПРАКТИКУМ
ЗАПУСК нейросети DEEPSEEK R1 ЛОКАЛЬНО НА СВОЕМ КОМПЬЮТЕРЕ
ЧТО БУДЕТ НА ОБУЧЕНИИ?
  • ПОКАЖЕМ, КАК РАЗВЕРНУТЬ МОДЕЛЬ нейросети DEEPSEEK R1 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ
  • Где и как применять? Потестируем модель после установки на разных задачах
  • Как дообучить модель под себя?

pypdf, pdfplumber или PyMuPDF: чем библиотеки отличаются на деле

Выбор библиотеки по задаче
Выбор библиотеки по задаче

Спор «какая библиотека лучше» решается не бенчмарком, а тем, что лежит в вашем файле и какая у проекта лицензия. Данные в таблице — с карточек пакетов на PyPI, замеры — наши, методика ниже.

Параметр pypdf pdfplumber PyMuPDF
Версия на 17.08.2026 6.16.1 0.11.10 1.28.2
Лицензия BSD-3-Clause MIT AGPL 3.0 либо коммерческая Artifex
Минимальный Python 3.9 3.8 3.10
Наш замер на одном файле 8 мс 33 мс 2 мс
Таблицы метода нет extract_tables() find_tables()
Правка и запись PDF да нет, только чтение да
Пароли и шифрование да, включая AES-256 только ввод пароля да
Зависимости на Python 3.11 и выше ни одной, ниже — typing_extensions pdfminer.six, Pillow, pypdfium2 нет, но в колесе бинарная сборка MuPDF

Лицензия — та строка, из-за которой выбор чаще всего переигрывают уже после прототипа. PyMuPDF на PyPI объявлен как «Dual Licensed — GNU AFFERO GPL 3.0 or Artifex Commercial License». AGPL требует открыть исходники продукта, который библиотеку использует, включая случай, когда продукт работает как веб-сервис. Для внутреннего скрипта это безразлично, для закрытого SaaS — повод либо покупать коммерческую лицензию, либо остаться на pypdf с BSD.

Второй разделитель — что вы вытаскиваете. Автор pdfplumber описывает её назначение прямо: «Plumb a PDF for detailed information about each text character, rectangle, and line. Plus: Table extraction and visual debugging. Works best on machine-generated, rather than scanned, PDFs». То есть библиотека знает координаты каждого символа и линии — из этого и собирается таблица. У pypdf такого слоя нет по устройству, поэтому и метода для таблиц нет.

Короткое правило: правите и склеиваете PDF — pypdf; вытаскиваете таблицы — pdfplumber; гоните тысячи файлов в конвейере и лицензия позволяет — PyMuPDF.

Наш замер: сколько pypdf и соседи тратят на один и тот же файл

Чтобы цифры можно было перепроверить, тестовый PDF мы не искали, а собрали. Скрипт ниже сам создаёт документ на две страницы с кириллическим текстом и таблицей на шесть строк, а потом читает его тремя библиотеками. Он самодостаточный: положите его в пустую папку, поставьте pip install pypdf pdfplumber pymupdf reportlab — и получите свои числа.

import os, time

from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer,
                                Table, TableStyle, PageBreak)

from pypdf import PdfReader
import pdfplumber
import pymupdf

PATH = "otchet.pdf"
FONT = next(p for p in (r"C:\Windows\Fonts\arial.ttf",
                        "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
                        "/Library/Fonts/Arial.ttf") if os.path.exists(p))


def make_pdf(path):
    """Собирает тестовый PDF: 2 страницы, кириллица, таблица 6x4."""
    pdfmetrics.registerFont(TTFont("Body", FONT))
    base = getSampleStyleSheet()
    st = ParagraphStyle("ru", parent=base["Normal"], fontName="Body",
                        fontSize=11, leading=15)
    hd = ParagraphStyle("ruh", parent=base["Heading1"], fontName="Body", fontSize=16)

    doc = SimpleDocTemplate(path, pagesize=A4, title="Отчёт по продажам",
                            author="Зерокодер", subject="Тестовый PDF")
    para = ("Документ собран для проверки того, как библиотеки Python читают "
            "кириллицу, таблицы и многостраничную разметку. Ниже приведена "
            "таблица с числами, которые должны дойти до парсера без потерь.")

    story = [Paragraph("Отчёт по продажам за квартал", hd), Spacer(1, 6 * mm)]
    for _ in range(3):
        story += [Paragraph(para, st), Spacer(1, 4 * mm)]

    rows = [["Товар", "Штук", "Цена, ₽", "Сумма, ₽"],
            ["Клавиатура", "120", "3 400", "408 000"],
            ["Монитор", "45", "18 900", "850 500"],
            ["Веб-камера", "310", "2 250", "697 500"],
            ["Микрофон", "78", "5 100", "397 800"],
            ["Итого", "553", "—", "2 353 800"]]
    table = Table(rows, colWidths=[55 * mm, 25 * mm, 30 * mm, 35 * mm])
    table.setStyle(TableStyle([
        ("FONTNAME", (0, 0), (-1, -1), "Body"),
        ("FONTSIZE", (0, 0), (-1, -1), 10),
        ("GRID", (0, 0), (-1, -1), 0.5, colors.black),
        ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#e6e6e6")),
    ]))
    story += [table, PageBreak(), Paragraph("Приложение", hd)]
    for _ in range(6):
        story += [Paragraph(para, st), Spacer(1, 4 * mm)]
    doc.build(story)


def read_pypdf(p):
    return "\n".join(pg.extract_text() or "" for pg in PdfReader(p).pages)


def read_pdfplumber(p):
    with pdfplumber.open(p) as pdf:
        return "\n".join(pg.extract_text() or "" for pg in pdf.pages)


def read_pymupdf(p):
    doc = pymupdf.open(p)
    out = "\n".join(pg.get_text() for pg in doc)
    doc.close()
    return out


make_pdf(PATH)
print("файл собран:", os.path.getsize(PATH), "байт")

for name, fn in [("pypdf", read_pypdf),
                 ("pdfplumber", read_pdfplumber),
                 ("PyMuPDF", read_pymupdf)]:
    best = None
    for _ in range(5):                 # берём лучший из пяти прогонов
        t0 = time.perf_counter()
        text = fn(PATH)
        dt = time.perf_counter() - t0
        best = dt if best is None else min(best, dt)
    print(f"{name:11} {best*1000:6.1f} мс  символов: {len(text)}")

Вывод на нашей машине — Python 3.14.3, Windows 11:

файл собран: 51730 байт
pypdf          7.9 мс  символов: 1902
pdfplumber    33.7 мс  символов: 1900
PyMuPDF        2.0 мс  символов: 1902

Конкретные миллисекунды от запуска к запуску плавают, и первый запуск в свежей папке всегда медленнее остальных — на нём мы видели 39,7 мс у pdfplumber и 3,5 у PyMuPDF. Устойчив порядок величин: pypdf укладывается примерно в восемь миллисекунд, pdfplumber — в три с лишним десятка, PyMuPDF — в две. Размер собранного файла и число символов не менялись ни в одном прогоне. Отсюда три вывода.

Разрыв по времени между PyMuPDF и pdfplumber в каждом отдельном запуске выходил более чем пятнадцатикратным. Причина в устройстве, а не в качестве кода: pypdf и pdfminer.six, на котором стоит pdfplumber, написаны на чистом Python, PyMuPDF же обёрнут вокруг сишной библиотеки MuPDF.

Абсолютные миллисекунды на двух страницах не значат ничего. Значение появляется на объёме: если пропорция сохранится, лишние 30 мс на файл превращаются в семь с половиной минут на пятнадцати тысячах документов. Пока файлов десятки, берите ту библиотеку, которая точнее отвечает на вашу задачу.

Разница в две единицы (1902 против 1900) — это разметка, не потерянный текст. Если убрать из обоих выводов пробелы и переводы строк, остаётся ровно по 1625 символов, и строки совпадают посимвольно. Расходится только раскладка: pypdf ставит 54 перевода строки, pdfplumber — 34. На обычном текстовом PDF выбор библиотеки на полноту извлечения не влияет; влияет он там, где текст лежит в таблице.

Таблицы: где pypdf рассыпает строку и чем это лечится

Три способа достать табличную строку
Три способа достать табличную строку

В PDF таблицы нет. Есть текст, расставленный по координатам, и линии, нарисованные поверх. Поэтому обычный extract_text() читает страницу по порядку следования объектов и разносит одну строку таблицы по разным строкам вывода. На нашем документе строка «Монитор, 45 штук, 18 900 ₽, 850 500 ₽» после pypdf выглядит так:

'Монитор'

Числа уехали в соседние строки, связь между товаром и суммой потеряна. Первое лечение — режим layout, он появился в pypdf 4.0.0 в январе 2024 года и в русскоязычных руководствах почти не встречается:

from pypdf import PdfReader

page = PdfReader("otchet.pdf").pages[0]
print(page.extract_text(extraction_mode="layout"))

Та же строка на том же файле:

'    Монитор                            45             18 900             850 500'

Режим сохраняет горизонтальные позиции, и строка снова читается целиком — её уже можно разобрать регуляркой или split(). Заодно вывод становится компактнее: 21 строка против 34 в обычном режиме. Официальная документация перечисляет и соседние параметры: layout_mode_space_vertically=False убирает пустые строки, layout_mode_scale_weight регулирует горизонтальные отступы, layout_mode_strip_rotated=False добавляет повёрнутый текст.

Второе лечение — отдать таблицу тому, кто умеет её размечать. pdfplumber возвращает готовый список списков:

import pdfplumber

with pdfplumber.open("otchet.pdf") as pdf:
    tables = pdf.pages[0].extract_tables()

print(len(tables), len(tables[0]), len(tables[0][0]))
print(tables[0][0])
print(tables[0][-1])

Вывод:

1 6 4
['Товар', 'Штук', 'Цена, ₽', 'Сумма, ₽']
['Итого', '553', '—', '2 353 800']

Одна таблица, шесть строк, четыре колонки, шапка и итоговая строка на месте вместе с рублёвым знаком и длинным тире. У PyMuPDF есть свой find_tables(), на этом же файле он нашёл ту же таблицу с той же геометрией — 6 строк, 4 колонки.

Правило выбора простое: если из PDF нужны именно табличные данные, extraction_mode="layout" хватает на аккуратных документах с ровной сеткой, а на вёрстке посложнее берите pdfplumber и разбирайте готовые ячейки. Гонять регулярки по слипшемуся выводу обычного режима — самый долгий из путей.

Скан вместо текста: почему pypdf возвращает пустую строку

Развилка обработки: цифровой PDF или скан
Развилка обработки: цифровой PDF или скан

Самая частая жалоба на любую из библиотек звучит одинаково: «код отработал, ошибок нет, текста ноль». Обычно это значит, что внутри страницы лежит картинка, а текстового слоя нет — так выглядит документ, прошедший через сканер или фотографию.

Мы взяли свой же тестовый PDF, растеризовали каждую страницу в изображение и собрали файл заново. Результат на всех трёх библиотеках:

pypdf       символов: 0
pdfplumber  символов: 0
PyMuPDF     символов: 0

Ни одна не «лучше» в этом сценарии — задача просто другого класса. Документация pypdf говорит об этом прямо: «pypdf is no OCR software; it will not be able to detect those failures. pypdf will also never be able to extract text from images». Там же указан выход: «consider using OCR software such as Tesseract OCR to extract text from images».

Практический приём: не гадать, а проверять до разбора. Скан отличается от цифрового документа по одному признаку — сколько символов приходится на страницу.

from pypdf import PdfReader

def is_scan(path, min_chars_per_page=50):
    reader = PdfReader(path)
    total = sum(len((p.extract_text() or "").strip()) for p in reader.pages)
    return total / max(len(reader.pages), 1) < min_chars_per_page

print(is_scan("otchet.pdf"))       # False, 1899 символов на 2 страницы
print(is_scan("otchet_scan.pdf"))  # True, 0 символов

Такой предфильтр в начале конвейера разводит поток на две ветки: цифровые файлы идут в быстрый разбор, сканы — в очередь на распознавание. Порог в 50 символов на страницу подобран под документы с текстом; для файлов, где на странице честно стоит одна подпись, его придётся опустить.

Про подобные развилки в обработке данных мы отдельно писали в материале о том, как автоматизация снимает барьеры в анализе данных.

Кириллица в pypdf: что дошло без потерь на нашем файле

Кракозябры вместо русского текста — вторая по частоте жалоба. На тестовом документе, собранном со шрифтом Arial, потерь не было: заголовок «Отчёт по продажам за квартал» дошёл целиком, буква «ё» сохранилась, знак «₽» и длинное тире «—» тоже. Это верно и для обычного режима, и для layout.

Важно понимать границу этого наблюдения. Успех означает, что в файле есть корректная карта соответствия символов, и библиотека её прочитала. Документация pypdf отдельно объясняет, почему извлечение текста сложное в принципе — от лигатур вроде U+FB00 до того, что таблица в PDF это просто абсолютно спозиционированный текст. Если конкретный документ отдаёт мусор, дело не в языке, а в том, как в него зашит шрифт: перебирайте библиотеки на этом файле, а не меняйте кодировку на выходе.

Битые и защищённые файлы: два аргумента pypdf, которые спасают конвейер

Спецификация PDF 2.0 занимает 1003 страницы, и документация pypdf честно объясняет следствие: «As a consequence, a lot of PDF files are not strictly following the specification». Отсюда параметр strict у PdfReader и PdfWriter. При strict=True библиотека бросает исключение на любом отступлении от стандарта, при strict=False — пишет предупреждение и старается вытащить, что получится. По умолчанию стоит второе.

Мы испортили в тестовом файле указатель startxref — типовая поломка, когда документ дописывали или обрезали. Читаем теми же функциями, что в блоке замера выше:

pypdf       прочитал, символов: 1902
pdfplumber  прочитал, символов: 1900
PyMuPDF     прочитал, символов: 1902

Это ровно те же числа, что на целом файле. Мы сверили тексты напрямую: извлечённое из битого документа совпало с извлечённым из исправного посимвольно, у всех трёх библиотек. Ни одного потерянного символа. В лог при этом pypdf написал две строки — incorrect startxref pointer(2) и parsing for Object Streams: библиотека увидела сломанный указатель и пошла искать объекты перебором. Цена такого восстановления — время разбора. А со строгим режимом pypdf останавливается:

PdfReader("otchet_broken.pdf", strict=True)
# pypdf.errors.PdfReadError: Broken xref table

Отсюда рабочее правило для пакетной обработки: держите strict=False в проде, но логируйте предупреждения. Файл, который прочитался с руганью, стоит пометить и проверить глазами — «прочитался» и «прочитался правильно» не одно и то же.

Второй случай — документ под паролем. Тут библиотеки ведут себя по-разному, и это стоит знать заранее.

from pypdf import PdfReader, PasswordType

reader = PdfReader("otchet_enc.pdf")
print(reader.is_encrypted)            # True
# reader.pages[0].extract_text() -> FileNotDecryptedError: File has not been decrypted

result = reader.decrypt("secret123")
print(result is PasswordType.OWNER_PASSWORD)   # True
print(len(reader.pages[0].extract_text()))     # 756

Метод decrypt() возвращает не просто «получилось», а какой именно пароль подошёл: USER_PASSWORD или OWNER_PASSWORD. В скриптах это удобно — по владельческому паролю доступны и права на изменение документа. Шифровать pypdf тоже умеет, вплоть до AES-256:

from pypdf import PdfWriter

writer = PdfWriter(clone_from="otchet.pdf")
writer.encrypt("secret123", algorithm="AES-256")
writer.write("otchet_enc.pdf")

pdfplumber на защищённом файле без пароля падает с PdfminerException, а с аргументом password="secret123" открывает его штатно. PyMuPDF отдаёт needs_pass = 1 и ждёт вызова authenticate(). Разница в том, что pypdf сообщает, каким паролем файл открыт, а остальные две просто пускают внутрь.

Метаданные документа через pypdf: одна строка вместо старого метода

Автор, заголовок, дата создания и программа-производитель лежат в отдельном словаре документа. Старый getDocumentInfo() удалён, вместо него свойство metadata:

from pypdf import PdfReader

meta = PdfReader("otchet.pdf").metadata
print(meta.title, "|", meta.author, "|", meta.subject, "|", meta.producer)

На нашем файле:

Отчёт по продажам | Зерокодер | Тестовый PDF | ReportLab PDF Library - (opensource)

Документация предупреждает отдельной строкой: «All the following could be None!» — любое из полей может отсутствовать, и обращение к нему в форматной строке уронит скрипт на первом же документе без автора. Проверяйте на None до вывода.

Поле producer в пакетной обработке полезнее заголовка: по нему видно, чем документ сделан, а значит какого качества внутри разметка. Файлы одного производителя обычно ломаются одинаково, и это готовый признак для группировки в конвейере.

РОССИЙСКИЕ НЕЙРОСЕТИ ДЛЯ ЖИЗНИ И КАРЬЕРЫ В 2025
Присоединяйся к онлайн-вебинару.
В прямом эфире разберем и потестируем лучшие на сегодняшний день отечественные ИИ!
Вы узнаете о том:
  • Выполним базовые задачи на российских нейросетях и посмотрим на результаты!
  • Файл-инструкцию «Как сделать нейро-фотосессию из своего фото бесплатно, без иностранных карт и прочих сложностей»
  • Покажем 10+ способов улучшить свою жизнь с ИИ каждому — от ребенка и пенсионера до управленца и предпринимателя
Участвовать бесплатно
ОБЗОРНЫЙ ПРАКТИКУМ ПО НАШУМЕВШИМ НЕЙРОСЕТЯМ
Нейросети DEEPSEEK И QWEN
За 2 часа сделаем полный обзор новых мощных ИИ-моделей, которые бросают вызов нейросети ChatGPT
Вы узнаете:
  • Возможность получить Доступ в Нейроклуб на целый месяц
  • Как ИИ ускоряет работу и приносит деньги
  • За 2 часа вы получите четкий план, как начать работать с ИИ прямо сейчас!
Участвовать бесплатно

Чек-лист: какую библиотеку брать под вашу задачу

Что нужно сделать Чем делать Ключевой вызов
Достать текст из обычного PDF pypdf page.extract_text()
Сохранить расположение колонок pypdf от 4.0.0 extract_text(extraction_mode="layout")
Разобрать таблицу по ячейкам pdfplumber page.extract_tables()
Обработать тысячи файлов PyMuPDF, если лицензия AGPL подходит page.get_text()
Склеить, разрезать, повернуть страницы pypdf PdfWriter()
Прочитать документ под паролем pypdf reader.decrypt("пароль")
Понять, что перед вами скан pypdf символов на страницу меньше порога
Вытащить текст со скана OCR, библиотеки PDF тут бессильны

Начинайте с pypdf: он ставится одной командой, на Python 3.11 и выше обходится без сторонних пакетов и закрывает большую часть задач. Переходите на соседей тогда, когда упрётесь в конкретную стену — таблицу, объём или лицензию.

Частые вопросы про pypdf

Чем pypdf отличается от PyPDF2?

Это один и тот же проект под новым именем. PyPDF2 остановился на версии 3.0.1 от 31 декабря 2022 года, дальнейшая разработка идёт в пакете pypdf. Ставить нужно pypdf: у PyPDF2 обновлений больше не будет.

Почему pypdf возвращает пустой текст?

Чаще всего внутри страницы лежит картинка без текстового слоя — это скан. Мы проверили такой файл тремя библиотеками, все вернули ноль символов. Помогает только распознавание: документация pypdf прямо отсылает к OCR-программам вроде Tesseract.

Умеет ли pypdf извлекать таблицы?

Отдельного метода для таблиц у pypdf нет. Частично выручает режим extract_text(extraction_mode="layout"), который сохраняет горизонтальные позиции и не разрывает строку таблицы. Если нужны готовые ячейки, берите pdfplumber с его extract_tables().

Что быстрее — pypdf, pdfplumber или PyMuPDF?

На нашем замере на одном файле из двух страниц PyMuPDF отработал за 2 мс, pypdf за 8 мс, pdfplumber за 33 мс. Самая быстрая библиотека обогнала самую медленную более чем в пятнадцать раз, при этом извлечённый текст совпал посимвольно.

Работает ли pypdf с кириллицей?

Да. На тестовом документе со шрифтом Arial заголовок на русском дошёл целиком, буква «ё», знак «₽» и длинное тире сохранились. Мусор вместо текста означает проблему со шрифтом в конкретном файле, а не отсутствие поддержки языка.

Как pypdf открыть PDF с паролем?

Вызовом reader.decrypt("пароль") после создания PdfReader. Метод возвращает, какой пароль подошёл — USER_PASSWORD или OWNER_PASSWORD. Без расшифровки обращение к странице бросает FileNotDecryptedError.

Что делать, если PDF битый?

Читать с параметром по умолчанию strict=False: pypdf запишет предупреждение и попробует поднять файл. Наш документ с испорченным startxref так прочитался всеми тремя библиотеками, причём текст совпал с текстом целого файла посимвольно. С strict=True pypdf на том же документе остановился на PdfReadError: Broken xref table.

Что в итоге

Работа с PDF на Python упирается не в выбор библиотеки, а в тип документа. Цифровой файл прочитает любая из трёх, и разница будет в миллисекундах и раскладке пробелов. Таблица потребует pdfplumber или режима layout. Скан не возьмёт ни одна — там начинается зона OCR. Первым делом определяйте, что у вас за файл, и только потом выбирайте инструмент. И проверьте импорты: если в коде остался PdfFileReader, он уже не запустится.

Большой практикум
ЗАМЕНИ ВСЕ НЕЙРОСЕТИ НА ОДНУ — PERPLEXITY
ПОКАЖЕМ НА КОНКРЕТНЫХ КЕЙСАХ
  • Освой нейросеть Perplexity и узнай, как пользоваться функционалом остальных ИИ в одном
  • УЧАСТВОВАТЬ ЗА 0 РУБ.
  • Расскажем, как получить подписку
Участвовать бесплатно
ОНЛАЙН-ПРАКТИКУМ
ЗАПУСК нейросети DEEPSEEK R1 ЛОКАЛЬНО НА СВОЕМ КОМПЬЮТЕРЕ
ЧТО БУДЕТ НА ОБУЧЕНИИ?
  • ПОКАЖЕМ, КАК РАЗВЕРНУТЬ МОДЕЛЬ нейросеть DEEPSEEK R1 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ
Участвовать бесплатно