Профили извлечения — настройка распознавания пробелов под тип документа
Разные 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().
Связанные страницы
- Извлечение текста — полная API извлечения
- Порядок чтения (XY-cut) — порядок чтения с учётом колонок
- OCR для сканированных PDF — когда одного профиля мало
- Справочник Python API