Skip to content

Профили извлечения — настройка распознавания пробелов под тип документа

Разные PDF прячут пробелы по-разному. Статья с arXiv набрана плотными колонками по ширине. Форма IRS держится на жёсткой сетке ячеек. Документ GDPR — это плотный юридический текст по ширине с минимальным кернингом. Один tj_offset_threshold, подобранный под первый случай, в другом вставит мусорные пробелы.

ExtractionProfile предоставляет девять предварительно настроенных наборов параметров, которые точно соответствуют реальным классам документов. Передайте профиль в extract_text() или extract_words(), и PDF Oxide применит подходящее соотношение word-margin, порог TJ-offset и переключатель адаптивного порога для данного стиля документа.

Поддержка в биндингах. Профили извлечения сейчас доступны в Python (pdf_oxide.ExtractionProfile) и Rust (pdf_oxide::config::ExtractionProfile). Биндинги Node, WASM, Go и C# внутри используют значение по умолчанию CONSERVATIVE; чтобы применить другой профиль из этих сред выполнения, вызовите CLI на Rust (pdf-oxide extract --profile academic doc.pdf) или оберните вызов через шаг на Python / Rust.

Быстрый пример

Python

from pdf_oxide import PdfDocument, ExtractionProfile

doc = PdfDocument("paper.pdf")

# Научные статьи: плотный набор, распознавание ссылок включено
text = doc.extract_text(0, profile=ExtractionProfile.academic())
print(text)

Rust

use pdf_oxide::PdfDocument;
use pdf_oxide::config::ExtractionProfile;

let mut doc = PdfDocument::open("paper.pdf")?;
let text = doc.extract_text_with_profile(0, ExtractionProfile::ACADEMIC)?;
println!("{}", text);

Доступные профили

Профиль Подходит для Порог TJ Word-margin ratio Адаптивный
conservative() По умолчанию — обычный текст, минимум ложных пробелов −120 0,10 выкл.
aggressive() PDF со слитными словами; разделяет слипшиеся слова −80 0,20 выкл.
balanced() Смешанный контент −100 0,15 выкл.
academic() Статьи arXiv, материалы конференций, технические отчёты −105 0,12 вкл. + распознавание ссылок / e-mail
policy() Юридические документы, GDPR, государственные регламенты −110 0,18 вкл.
form() Формы IRS, заявления, анкеты −120 0,08 выкл.
government() Государственные отчёты с таблицами −105 0,14 выкл.
scanned_ocr() Результат OCR с шумными координатами зависит зависит вкл.
adaptive() Экстрактор сам подбирает параметры по статистике шрифтов зависит зависит вкл.

Когда нужен каждый профиль

Научные статьи и материалы конференций — academic()

Плотный набор, двухколоночная вёрстка, встроенные ссылки. При настройках по умолчанию между лигатурами (fi, ff) часто появляются лишние пробелы, а при плотном кернинге — наоборот, пробелы теряются.

doc = PdfDocument("neurips-paper.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.academic())

Академический профиль включает адаптивный порог и распознавание ссылок / e-mail, благодаря чему строчные ссылки вида [1,2,3] и адреса вроде author@lab.edu сохраняются в чистом виде.

Формы IRS, заявления — form()

В формах важнее сохранить выравнивание колонок, чем границы слов. Профиль form() задаёт очень узкое соотношение word-margin (0,08), чтобы жёстко выровненные подписи полей не сливались со значениями.

doc = PdfDocument("w2.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.form())

GDPR / регламенты / юридические документы — policy()

В текстах по ширине вставляются пробелы переменной ширины, из-за чего порог по умолчанию ломается. policy() использует более широкое значение word-margin (0,18) и адаптивный порог, чтобы правильно разобрать плотный юридический текст.

doc = PdfDocument("gdpr.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.policy())

Результат OCR (сканы) — scanned_ocr()

После OCR (Tesseract, PaddleOCR, Azure) координаты символов зашумлены, а подсказок кернинга не остаётся. scanned_ocr() компенсирует это адаптивным порогом, пересчитывающим статистику шрифтов на каждой странице.

doc = PdfDocument("scanned.pdf")
text = doc.extract_text(0, profile=ExtractionProfile.scanned_ocr())

Доверить выбор библиотеке — adaptive()

Если заранее неизвестно, какого класса документ, adaptive() при первом проходе снимает статистику шрифтов и подбирает пороги перед извлечением. Чуть медленнее фиксированного профиля, зато устойчив к смешанным корпусам.

for pdf_path in Path("mixed_corpus/").glob("*.pdf"):
    doc = PdfDocument(str(pdf_path))
    text = doc.extract_text(0, profile=ExtractionProfile.adaptive())

Поля профиля

Каждый профиль раскрывает свои настроечные параметры — их можно прочитать или клонировать:

Python

from pdf_oxide import ExtractionProfile

p = ExtractionProfile.academic()
print(p.name)                # "Academic"
print(p.word_margin_ratio)   # 0.12
print(p.tj_offset_threshold) # -105.0

# Перебрать все пресеты
for profile in ExtractionProfile.all_profiles():
    print(profile.name, profile.word_margin_ratio)

Rust

use pdf_oxide::config::ExtractionProfile;

let p = ExtractionProfile::ACADEMIC;
println!("{} margin={} tj={}",
    p.name, p.word_margin_ratio, p.tj_offset_threshold);

Выбор профиля в продакшн-пайплайнах

Если в пайплайн поступает смешанный корпус — научные статьи вперемешку с формами IRS и выгруженными из веба HTML — по умолчанию применяйте adaptive(). Он добавляет несколько процентов накладных расходов на страницу, зато устраняет самые неприятные ошибки (слипание слов, пропажа пробелов между колонками).

Если корпус однороден — конвейер приёма заявок по Title IX, инструмент проверки договоров, краулер arXiv — указывайте подходящий профиль явно: так вы получите максимальное качество извлечения и избежите затрат на постраничную выборку в adaptive().

Связанные страницы