Skip to content

PDF-библиотека для Python: PDF Oxide за десять строк

PDF Oxide — самая быстрая PDF-библиотека для Python. Извлечение текста занимает в среднем 0,8 мс на страницу — это в 5 раз быстрее PyMuPDF, при 100 % успешной обработке 3 830 тестовых PDF. Одна библиотека закрывает извлечение, создание и редактирование. Лицензия MIT, ядро на Rust, без системных зависимостей.

Установка

pip install pdf_oxide

Требования: Python 3.8 и новее. Готовые wheel-пакеты для Linux, macOS и Windows на x86_64 и ARM64. Компилятор и системные пакеты не нужны.

Открыть PDF

Используйте PdfDocument, чтобы открыть любой PDF-файл и посмотреть его свойства.

from pdf_oxide import PdfDocument

doc = PdfDocument("research-paper.pdf")
print(f"Pages: {doc.page_count()}")
print(f"PDF version: {doc.version()}")

API страниц

С версии v0.3.34 PdfDocument поддерживает итерацию и индексирование и возвращает объекты PdfPage с ленивыми свойствами.

from pdf_oxide import PdfDocument

with PdfDocument("paper.pdf") as doc:
    for page in doc:            # len(doc), doc[i], doc[-1] работают
        text = page.text        # ленивое — вычисляется при обращении
        md = page.markdown(detect_headings=True)
        for table in page.tables:
            for row in table["rows"]:
                print([cell["text"] for cell in row["cells"]])

Свойства страницы (все ленивые): text, chars, words, lines, spans, tables, images, paths, annotations, width, height, bbox. Методы: markdown(), plain_text(), html(), render(), search(), region(x, y, w, h).

В v0.3.34 класс страницы редактора переименован в EditorPage, чтобы избежать коллизии с PdfPage.

Извлечение текста

Одна страница

Извлеките простой текст страницы по её индексу (отсчёт от нуля).

from pdf_oxide import PdfDocument

doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
print(text)

Все страницы

from pdf_oxide import PdfDocument

doc = PdfDocument("book.pdf")
for i in range(doc.page_count()):
    text = doc.extract_text(i)
    print(f"--- Page {i + 1} ---")
    print(text)

Посимвольное извлечение

extract_chars() возвращает список TextChar с точной позицией и метаданными шрифта для каждого символа страницы.

from pdf_oxide import PdfDocument

doc = PdfDocument("paper.pdf")
chars = doc.extract_chars(0)

for ch in chars[:10]:
    print(f"'{ch.char}' at ({ch.x:.1f}, {ch.y:.1f}) "
          f"size={ch.font_size:.1f} font={ch.font_name} "
          f"bbox={ch.bbox}")

Каждый TextChar содержит следующие поля:

Поле Тип Описание
char str Символ Юникода
x float Горизонтальная координата в пунктах
y float Вертикальная координата в пунктах
font_size float Размер шрифта в пунктах
font_name str Имя шрифта в PostScript
bbox tuple[float, 4] Ограничивающий прямоугольник (x0, y0, x1, y1)

Текстовые спаны

extract_spans() объединяет подряд идущие символы с одинаковым шрифтом и размером в спаны, возвращая структурированный текст с метаданными шрифта.

from pdf_oxide import PdfDocument

doc = PdfDocument("paper.pdf")
spans = doc.extract_spans(0)

for span in spans:
    print(f"'{span.text}' font={span.font_name} size={span.font_size}")

Конвертация в Markdown

Преобразуйте страницу PDF в Markdown с опциональным распознаванием заголовков.

from pdf_oxide import PdfDocument

doc = PdfDocument("paper.pdf")
md = doc.to_markdown(0, detect_headings=True)
print(md)

Конвертация в HTML

Преобразуйте страницу PDF в HTML.

from pdf_oxide import PdfDocument

doc = PdfDocument("paper.pdf")
html = doc.to_html(0)
print(html)

Извлечение изображений

extract_images() возвращает список ImageInfo для каждого изображения на странице, включая картинки из потоков содержимого и вложенных Form XObject.

from pdf_oxide import PdfDocument

doc = PdfDocument("brochure.pdf")
images = doc.extract_image_bytes(0)

for i, img in enumerate(images):
    print(f"Image {i}: {img['width']}x{img['height']} "
          f"({len(img['data'])} bytes)")
    with open(f"image_{i}.{img['format']}", "wb") as f:
        f.write(img["data"])

В каждом словаре из extract_image_bytes() есть следующие ключи:

Ключ Тип Описание
width int Ширина изображения в пикселях
height int Высота изображения в пикселях
data bytes Сырые байты изображения
format str Формат (например, png, jpeg)

Открытие из байтов

Откройте PDF из байтов в памяти — удобно при загрузке из S3, HTTP или базы данных:

from pdf_oxide import PdfDocument

doc = PdfDocument.from_bytes(pdf_bytes)
text = doc.extract_text(0)

# Пароль тоже поддерживается:
doc = PdfDocument.from_bytes(pdf_bytes, password="secret")

Для API-билдера:

from pdf_oxide import Pdf

pdf = Pdf.from_bytes(existing_pdf_bytes)
pdf.save("modified.pdf")

PDF с паролем

Передайте password= в конструктор, чтобы открыть зашифрованный документ.

from pdf_oxide import PdfDocument

doc = PdfDocument("confidential.pdf", password="secret")
text = doc.extract_text(0)
print(text)

Также можно вызвать doc.authenticate(password) уже после открытия.

Создание PDF

Класс Pdf предоставляет фабричные методы для создания PDF из разных исходных форматов.

Из Markdown

from pdf_oxide import Pdf

pdf = Pdf.from_markdown("# Hello World\n\nThis is a PDF.")
pdf.save("output.pdf")

Из HTML

from pdf_oxide import Pdf

pdf = Pdf.from_html("<h1>Invoice</h1><p>Amount due: $42.00</p>")
pdf.save("invoice.pdf")

Из простого текста

from pdf_oxide import Pdf

pdf = Pdf.from_text("Plain text document.\n\nSecond paragraph.")
pdf.save("notes.pdf")

Из изображений

from pdf_oxide import Pdf

pdf = Pdf.from_image("scan.jpg")
pdf.save("scan.pdf")

Поиск

Ищите текст по всему документу или в одной странице.

from pdf_oxide import PdfDocument

doc = PdfDocument("manual.pdf")

# Поиск по всем страницам
results = doc.search("configuration")
for r in results:
    print(f"Page {r.page}: '{r.text}' at ({r.x:.0f}, {r.y:.0f})")

# Поиск по одной странице
page_results = doc.search_page(0, "configuration")

Обработка ошибок

PDF Oxide выбрасывает PdfError при ошибках, характерных для PDF, и стандартные исключения Python — при проблемах ввода-вывода.

from pdf_oxide import PdfDocument, PdfError

try:
    doc = PdfDocument("document.pdf")
    text = doc.extract_text(0)
except PdfError as e:
    print(f"PDF error: {e}")
except FileNotFoundError:
    print("File not found")

Что дальше