pdfplumber vs PyMuPDF — скорость, таблицы и лицензирование
pdfplumber и PyMuPDF — популярные Python-библиотеки для PDF, но обе вынуждают идти на компромиссы. pdfplumber хорош для таблиц, но в 29 раз медленнее, чем нужно. PyMuPDF быстр, но ограничен лицензией AGPL-3.0, блокирующей коммерческое использование. Эта страница сравнивает обе библиотеки и показывает, почему PDF Oxide — лучший выбор для большинства сценариев.
Коротко: PDF Oxide в 29 раз быстрее pdfplumber, в 5.8 раз быстрее PyMuPDF, распространяется под MIT-лицензией и обрабатывает текст, изображения, формы, шифрование, вывод в Markdown и OCR — всё в одной библиотеке. Единственная область, где pdfplumber по-прежнему лидирует, — сложное извлечение таблиц с визуальной отладкой.
Краткое сравнение
| pdfplumber | PyMuPDF | PDF Oxide | |
|---|---|---|---|
| Лицензия | MIT | AGPL-3.0 | MIT |
| Язык | Чистый Python | C (MuPDF) | Rust + PyO3 |
| Среднее время извлечения | 23.2 мс | 4.6 мс | 0.8 мс |
| Время извлечения p99 | 189 мс | 28 мс | 9 мс |
| Успешность (3,830 PDF) | 98.8% | 99.3% | 100% |
| Извлечение текста | Да | Да | Да |
| Позиции символов | Да | Да | Да |
| Извлечение таблиц | Продвинутое | Базовое | Базовое |
| Извлечение изображений | Нет | Да | Да |
| Визуальная отладка | Да | Нет | Нет |
| Создание PDF | Нет | Да | Да |
| Редактирование PDF | Нет | Да | Да |
| Вывод в Markdown | Нет | Нет | Да |
| Вывод в HTML | Нет | Нет | Да |
| Поля форм | Только чтение | Чтение + запись | Чтение + запись |
| Шифрование | Нет | Чтение + запись | Чтение + запись |
| Рендеринг | Нет | Да | Да |
| OCR | Нет | Tesseract | Встроенный (PaddleOCR) |
| Размер при установке | ~1 МБ | ~20 МБ | ~5 МБ |
| Версии Python | 3.8+ | 3.8–3.12 | 3.8–3.14 |
Бенчмарки скорости
Все три библиотеки протестированы на одном корпусе из 3 830 PDF из трёх независимых публичных наборов тестов (veraPDF, Mozilla pdf.js, DARPA SafeDocs). Корпус охватывает все версии спецификации PDF (1.0–2.0), зашифрованные файлы, повреждённые документы, кодировки CJK и сложные макеты.
| Метрика | pdfplumber | PyMuPDF | PDF Oxide |
|---|---|---|---|
| Среднее время извлечения | 23.2 мс | 4.6 мс | 0.8 мс |
| Время извлечения p99 | 189 мс | 28 мс | 9 мс |
| Относительно PDF Oxide | в 29 раз медленнее | в 5.8 раз медленнее | 1x |
| Успешность (валидные PDF) | 98.8% (3,777/3,823) | 99.3% (3,796/3,823) | 100% (3,823/3,823) |
PyMuPDF примерно в 5 раз быстрее pdfplumber, потому что делегирует весь парсинг C-библиотеке MuPDF. pdfplumber использует pdfminer для парсинга и добавляет собственный слой пространственного анализа — оба написаны на чистом Python. PDF Oxide обрабатывает весь парсинг, декодирование шрифтов и сборку текста в скомпилированном Rust, выполняющемся непосредственно в процессе Python через PyO3, что обеспечивает преимущество в 5.8 раза над PyMuPDF и в 29 раз над pdfplumber.
Что означают числа на практике
| Нагрузка | pdfplumber | PyMuPDF | PDF Oxide |
|---|---|---|---|
| 100 PDF | 2.3 секунды | 0.46 секунды | 0.08 секунды |
| 1,000 PDF | 23 секунды | 4.6 секунды | 0.8 секунды |
| 10,000 PDF | 3.9 минуты | 46 секунд | 8 секунд |
| 100,000 PDF | 39 минут | 7.7 минут | 80 секунд |
Для одноразовых скриптов, обрабатывающих несколько файлов, разница в скорости несущественна. Для production-пайплайнов, обрабатывающих тысячи документов ежедневно, разрыв между 39 минутами и 80 секундами меняет архитектурные решения.
Извлечение таблиц
Извлечение таблиц — основная причина, по которой разработчики выбирают pdfplumber вместо PyMuPDF. Именно здесь pdfplumber действительно превосходит остальных.
pdfplumber: структурированный парсинг таблиц
pdfplumber предоставляет специализированное извлечение таблиц с настраиваемым определением линий, объединением ячеек и визуальной отладкой:
import pdfplumber
with pdfplumber.open("invoice.pdf") as pdf:
page = pdf.pages[0]
# Извлечение всех таблиц как структурированных данных
tables = page.extract_tables()
for table in tables:
for row in table:
print(row)
# Тонкая настройка определения с пользовательскими параметрами
tables = page.extract_tables({
"vertical_strategy": "text",
"horizontal_strategy": "lines",
"snap_tolerance": 5,
})
# Визуальная отладка: рендеринг страницы с обнаруженными границами таблиц
im = page.to_image()
im.debug_tablefinder()
im.save("debug.png")
pdfplumber возвращает структурированные данные строк/столбцов и обрабатывает объединённые ячейки, перекрывающие заголовки и безрамочные таблицы. Оверлей визуальной отладки незаменим для настройки параметров извлечения на сложных макетах.
PyMuPDF: базовое определение таблиц
PyMuPDF добавил определение таблиц в последних версиях, но оно менее зрелое, чем алгоритмы pdfplumber:
import fitz
doc = fitz.open("invoice.pdf")
page = doc[0]
# Встроенный поиск таблиц в PyMuPDF (добавлен в v1.23)
tabs = page.find_tables()
for table in tabs:
df = table.to_pandas() # требуется pandas
print(df)
Извлечение таблиц в PyMuPDF работает для простых сеточных таблиц с видимыми границами. Он плохо справляется с безрамочными макетами, многоуровневыми заголовками и ячейками, перекрывающими несколько строк или столбцов — именно с теми случаями, где pdfplumber наиболее силён.
PDF Oxide: вывод таблиц в Markdown
PDF Oxide конвертирует таблицы в синтаксис Markdown в рамках пайплайна структурированного вывода:
from pdf_oxide import PdfDocument
doc = PdfDocument("invoice.pdf")
# Таблицы определяются и конвертируются в формат Markdown-таблиц
md = doc.to_markdown(0, detect_headings=True)
print(md)
# Также доступно как HTML с тегами таблиц
html = doc.to_html(0)
print(html)
Определение таблиц в PDF Oxide работает для стандартных сеточных макетов и выдаёт чистый Markdown или HTML. Для сложных таблиц с объединёнными ячейками, безрамочных макетов или перекрывающих заголовков специализированные алгоритмы pdfplumber по-прежнему надёжнее.
Итог по извлечению таблиц
| Возможность | pdfplumber | PyMuPDF | PDF Oxide |
|---|---|---|---|
| Простые таблицы с рамками | Да | Да | Да |
| Безрамочные таблицы | Да | Ограниченно | Ограниченно |
| Объединённые ячейки | Да | Ограниченно | Ограниченно |
| Многоуровневые заголовки | Да | Нет | Нет |
| Настраиваемое определение | Да | Ограниченно | Нет |
| Визуальная отладка | Да | Нет | Нет |
| Формат вывода | Списки Python | DataFrames pandas | Markdown / HTML |
| Скорость | Медленная (чистый Python) | Быстрая | Самая быстрая |
Если извлечение сложных таблиц — ваша единственная задача, pdfplumber — лучший инструмент. Если нужны таблицы вместе с быстрым извлечением текста, изображений или созданием PDF, PDF Oxide покрывает больше задач.
Извлечение текста
Для извлечения простого текста все три библиотеки справляются, но различаются скоростью и дизайном API.
pdfplumber
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[0]
text = page.extract_text()
print(text)
PyMuPDF
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
text = page.get_text()
print(text)
PDF Oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
print(text)
Все три дают сопоставимый текстовый вывод для корректных PDF. PDF Oxide достигает 99.5% совпадения текста с PyMuPDF на полном корпусе; оставшиеся 0.5% — различия в нормализации пробелов и обработке лигатур.
Позиционирование на уровне символов
И pdfplumber, и PyMuPDF предоставляют данные о позициях символов, что важно для пространственного анализа, определения bounding box и восстановления макета.
pdfplumber
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[0]
for char in page.chars[:10]:
print(f"'{char['text']}' at ({char['x0']:.1f}, {char['top']:.1f}) "
f"size={char['size']:.1f}")
PyMuPDF
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
blocks = page.get_text("dict")["blocks"]
for block in blocks:
if "lines" in block:
for line in block["lines"]:
for span in line["spans"]:
print(f"'{span['text']}' size={span['size']:.1f}")
PDF Oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
chars = doc.extract_chars(0)
for ch in chars[:10]:
print(f"'{ch.char}' at ({ch.x:.1f}, {ch.y:.1f}) size={ch.font_size:.1f}")
pdfplumber возвращает словари для каждого символа с подробными метаданными. PyMuPDF возвращает вложенные структуры блоков/строк/спанов. PDF Oxide возвращает плоские объекты символов с позицией и данными о шрифте.
Лицензирование
Это наиболее значимое отличие между pdfplumber и PyMuPDF для коммерческих проектов.
| pdfplumber | PyMuPDF | PDF Oxide | |
|---|---|---|---|
| Лицензия | MIT | AGPL-3.0 | MIT |
| Коммерческий продукт | Да | Требуется коммерческая лицензия | Да |
| Закрытый SaaS | Да | Требуется коммерческая лицензия | Да |
| Распространение Docker | Да | Требуется коммерческая лицензия | Да |
| Внутренние инструменты | Да | Да | Да |
| Open-source проект | Да | Да (если совместим с AGPL) | Да |
Проблема AGPL у PyMuPDF
PyMuPDF оборачивает MuPDF, распространяемый под AGPL-3.0. Если вы распространяете ПО, включающее PyMuPDF — в том числе SaaS, веб-приложения и Docker-контейнеры — ваш код должен быть открыт под AGPL, либо вам нужно приобрести коммерческую лицензию у Artifex.
Artifex не публикует стоимость коммерческой лицензии. Нужно обращаться в отдел продаж. Лицензии обычно привязаны к приложению, продлеваются ежегодно, без бесплатного уровня или исключений для стартапов.
pdfplumber и PDF Oxide — оба под MIT
И pdfplumber, и PDF Oxide распространяются под лицензией MIT. Используйте любой из них в любом проекте — коммерческом, проприетарном, SaaS или open source — без обязательств. Если лицензирование — ваша основная забота и вы выбираете между pdfplumber и PyMuPDF, pdfplumber (или PDF Oxide) — более безопасный выбор.
Зашифрованные PDF
Обработка шифрования — существенный пробел в функциональности pdfplumber и частая проблема для разработчиков, работающих с защищёнными документами.
pdfplumber: нет поддержки шифрования
pdfplumber вообще не может открывать зашифрованные или защищённые паролем PDF. Передача зашифрованного PDF в pdfplumber приводит к ошибке. Файл нужно расшифровать заранее другим инструментом:
import pdfplumber
# На зашифрованных PDF вызовет ошибку:
with pdfplumber.open("encrypted.pdf") as pdf:
# raises pdfminer.pdfparser.PDFSyntaxError или аналогичную
pass
Типичный обходной путь — использовать PyMuPDF или pypdf для расшифровки файла, а затем передать его в pdfplumber для извлечения таблиц — добавляя ещё одну зависимость в пайплайн.
PyMuPDF: полная поддержка шифрования
import fitz
doc = fitz.open("encrypted.pdf")
doc.authenticate("password")
page = doc[0]
text = page.get_text()
PyMuPDF поддерживает пользовательские и владельческие пароли, шифрование AES-128 и AES-256, а также создание зашифрованных PDF.
PDF Oxide: полная поддержка шифрования
from pdf_oxide import PdfDocument
doc = PdfDocument("encrypted.pdf", password="password")
text = doc.extract_text(0)
PDF Oxide обрабатывает все стандартные методы шифрования PDF (RC4, AES-128, AES-256) как для чтения, так и для записи. Никаких дополнительных зависимостей или предварительной обработки не требуется.
Извлечение изображений
Ещё один пробел в функциональности pdfplumber. pdfplumber не извлекает встроенные изображения из PDF.
PyMuPDF
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
for i, img in enumerate(page.get_images()):
xref = img[0]
base_image = doc.extract_image(xref)
with open(f"image_{i}.{base_image['ext']}", "wb") as f:
f.write(base_image["image"])
PDF Oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
images = doc.extract_image_bytes(0)
for i, img in enumerate(images):
with open(f"image_{i}.{img['format']}", "wb") as f:
f.write(img["data"])
Если ваш пайплайн требует извлечения и текста, и изображений из PDF, pdfplumber не справится с частью изображений. Для этого нужен PyMuPDF, PDF Oxide или pypdfium2.
Вывод Markdown и HTML
Ни pdfplumber, ни PyMuPDF не предоставляют встроенной конвертации в Markdown или HTML. Это уникальная возможность PDF Oxide.
from pdf_oxide import PdfDocument
doc = PdfDocument("paper.pdf")
# Markdown с обнаружением заголовков и форматированием таблиц
md = doc.to_markdown(0, detect_headings=True)
print(md)
# HTML с семантическими тегами
html = doc.to_html(0)
print(html)
Для LLM-пайплайнов, RAG-систем и рабочих процессов конвертации документов структурированный Markdown-вывод устраняет необходимость в дополнительном этапе конвертации. Пользователи PyMuPDF обычно используют отдельный пакет pymupdf4llm, который в 69 раз медленнее встроенной конвертации PDF Oxide.
Когда выбирать какую библиотеку
Выберите pdfplumber, если:
- Сложное извлечение таблиц — ваша основная задача. Алгоритмы таблиц pdfplumber обрабатывают объединённые ячейки, безрамочные таблицы и перекрывающие заголовки лучше любой другой Python-библиотеки.
- Нужна визуальная отладка. pdfplumber может рендерить аннотированные изображения страниц с обнаруженными линиями, символами и границами таблиц — незаменимо для настройки извлечения на сложных документах.
- Предпочитаете чистый Python. Никаких компилируемых зависимостей, устанавливается везде, где работает Python.
- Скорость не критична. Если обрабатываете менее сотни файлов за раз, 23 мс в среднем вполне приемлемы.
Выберите PyMuPDF, если:
- У вас уже есть коммерческая лицензия MuPDF и вы зависите от рендеринга MuPDF или экспорта SVG.
- Нужен высококачественный рендеринг. Движок рендеринга MuPDF зрелый и хорошо справляется со сложными PDF.
- Ваш проект совместим с AGPL. Если вы создаёте open-source ПО под AGPL или совместимой лицензией, лицензирование PyMuPDF не проблема.
- Нужен OCR через Tesseract. PyMuPDF имеет встроенную интеграцию с Tesseract для отсканированных документов.
Выберите PDF Oxide, если:
- Нужна скорость и широкий охват функциональности. 0.8 мс среднее извлечение — в 5.8 раз быстрее PyMuPDF, в 29 раз быстрее pdfplumber — с текстом, изображениями, формами, созданием и шифрованием в одной библиотеке.
- Нужна MIT-лицензия без потери скорости. pdfplumber — MIT, но медленный. PyMuPDF быстр, но AGPL. PDF Oxide — и MIT, и быстрый.
- Нужен вывод в Markdown или HTML. Встроенная структурированная конвертация для LLM-пайплайнов и RAG-систем.
- Нужна поддержка зашифрованных PDF с разрешительной лицензией. pdfplumber не умеет работать с шифрованием. PyMuPDF умеет, но требует соблюдения AGPL. PDF Oxide обрабатывает шифрование под MIT.
- Нужна одна библиотека для извлечения, создания и редактирования. И pdfplumber, и PyMuPDF требуют дополнительных инструментов для части рабочего процесса. PDF Oxide покрывает извлечение, создание, редактирование, рендеринг и валидацию.
Используйте PDF Oxide + pdfplumber вместе:
Для пайплайнов, требующих быстрого извлечения текста, изображений и сложного парсинга таблиц, используйте PDF Oxide для общего пайплайна и pdfplumber для таблиц:
from pdf_oxide import PdfDocument
import pdfplumber
# Быстрое извлечение текста и изображений с PDF Oxide
doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
images = doc.extract_image_bytes(0)
# Сложное извлечение таблиц с pdfplumber
with pdfplumber.open("report.pdf") as pdf:
tables = pdf.pages[0].extract_tables()
Установка
# pdfplumber
pip install pdfplumber
# PyMuPDF
pip install pymupdf
# PDF Oxide
pip install pdf_oxide
Все три устанавливаются через pip. pdfplumber и PDF Oxide распространяются под MIT. PyMuPDF — под AGPL-3.0 — проверьте последствия лицензирования перед добавлением в коммерческий проект.
Вердикт
pdfplumber и PyMuPDF решают часть задач. PDF Oxide решает их все.
| Что для вас важно | Лучший выбор |
|---|---|
| Максимальная скорость | PDF Oxide (0.8 мс — в 29 раз быстрее pdfplumber) |
| Сложное извлечение таблиц | pdfplumber (визуальная отладка, объединённые ячейки) |
| Разрешительная лицензия + скорость | PDF Oxide — pdfplumber MIT, но медленный; PyMuPDF быстр, но AGPL |
| Зашифрованные PDF | PDF Oxide или PyMuPDF — pdfplumber не умеет расшифровывать |
| Извлечение изображений | PDF Oxide или PyMuPDF — pdfplumber не поддерживает |
| Вывод в Markdown/HTML | PDF Oxide — единственная библиотека со встроенной конвертацией |
| OCR без Tesseract | PDF Oxide — встроенный PaddleOCR |
| Одна библиотека для всего | PDF Oxide — извлечение, создание, редактирование, шифрование, OCR |
Если ваш рабочий процесс не сводится целиком к сложному извлечению таблиц (безрамочные таблицы, объединённые ячейки, визуальная отладка), PDF Oxide заменяет и pdfplumber, и PyMuPDF — быстрее, больше возможностей, MIT-лицензия.
Начните за 10 секунд:
pip install pdf_oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
text = doc.extract_text(0) # в 29 раз быстрее pdfplumber
md = doc.to_markdown(0) # встроенное, без отдельного пакета
images = doc.extract_image_bytes(0) # pdfplumber так не умеет
Связанные страницы
- PDF Oxide vs PyMuPDF — детальное сравнение с руководством по миграции
- PDF Oxide vs pdfplumber — детальное сравнение с примерами кода
- Сравнение с Python-библиотеками — все Python-библиотеки в сравнении
- Benchmark производительности — полная методология benchmark
- Извлечение таблиц из PDF — руководство по извлечению таблиц
- Начало работы с Python — установка и первое извлечение