pdfminer.six извлекает из PDF текст, координаты символов и блоков, сведения о шрифтах и цветах, встроенные изображения, закладки и значения полей AcroForm. Для разовой обработки доступны команды pdf2txt.py и dumppdf.py, а для автоматизации — функции extract_text, extract_pages и модульные классы парсера, интерпретатора и конвертеров.
Основной рабочий экран — терминал или консоль среды разработки: пользователь указывает входной PDF, страницы, пароль, формат результата и параметры анализа макета, после чего получает текст в стандартном выводе либо файл TXT, HTML, XML или tag. В Python тот же процесс строится как короткий вызов высокого уровня или как управляемая цепочка объектов, когда нужно контролировать каждую страницу и каждый элемент.
Практичный порядок работы начинается с простого извлечения текста, затем проверяется порядок колонок, пробелы и переносы, после чего корректируются char_margin, word_margin, line_margin, boxes_flow и detect_vertical. Если обычной строки недостаточно, extract_pages возвращает иерархию LTPage, LTTextBox, LTTextLine, LTChar, LTFigure и LTImage, из которой можно собрать собственный JSON, индекс поиска, отчёт о шрифтах или координатную разметку.
Скачать pdfminer.six
- Редактирование PDF
- Русский интерфейс
- Просто новичкам
- Нет графического окна
- Не распознаёт сканы
- Нужны навыки Python
Рабочая среда и проверка команд
После установки полезно проверить сразу два уровня доступа. Команда pdf2txt.py --version подтверждает, что исполняемый сценарий найден в PATH, а импорт pdfminer показывает, что пакет доступен выбранному интерпретатору Python. Эти проверки выявляют типичную ситуацию, когда пакет установлен в одном виртуальном окружении, а команда запускается из другого. Если версии интерпретатора в приглашении терминала и в среде проекта различаются, сначала активируют нужное окружение, затем повторяют обе проверки.
Справка pdf2txt.py --help одновременно служит картой интерфейса. В ней параметры разделены по смыслу: выбор страниц и пароль относятся к разбору документа, параметры LAParams управляют восстановлением макета, а блок вывода задаёт файл, кодировку, формат и каталог изображений. Такой интерфейс удобен для воспроизводимых операций: команда сохраняется в журнале сборки, shell-скрипте или конфигурации задания и повторяется на другой машине без ручного щёлканья по диалогам.

Изоляция зависимостей
Для проекта с несколькими библиотеками обработки PDF лучше использовать отдельное виртуальное окружение. Это предотвращает конфликт пакета pdfminer.six с одноимённым модулем pdfminer из другой поставки: импорт в обоих случаях выглядит одинаково, но набор классов и поведение могут различаться. При подозрении на конфликт проверяют pdfminer.__file__, удаляют лишнюю поставку и устанавливают только требуемый пакет в активное окружение.
Базовая установка рассчитана на извлечение текста и разбор структуры. Дополнительный набор зависимостей pdfminer.six[image] нужен, когда требуется сохранять некоторые встроенные изображения в удобных форматах. Наличие extras не превращает анализатор в средство OCR: зависимость помогает декодировать графические потоки, но текст внутри фотографии или скана по-прежнему не распознаётся.
Первое извлечение текста
Минимальная команда принимает путь к одному или нескольким PDF и печатает результат в стандартный вывод. Для короткого документа этого достаточно, но в реальной работе вывод обычно перенаправляют в файл или задают --outfile. Между страницами появляется символ перевода страницы, а между текстовыми блоками — переносы, рассчитанные анализатором макета. Это не копирование визуальной страницы пиксель в пиксель, а реконструкция последовательности строк по объектам PDF.
На документе с двумя колонками программа сначала читает текстовые операторы, вычисляет прямоугольники символов, объединяет соседние символы в строки и группирует строки в текстовые блоки. Итоговый порядок зависит от геометрии и параметра boxes_flow. Поэтому первое извлечение используют как диагностику: если слова читаются правильно, но колонки перемешаны, менять кодировку бессмысленно — корректировать нужно правила макета.

Стандартный вывод и файл результата
Печать в терминал удобна для проверки первых строк и для конвейеров Unix, например передачи результата в фильтр, поиск или подсчёт. Для больших документов безопаснее писать в файл: терминальный буфер не обрезает данные, кодировка фиксируется параметром --codec, а следующий этап обработки получает стабильный путь. Значение - у outfile означает стандартный вывод и полезно в контейнерах, где лог собирает внешняя система.
При обработке нескольких входных файлов одна команда последовательно выдаёт их содержимое. Если требуется отдельный TXT на каждый PDF, оболочка должна запускать pdf2txt.py в цикле и формировать имя результата из имени источника. Это надёжнее, чем складывать документы в один поток, потому что сохраняется соответствие входа и выхода и проще повторно обработать только неудачные файлы.
Выбор страниц и ограничение объёма
Параметр --page-numbers принимает номера страниц, понятные пользователю, и удобен для точечного извлечения. В командной строке после списка чисел лучше ставить разделитель -- перед именем файла, иначе парсер аргументов может попытаться принять путь за очередной номер. Старый параметр --pagenos использует нумерацию с нуля и строку с номерами через запятую; его имеет смысл сохранять только в существующих сценариях.
--maxpages прекращает обработку после заданного количества страниц. Это полезно для предварительной оценки неизвестного корпуса: можно проверить первые две-три страницы каждого файла, измерить качество текста и определить, нужен ли OCR или специальная настройка макета. Ограничение также снижает риск чрезмерного потребления времени на повреждённом или необычно сложном документе.

Номера страниц в Python
Функции extract_text и extract_pages принимают page_numbers как множество или последовательность индексов с нуля. Если пользователь вводит страницы как 1, 3 и 5, приложению нужно преобразовать их в 0, 2 и 4. Явное преобразование лучше скрытой догадки: оно предотвращает смещение на одну страницу и позволяет валидировать отрицательные и слишком большие номера до запуска парсера.
Для выборки по диапазону создают set(range(start - 1, end)). Множество ускоряет проверку принадлежности, когда PDF содержит много страниц. Однако порядок результата задаётся самим документом, а не порядком чисел во множестве: запрос страниц 5, 2 и 4 обычно выдаёт их в естественной последовательности документа. Если нужен пользовательский порядок, страницы обрабатывают отдельными вызовами или сортируют полученные структуры после разбора.
Настройка анализа макета
LAParams определяет, как геометрические символы превращаются в читаемые строки и абзацы. Значения не задаются в пунктах или миллиметрах: большинство расстояний относительны к ширине или высоте символа. Поэтому одна и та же настройка масштабируется вместе со шрифтом и часто работает на документах с разными размерами текста. Тонкая настройка требуется там, где PDF хранит каждый символ независимо или располагает несколько смысловых потоков рядом.

line_overlap
line_overlap задаёт, насколько два символа должны перекрываться по вертикали, чтобы считаться частью одной строки. Слишком высокое значение разбивает строку при небольшом смещении базовой линии, например в формулах или при использовании нескольких кеглей. Слишком низкое значение может объединить верхний индекс с соседней строкой. Настройку меняют после просмотра координат LTChar, а не вслепую: сравнивают высоты символов и фактическое перекрытие.
char_margin
char_margin регулирует максимальный относительный разрыв между символами одной строки. Если PDF кодирует каждую букву отдельной командой и оставляет большие промежутки, увеличение параметра возвращает целые слова и строки. Но чрезмерное значение способно соединить текст из разных колонок, особенно когда колонки узкие. Для диагностики полезно вывести bbox соседних LTChar и вычислить горизонтальный разрыв относительно их ширины.
word_margin
word_margin определяет, когда между символами вставляется пробел. При слишком малом значении внутри слов появляются лишние пробелы; при слишком большом слова склеиваются. Этот параметр влияет на текстовый результат, но не обязан менять состав LTTextLine. Для документов с выравниванием по ширине разумно тестировать несколько страниц, потому что межсловные интервалы меняются от строки к строке.
line_margin
line_margin объединяет близкие строки в один текстовый блок. Низкое значение даёт много коротких LTTextBox и может разделить абзац на строки. Высокое значение соединяет подпись, основной текст и колонтитул. Когда задача требует только последовательного текста, умеренное объединение обычно удобно; при извлечении зон страницы лучше сохранять более мелкие блоки и объединять их собственным правилом по координатам.
boxes_flow
boxes_flow балансирует горизонтальное и вертикальное положение при выборе порядка текстовых блоков. Отрицательные значения сильнее учитывают движение слева направо, положительные — сверху вниз. Значение disabled отключает продвинутую эвристику и сортирует блоки по положению нижнего левого угла. Такой режим бывает предсказуемее для таблиц и форм, но хуже восстанавливает журнальные колонки и плавающие подписи.
detect_vertical и all_texts
detect_vertical включает распознавание вертикально ориентированных строк. Его следует применять к документам с вертикальным письмом или повернутыми подписями, а не включать безусловно для всего корпуса: дополнительная эвристика может изменить группировку обычного текста. all_texts заставляет анализировать текст внутри фигур LTFigure; без него надписи в Form XObject могут не попадать в обычный поток.
no_laparams
Режим без LAParams полезен, когда нужен максимально прямой поток символов и не требуется восстановление блоков. Он уменьшает объём высокоуровневой структуры, но лишает программу эвристики порядка и абзацев. Такой вывод подходит для отладки кодировок и проверки наличия текстовых операторов, а для чтения человеком обычно уступает стандартному анализу.
Форматы вывода TXT, HTML, XML и tag
Текстовый формат оптимален для полнотекстового поиска, классификации, нормализации и передачи в языковые модели. Он компактен, но теряет точные координаты и часть графической структуры. HTML сохраняет абсолютное размещение элементов и подходит для визуальной проверки того, как анализатор понял страницу. XML подробно описывает страницы, текстовые блоки, строки, символы и bbox, поэтому удобен для отладки и преобразования в собственную схему данных.
Формат tag ориентирован на помеченное содержимое PDF и полезен только там, где документ действительно содержит структурные теги. Наличие визуальных заголовков не означает наличие корректного дерева тегов: многие PDF созданы печатью из программ, которые сохраняют внешний вид, но не семантику. Перед построением процесса на tag проверяют несколько реальных файлов и предусматривают резервный путь через layout-объекты.

HTML как средство визуальной диагностики
HTML-конвертер размещает текстовые элементы с координатами и масштабом, близкими к исходной странице. Это помогает увидеть, почему два визуально соседних фрагмента оказались разными блоками или почему порядок колонок не совпал с ожиданием. Получившийся HTML не следует считать готовой доступной веб-страницей: он предназначен для представления результата конвертации и может содержать множество позиционированных элементов.
Параметр --layoutmode влияет на стратегию HTML-размещения. Режимы точного, обычного и свободного представления по-разному балансируют геометрию и читаемость. Выбор проверяют по целевой задаче: для сопоставления координат важна точность, для быстрого чтения — устойчивый поток, а для последующего парсинга лучше использовать XML или API вместо повторного разбора HTML.

Кодировка результата
По умолчанию текст записывается в UTF-8. Явное указание --codec utf-8 полезно в старых сценариях и при обмене между системами, где кодировка не фиксируется окружением. Ошибки вида кракозябры чаще связаны не с кодировкой выходного файла, а с отсутствующей или нестандартной таблицей сопоставления символов внутри PDF. В таком случае смена codec не восстановит буквы; нужно исследовать шрифт, ToUnicode и значения CID.
Высокоуровневые функции Python
extract_text — кратчайший путь от файла к строке. Функция принимает путь или файловый объект, пароль, набор страниц, максимальное число страниц, параметры LAParams и режим кеширования. Она подходит, когда нужен весь текст и не требуется различать блоки. Возвращаемую строку сразу нормализуют под задачу: удаляют повторяющиеся пробелы, сохраняют границы страниц или, наоборот, заменяют символ перевода страницы служебным маркером.
from pdfminer.high_level import extract_text
text = extract_text(
'document.pdf',
page_numbers={0, 1},
maxpages=2,
password='',
)
print(text)
extract_text_to_fp пишет в файловый объект и поддерживает разные типы вывода. Она удобна в веб-приложении или обработчике очереди, где результат нужно направить в StringIO, BytesIO, временный файл или поток ответа. Для HTML с анализом макета передают laparams=LAParams(), выбирают output_type="html" и согласуют codec с типом потока.
extract_pages возвращает генератор макетов страниц. Генератор не загружает всю иерархию документа в список заранее, поэтому его можно обрабатывать постранично и освобождать собственные промежуточные данные. Главное правило — не превращать результат в список без необходимости на больших файлах: потоковая обработка снижает пиковое потребление памяти.

Иерархия объектов макета
Верхний объект LTPage содержит ширину, высоту и дочерние элементы страницы. Координаты выражены в PDF-пунктах, начало системы обычно находится внизу слева. Прямоугольник bbox записывается как (x0, y0, x1, y1). При сопоставлении с растровым изображением страницы нужно учесть масштаб DPI и инвертировать вертикальную ось, потому что пиксельные координаты изображения часто начинаются сверху слева.
LTTextBox и LTTextLine
LTTextBox объединяет строки, которые анализатор считает одним логическим блоком. Его номер или порядок не является постоянным идентификатором между разными настройками LAParams. LTTextLine хранит символы строки и добавленные пробелы. Для извлечения текста зоны страницы обычно фильтруют LTTextContainer по пересечению bbox с заданным прямоугольником, а затем сортируют по верхней координате и x0.
LTChar и LTAnno
LTChar представляет видимый символ и содержит текст, шрифт, размер, матрицу преобразования, цветовые данные и bbox. LTAnno обозначает вставленные анализатором пробелы или переводы строки и не имеет геометрии обычного символа. Код, который ожидает bbox у каждого дочернего объекта, должен явно проверять тип: иначе на пробеле или переносе возникнет ошибка атрибута.
LTFigure и LTImage
LTFigure соответствует графическому объекту-контейнеру, часто Form XObject. Внутри него могут находиться текст, линии и изображения, поэтому обход должен быть рекурсивным. LTImage описывает поток изображения и его геометрию, но не гарантирует привычное расширение файла: формат зависит от фильтров PDF, цветового пространства и доступных декодеров. Иногда результат сохраняется как BMP или сырой поток, хотя исходная картинка визуально похожа на PNG.
LTLine, LTRect и LTCurve
Векторные линии и прямоугольники помогают находить границы таблиц, рамки полей и разделители колонок. pdfminer.six не превращает их автоматически в таблицу, но возвращает геометрию, на которой можно построить собственный алгоритм. Следует учитывать толщину линии, совпадающие сегменты и прямоугольники заливки: декоративный фон может выглядеть как ячейка, а таблица без видимых границ вообще не содержит линий.
Шрифты, размеры, цвета и координаты символов
Для аудита оформления обходят LTChar и записывают fontname, size, bbox и текст. Встроенное имя шрифта может иметь префикс подмножества, например случайные буквы перед знаком плюс. При группировке одинаковых гарнитур такой префикс удаляют только после проверки формата имени, иначе можно случайно объединить разные шрифты. Размер символа отражает преобразованную геометрию и может быть дробным.

Цвет доступен через графическое состояние символа. Нужно различать stroking и non-stroking color: текст обычно рисуется незаливающим цветом, но режим рендеринга PDF допускает обводку, заливку или их сочетание. Значение может быть числом, кортежем компонентов или объектом цветового пространства. Для унификации в RGB потребуется преобразование с учётом DeviceGray, DeviceRGB, DeviceCMYK и специальных пространств; простое копирование кортежа не всегда даёт экранный цвет.
Координаты позволяют решать задачи, невозможные для обычного TXT: отделять шапку и подвал, связывать подпись с рисунком, находить текст справа от метки, восстанавливать строки таблицы и подсвечивать найденный фрагмент в просмотрщике. При повороте страницы или текста bbox остаётся осевым прямоугольником, поэтому для точного наложения могут понадобиться матрица символа и угол, а не только четыре координаты.
Низкоуровневый разбор и dumppdf.py
dumppdf.py выводит внутренние объекты PDF: словари, массивы, ссылки, потоки, каталог, дерево страниц, ресурсы, шрифты и метаданные. Это диагностический инструмент, когда высокоуровневый текст выглядит неправильно или требуется понять структуру незнакомого файла. Режим -a обходит все объекты; на больших документах вывод получается огромным, поэтому его направляют в файл и ищут нужные ключи.

Низкоуровневый API начинается с PDFParser, который читает синтаксис из двоичного потока, и PDFDocument, который связывает объекты в документ. PDFPage создаёт последовательность страниц, PDFResourceManager кеширует общие ресурсы, PDFPageInterpreter исполняет операторы содержимого, а устройство-конвертер принимает события. Такая композиция нужна, когда стандартные конвертеры не дают требуемого результата: можно написать устройство, которое собирает только определённые операторы или сохраняет собственную структуру.
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser
with open('document.pdf', 'rb') as source:
parser = PDFParser(source)
document = PDFDocument(parser)
resources = PDFResourceManager()
# Конвертер и выходной поток создаются здесь.
# Каждая страница передаётся interpreter.process_page(page).
Кеширование ресурсов
Ресурсный менеджер повторно использует шрифты и другие объекты между страницами. Это ускоряет документ с общими ресурсами, но занимает память. В CLI кеш отключается параметром --disable-caching; такой режим полезен при диагностике утечек, обработке множества независимых файлов в одном процессе или строгом ограничении памяти. Производительность следует измерять на реальном корпусе: отключение кеша может заметно увеличить время.
Извлечение встроенных изображений
Параметр --output-dir создаёт файлы для найденных изображений одновременно с текстовым выводом. Имена формируются из внутренних объектов и не обязаны совпадать с подписями или именами исходных файлов. После извлечения проверяют сигнатуру каждого файла утилитой определения формата или библиотекой изображений, потому что расширение может отражать декодированный контейнер, а не первоначальное представление.

Поддерживаются распространённые изображения и потоки с несколькими фильтрами, включая JPEG, JBIG2, битовые карты и варианты с предикторами. Однако PDF может строить иллюстрацию из векторных операций, масок, отдельных цветовых каналов или нескольких наложенных XObject. В таком случае единой картинки для извлечения нет; для получения визуального вида страницу нужно рендерить другим инструментом, а pdfminer.six использовать для текста и структуры.
Извлечение изображения не является экспортом страницы. Если документ — скан, программа может сохранить большой растр, но не вернёт слова внутри него. Рабочий конвейер для скана состоит из рендеринга или извлечения растра, OCR внешним движком и последующего связывания распознанных координат с системой страницы. pdfminer.six полезен на этапе проверки, есть ли в документе скрытый текстовый слой поверх скана.
Защищённые паролем документы
Пароль передаётся через --password или аргумент password в Python. Если пароль отсутствует или неверен, разбор завершается исключением, и пакетный сценарий должен пометить файл как требующий учётных данных, а не повторять его бесконечно. Хранить пароль прямо в командной строке нежелательно в многопользовательской системе, потому что он может попасть в историю оболочки и список процессов; безопаснее получать его из защищённой переменной или секрет-хранилища приложения.

Поддержка шифрования позволяет читать разрешённое содержимое после успешной аутентификации, но не отменяет ограничения документа и правила доступа организации. Перед массовой обработкой проверяют, что у пользователя есть право извлекать данные. В программном интерфейсе ошибки пароля отделяют от синтаксических ошибок и ошибок ввода-вывода, чтобы сообщение точно объясняло, что требуется сделать.
Закладки и оглавление
Метод PDFDocument.get_outlines() возвращает уровень, заголовок и варианты цели записи: прямое назначение, действие или элемент структуры. Уровень позволяет восстановить вложенность оглавления, а заголовок уже декодирован в строку. Простого номера страницы в кортеже нет, потому что цель PDF может быть именованной, косвенной или ссылаться на действие.

Чтобы определить номер страницы, строят соответствие object id страниц их порядковым номерам, затем рекурсивно разрешают PDFObjRef, словари назначения, массивы и именованные ссылки. Нужно предусмотреть цель, ведущую не на страницу, удалённое действие и повреждённую ссылку. Результат лучше хранить как номер либо null вместе с исходным типом цели, а не подставлять ноль, который можно принять за первую страницу.
Оглавление полезно для сегментации длинного отчёта: диапазон раздела определяется страницей текущей записи и страницей следующей записи того же или более высокого уровня. Но документ может содержать неполные закладки, поэтому границы сверяют с заголовками текста. Для поиска по разделам сохраняют иерархический путь, например Глава / Подраздел / Пункт, а не только последний заголовок.
Поля AcroForm
Поля интерактивной формы находятся в каталоге документа под ключом AcroForm. Ссылки разрешаются функцией resolve1, имена и байтовые значения декодируются, а PSLiteral и PSKeyword преобразуются по имени. Поле может наследовать свойства от родителя, иметь несколько виджетов и хранить значение не в очевидном узле, поэтому производственный код должен рекурсивно обходить дерево Fields.

Текстовое поле обычно возвращает строку, список выбора — строку или массив, флажок — имя состояния вроде Yes или Off. Для нормализации сохраняют одновременно исходное значение и приведённое логическое или строковое значение. Это позволяет отличить пустое поле от отсутствующего поля и не потерять нестандартное состояние, заданное автором формы.
XFA-формы не поддерживаются этим способом. Внешне XFA может выглядеть как обычная заполняемая форма, но данные находятся в XML-пакетах и динамической разметке. Перед обещанием извлечения проверяют наличие AcroForm и структуру Fields; при XFA выбирают специализированный инструмент или предварительное преобразование, не подменяя отсутствие данных пустым словарём.
Сканированные PDF и необходимость OCR
pdfminer.six извлекает символы из текстовых операторов PDF, поэтому страница, содержащая только фотографию текста, возвращает пустую строку или минимум служебных данных. Быстрая диагностика — сравнить число LTChar с числом крупных LTImage на странице. Если символов нет, а изображение покрывает почти весь MediaBox, документ вероятнее всего требует OCR.
Некоторые сканы уже имеют невидимый текстовый слой. В этом случае текст извлекается, но его порядок и символы зависят от качества предыдущего распознавания. Следует сравнивать координаты LTChar с видимыми строками и искать признаки плохого слоя: повторяющиеся фразы, символы за пределами страницы, один огромный текстовый блок или несоответствие языка. Повторный OCR имеет смысл только после такой проверки.
Для гибридного конвейера сначала запускают pdfminer.six. Страницы с достаточным количеством читаемых символов проходят обычную обработку, а страницы без текста отправляются в OCR. Затем результаты объединяются с сохранением номера страницы и источника текста. Такой выборочный подход быстрее полного OCR и не ухудшает уже качественный цифровой текст.
Таблицы: что доступно и чего нет
Пакет возвращает текстовые блоки, символы, линии и прямоугольники, но не выдаёт готовую двумерную таблицу одной функцией. Табличный алгоритм строят поверх геометрии: находят горизонтальные и вертикальные границы либо группируют слова по близким координатам, формируют строки, определяют столбцы и разрешают объединённые ячейки. Для документов с устойчивым шаблоном это даёт контролируемый результат.
Таблица без линий требует статистики позиций. Слова группируют по перекрытию вертикальных интервалов, затем анализируют повторяющиеся x0 и x1. Допуск должен зависеть от размера шрифта и разрешать небольшие отклонения. Заголовок, сноска и многострочная ячейка нарушают простую сетку, поэтому алгоритму нужны правила продолжения строки и проверка числа столбцов.
Если основная задача — извлечение произвольных таблиц, удобнее использовать инструмент, который уже строит таблицы поверх pdfminer.six и предоставляет визуальную отладку. Сам pdfminer.six выбирают, когда важны полный контроль, нестандартная структура, собственные эвристики или необходимость одновременно анализировать текст, графику, формы и внутренние объекты.
Вертикальное письмо, CJK и шрифтовые карты
Поддержка CJK и CID-шрифтов позволяет разбирать документы, где символы задаются не однобайтовой кодировкой. Ключевую роль играет карта ToUnicode или известная CMap. Если сопоставление отсутствует, в выводе могут появляться маркеры вида (cid:NNN). Это означает, что код символа прочитан, но надёжного соответствия Unicode не найдено.
Для вертикального письма включают detect_vertical и проверяют LTTextLineVertical. Поворот страницы и вертикальная система письма — разные случаи: параметр --rotation меняет ориентацию страницы перед обработкой, а detect_vertical пытается распознать строки, чьи символы идут вертикально. Неверный выбор может изменить порядок чтения, поэтому проверяют образец каждого типа документа.
Нестандартный встроенный шрифт может отображаться в просмотрщике, но не иметь корректной карты символов. pdfminer.six не выполняет распознавание формы глифа. Практические варианты — найти другой экспорт документа с текстовым слоем, получить исходный файл, применить OCR или создать пользовательскую карту только при наличии достоверного соответствия кодов и символов.
Поворот, CropBox и координатные системы
Параметр --rotation поворачивает страницу на указанное число градусов перед дальнейшей обработкой. Он полезен, когда файл хранит контент боком или требуется унифицировать ориентацию. Поворот меняет координаты элементов, поэтому нельзя смешивать bbox из повернутого извлечения с координатами исходной страницы без обратного преобразования.
PDF может содержать MediaBox, CropBox и дополнительные границы. LTPage обычно отражает рабочий размер страницы после учёта геометрии документа, но приложение, накладывающее координаты на рендер, должно использовать те же границы и поворот, что и рендерер. Несовпадение на постоянную величину часто указывает на CropBox, а зеркальное расхождение по вертикали — на разное направление оси Y.
Для перевода пунктов в пиксели применяют коэффициент dpi / 72. Координата пикселя X равна x в пунктах, умноженному на коэффициент. Для верхней координаты изображения используют высоту страницы в пунктах минус y1, затем умножают на коэффициент. Округление выполняют в самом конце, иначе накопленная ошибка становится заметной на длинной странице.
Производительность и память
Время обработки зависит не только от числа страниц. Страница с тысячами отдельных символов, сложными шрифтами, вложенными Form XObject и большим количеством векторных команд может быть тяжелее десятка простых страниц. Поэтому метрики собирают по времени на страницу, числу LTChar, размеру файла и пиковому потреблению памяти, а не только по мегабайтам PDF.
Постраничный генератор extract_pages позволяет сразу записывать результат страницы в базу или JSON Lines и освобождать временные структуры. Для многопроцессной обработки лучше выдавать каждому рабочему процессу отдельный файл, а не делить один PDFDocument между процессами. Это упрощает управление файловыми дескрипторами и исключениями.
Параллелизм ограничивают по памяти и по доверенности документов. Десятки процессов могут одновременно распаковывать большие потоки и исчерпать RAM. Практичный пул имеет небольшой фиксированный размер, тайм-аут на файл, лимит размера результата и очередь повторной проверки. Очень большие документы сначала тестируют с maxpages, затем обрабатывают полностью.
Пакетная обработка корпуса
Надёжный пакетный сценарий записывает для каждого файла путь, хеш, размер, число обработанных страниц, длину текста, число блоков и статус. Такой журнал позволяет отличить пустой цифровой документ от ошибки и не повторять уже завершённую работу. Временный результат пишут под промежуточным именем и атомарно переименовывают после успешного завершения.

Исключения ловят на уровне одного файла, чтобы повреждённый документ не останавливал весь корпус. При этом нельзя использовать общий except Exception без записи типа и сообщения: иначе пароль, синтаксическая ошибка, отсутствие файла и внутренняя ошибка выглядят одинаково. Журнал должен содержать краткую безопасную причину и отдельный технический стек в защищённом логе.
Для повторяемости сохраняют параметры LAParams вместе с результатом. Текст, извлечённый с разными char_margin или boxes_flow, нельзя считать идентичным даже при одном исходном PDF. Конфигурацию удобно сериализовать в JSON и включать её хеш в имя набора данных или метаданные индекса.
Ошибки и способы устранения
Повреждённый файл может вызвать PDFSyntaxError, PSEOF, ошибку ссылки или декодирования потока. Сначала проверяют, открывается ли документ в независимом просмотрщике и начинается ли файл с сигнатуры PDF. Затем пробуют сохранить копию через надёжный нормализатор PDF; если восстановление меняет документ, сохраняют исходник и фиксируют происхождение новой копии.

| Симптом | Вероятная причина | Практическое действие |
|---|---|---|
| Пустой текст | Страница состоит из изображения | Проверить LTImage и направить страницу в OCR |
| Вместо букв cid-коды | Нет корректной Unicode-карты шрифта | Искать другой экспорт, OCR или достоверную CMap |
| Слова склеены | Слишком большой word_margin | Уменьшить значение и проверить несколько строк |
| Лишние пробелы внутри слов | Слишком маленький word_margin или большие интервалы символов | Подобрать word_margin и char_margin по bbox |
| Колонки перемешаны | Неудачный boxes_flow | Проверить значения от горизонтального к вертикальному приоритету |
| Текст из рисунка пропал | Не анализируется содержимое LTFigure | Включить all_texts или рекурсивный обход |
| Команда не найдена | Исполняемый каталог окружения не в PATH | Активировать окружение или запускать модуль через его Python |
| ImportError после установки | Конфликт пакетов или другое окружение | Проверить путь модуля и список установленных пакетов |
| Ошибка пароля | Документ зашифрован или пароль неверен | Передать пароль безопасным способом и различать статус |
| Большой расход памяти | Сложная страница, список всех макетов или кеш | Обрабатывать генератором, ограничить пул, проверить кеширование |
Команда зависает или работает необычно долго
Сначала ограничивают документ одной страницей и включают диагностическое логирование. Если проблема воспроизводится на конкретной странице, её изолируют и анализируют число объектов, вложенность XObject и размеры потоков. Для автоматического сервиса нужен внешний тайм-аут процесса: код Python не всегда может безопасно прервать глубокий разбор в середине операции.
Разные результаты в разных средах
Сравнивают версию Python, установленный пакет, зависимости, параметры и сам файл по SHA-256. Не следует полагаться на глобальный PATH или нефиксированные зависимости. Тестовый набор из нескольких PDF с ожидаемыми фрагментами и координатами обнаруживает изменения до обновления производственного индекса.
Безопасная обработка недоверенных PDF
PDF — сложный контейнер с вложенными потоками, ссылками, шрифтами и сжатием. Файлы из внешних источников обрабатывают в отдельном непривилегированном процессе или контейнере, ограничивают память, процессорное время, размер временных файлов и сетевой доступ. Выходные имена формируют самостоятельно, не используя внутренние имена объектов без очистки.
Служба должна использовать поддерживаемую сборку и регулярно обновлять зависимости безопасности. Архивы CMap и дополнительные данные берут только из доверенного источника. Даже если задача состоит лишь в извлечении текста, нельзя считать документ пассивным набором строк: декодеры и парсер обрабатывают бинарную структуру, поэтому изоляция остаётся важной.
Результат тоже проверяют. Огромная строка, миллионы элементов на одной странице или необычно длинные имена шрифтов могут перегрузить следующий этап. Лимиты на число символов, объектов и размер JSON должны завершать файл контролируемым статусом, а не обрезать данные без отметки.
Практические сценарии
Полнотекстовый индекс
Для поискового индекса извлекают текст постранично, нормализуют переносы и сохраняют номер страницы. Полезно хранить исходный фрагмент и очищенную версию: первая нужна для показа пользователю, вторая — для поиска. Координаты абзаца позволяют открыть страницу и подсветить результат, если просмотрщик использует ту же геометрию.
Разметка документов для машинного обучения
extract_pages даёт признаки, недоступные обычному тексту: положение, размер шрифта, начертание, цвет и тип объекта. На их основе можно отличать заголовки, подписи, номера страниц и основной текст. Перед обучением признаки нормализуют относительно ширины и высоты страницы, чтобы модель не зависела от формата листа.
Контроль фирменного оформления
Обход LTChar выявляет использованные шрифты и размеры, а векторные объекты помогают найти разделители и цветовые элементы. Такой аудит не заменяет полноценный рендеринг, но быстро находит страницу с неожиданным шрифтом, слишком мелким текстом или отличающимся цветом. Результат привязывают к странице и bbox для ручной проверки.
Извлечение реквизитов по якорям
В устойчивом шаблоне сначала находят текстовую метку, затем выбирают блоки справа или ниже её bbox. Метод надёжнее глобального регулярного выражения, когда одинаковые числа встречаются в нескольких разделах. Допуски задают относительно размера шрифта и проверяют, что найденное значение находится в той же строке или ячейке.
Сегментация отчёта по закладкам
Outlines дают логическую структуру, а extract_pages — содержимое страниц. Совместив их, можно создать отдельные записи по разделам, сохранить иерархию и индексировать главы независимо. Если две закладки ведут на одну страницу, начало раздела уточняют по заголовку и координате, а не делят страницу целиком.
Проверка скрытого текстового слоя
Для архивного скана сравнивают число символов, их bbox и визуальный растр. Текстовый слой хорошего качества покрывает строки и повторяет их порядок. Если все символы сжаты в одну точку или располагаются за пределами страницы, слой нельзя использовать для подсветки, хотя поиск по строке может частично работать.
Сравнение pdfminer.six с аналогами
| Программа | Лучше подходит для | Главное ограничение |
|---|---|---|
| pdfminer.six | Точного разбора текста, координат, шрифтов, объектов PDF и собственных конвейеров на Python | Нет готового OCR и визуального редактора |
| pdfplumber | Извлечения таблиц, слов и геометрии с удобными высокоуровневыми методами и визуальной отладкой | Наследует ограничения текстового слоя PDF |
| pypdf | Объединения, разделения, поворота, шифрования, форм и структурных операций с PDF | Геометрический анализ текста менее детализирован для сложных макетов |
| PyMuPDF | Быстрого рендеринга страниц, извлечения текста и изображений, аннотаций и смешанных задач | Лицензионные условия требуют отдельной оценки для проекта |
| Apache Tika | Единого извлечения текста и метаданных из множества форматов через Java или сервер | Меньше контроля над каждым символом и объектом страницы |
| PDF Commander | Ручного редактирования, объединения и конвертации PDF без написания кода | Не заменяет программный разбор объектов и координат |
pdfminer.six выбирают, когда результат должен объясняться через конкретные объекты, координаты и параметры макета. pdfplumber экономит время на таблицах и словах, поскольку предоставляет готовые методы поверх близкой модели геометрии. pypdf удобнее для изменения структуры файла, а PyMuPDF — когда в одном процессе нужны быстрый рендер и широкий набор операций. Apache Tika полезен в корпоративном конвейере разных форматов, где детализация PDF вторична. PDF Commander разумнее для человека, которому нужно визуально исправить документ, а не строить извлечение в коде.
Как спроектировать устойчивый конвейер
- Зафиксировать набор типовых PDF: цифровой текст, скан, две колонки, таблица, форма, пароль и повреждённый файл.
- Сначала запустить стандартный extract_text и измерить длину текста по страницам.
- Для страниц с плохим порядком изучить extract_pages и подобрать LAParams на представительном наборе.
- Разделить цифровые страницы и страницы, требующие OCR, по количеству LTChar и площади LTImage.
- Сохранять текст, номер страницы, bbox, параметры извлечения и SHA-256 исходного файла.
- Ограничить время, память, число объектов и размер результата для недоверенных документов.
- Обрабатывать каждый файл независимо и записывать точный статус ошибки.
- Проверять обновления на регрессионном наборе до пересборки основного индекса.
Ключевой принцип — не пытаться одним набором параметров исправить все типы документов. Корпус сначала классифицируют по структуре, затем применяют профиль настроек. Журнальная статья, банковская форма и экспорт из CAD используют разные расстояния и порядок объектов. Профили делают результат стабильнее и упрощают объяснение ошибок.
Ответы на частые практические вопросы
Почему текст копируется из просмотрщика, но извлекается в другом порядке?
Просмотрщик может применять собственную эвристику выделения и знать визуальное направление движения мыши. pdfminer.six строит порядок из координат и boxes_flow. Нужно проверить текстовые блоки, подобрать boxes_flow и при необходимости реализовать сортировку зон под конкретный макет.
Можно ли получить слова с координатами?
Да, но базовая иерархия ориентирована на символы, строки и блоки. Слова формируют из последовательностей LTChar, используя LTAnno и разрывы координат. При этом следует сохранять общий bbox слова и ссылку на страницу. Для готового метода слов удобен высокоуровневый инструмент, построенный поверх этой геометрии.
Почему изображение сохраняется как BMP?
Формат определяется внутренним потоком и доступным декодированием. PDF не обязан хранить картинку как исходный PNG. Если нужен визуально точный фрагмент страницы, страницу рендерят; если нужен именно встроенный поток, принимают сохранённый формат и конвертируют после проверки цветового пространства и маски.
Можно ли редактировать найденный текст?
Основное назначение API — разбор и извлечение, а не изменение операторов содержимого. Координаты можно передать библиотеке редактирования или использовать для создания аннотации, но замена текста внутри PDF требует учёта шрифтов, кодировок, потоков и ресурсов и не является штатной операцией pdfminer.six.
Как отличить пустую страницу от ошибки?
Пустая страница успешно создаёт LTPage без значимого текста, тогда как ошибка сопровождается исключением или незавершённым разбором. В статусе сохраняют отдельно success_empty, success_text и error. Дополнительно считают изображения и векторные объекты, чтобы пустая строка не скрывала скан.
Как извлечь только верхнюю половину страницы?
extract_pages возвращает элементы с bbox. Выбирают элементы, чей центр или площадь пересечения попадает в прямоугольник верхней половины, затем сортируют и получают текст. Критерий центра проще, а площадь пересечения лучше для блока, пересекающего границу зоны.
Как убрать колонтитулы на всех страницах?
Собирают строки из верхней и нижней полосы, нормализуют номера и сравнивают повторяемость по страницам. Фрагмент, повторяющийся на большей части документа в близких координатах, помечают колонтитулом. Простое удаление первой и последней строки опасно для страниц без шапки или с продолжением таблицы.
Подходит ли XML как постоянный формат хранения?
XML удобен для диагностики и обмена полной структурой, но может быть очень объёмным из-за элемента на каждый символ. Для постоянного хранилища часто лучше собственный компактный JSON или колонночный формат с нужными полями. Исходный PDF и параметры обработки сохраняют для повторного извлечения.
Как проверить качество без ручного чтения всех страниц?
Используют метрики: доля печатных Unicode-символов, средняя длина слов, число cid-маркеров, отношение символов к площади страницы, повторяемость строк, доля элементов за пределами страницы и расхождение с ожидаемым языком. Аномальные страницы отправляют на визуальную выборку.
Когда переходить к низкоуровневому API?
Переход оправдан, если нужно собственное устройство вывода, доступ к каталогу и ссылкам, особое управление ресурсами или точное понимание операторов. Если задача ограничена текстом и координатами, extract_text и extract_pages проще, короче и легче тестируются.
Финальная проверка результата
После настройки извлечение проверяют не по одному удачному PDF, а по набору разных страниц. Для каждой страницы сравнивают наличие ключевых фраз, порядок колонок, количество блоков, координаты нескольких якорей, шрифты заголовков и статус изображений. Отдельно тестируют пароль, отсутствие текста, повреждённый файл и форму.
Автоматические тесты не должны сравнивать весь текст побайтно, если допустимы незначительные изменения пробелов. Надёжнее проверять нормализованные фрагменты, структуру страниц и числовые координаты с допуском. Для задач юридического архива, напротив, сохраняют сырой вывод и хеш, чтобы любое изменение было заметно.
Хорошо настроенный процесс заканчивается явным артефактом: TXT для чтения, JSON с геометрией для приложения, каталог изображений, запись оглавления или словарь формы. Каждый артефакт связан с исходным SHA-256, номером страницы и конфигурацией. Тогда pdfminer.six становится не разовой командой, а проверяемым компонентом обработки PDF, результаты которого можно повторить, диагностировать и безопасно передать следующему этапу.
Справочник по параметрам командной строки
Ниже параметры сгруппированы по последствиям для результата. Такой справочник полезен при чтении сохранённой команды: по одному флагу можно понять, изменялся ли состав страниц, геометрическая группировка, формат или только место записи. Не следует менять сразу несколько параметров при диагностике, иначе невозможно определить, какой из них исправил или ухудшил результат.
--debug
Включает подробное журналирование парсера и помогает найти страницу или объект, на котором возникает ошибка. Лог может содержать большой объём технических данных, поэтому его направляют в отдельный файл и не показывают конечному пользователю.
--disable-caching
Отключает кеш ресурсов. Применяется для измерения памяти и для сценариев, где повторное использование шрифтов не даёт выигрыша. На обычном многостраничном документе может замедлить обработку.
--page-numbers
Ограничивает обработку указанными пользовательскими номерами страниц. После списка ставят двойной дефис перед путём, если имя файла может быть принято за продолжение списка.
--pagenos
Старый вариант выбора страниц с индексами от нуля и записью через запятую. При новом сценарии предпочтительнее page-numbers, чтобы вход совпадал с нумерацией в просмотрщике.
--maxpages
Останавливает разбор после заданного числа страниц. Значение ноль означает отсутствие ограничения. Используется для пробного прогона и защитного лимита.
--password
Передаёт пароль открытия. Пароль не исправляет запрет доступа и должен поступать из безопасного источника, а не из публичного журнала команды.
--rotation
Поворачивает страницу перед анализом. После изменения координаты относятся к преобразованной ориентации, что важно для наложения на изображение.
--no-laparams
Отключает высокоуровневую группировку макета. Подходит для диагностики сырого потока символов, но обычно ухудшает читаемость.
--detect-vertical
Разрешает формировать вертикальные текстовые строки. Включается для соответствующего письма или повернутых надписей после проверки образца.
--line-overlap
Устанавливает минимальное относительное перекрытие символов для одной строки. Особенно заметен в формулах, индексах и смешанных размерах шрифта.
--char-margin
Задаёт расстояние, при котором символы объединяются в строку. Увеличение помогает разреженному тексту, но может склеить колонки.
--word-margin
Задаёт порог вставки пробела между символами одной строки. Настраивается по реальным межсловным промежуткам документа.
--line-margin
Определяет объединение строк в текстовые блоки. Высокое значение укрупняет абзацы, низкое сохраняет больше отдельных строк.
--boxes-flow
Управляет приоритетом горизонтального и вертикального положения при сортировке блоков. Disabled даёт простую геометрическую сортировку.
--all-texts
Включает анализ текста внутри фигур и Form XObject. Может добавить полезные подписи, но также увеличивает объём и возвращает декоративный текст.
--outfile
Записывает результат в файл; дефис оставляет стандартный вывод. Каталог назначения должен существовать и быть доступен для записи.
--output_type
Выбирает text, html, xml или tag. Формат определяет не только расширение, но и доступную структуру данных.
--codec
Задаёт кодировку текстового представления. Не исправляет отсутствующую карту символов внутри PDF.
--output-dir
Указывает каталог для извлечённых изображений. Его содержимое проверяют по сигнатурам и связывают со страницей собственным журналом.
--layoutmode
Меняет способ размещения элементов в HTML. Проверяется визуально; для машинной геометрии предпочтительнее API или XML.
--scale
Масштабирует HTML-представление и влияет на визуальные размеры, но не делает распознанный текст точнее.
--strip-control
Удаляет управляющие символы из текстового вывода, когда они мешают следующему этапу. Перед включением проверяют, не используются ли они как значимые разделители.
Метаданные, каталог и служебная структура PDF
Текст страницы — только один слой документа. Через PDFDocument можно обращаться к каталогу, словарю Info, именованным объектам и связанным структурам. В производственном конвейере метаданные извлекают отдельно от визуального содержимого: название, автор, тема и ключевые слова не должны смешиваться с абзацами, потому что они имеют другое происхождение и могут отсутствовать либо содержать устаревшие значения.
Значения словаря Info часто представлены PDF-строками, байтами, ссылками или массивами. Перед сохранением ссылку раскрывают resolve1, строки декодируют средствами pdfminer, а неизвестные типы переводят в безопасное диагностическое представление. Прямой вызов str для байтов может дать литерал с префиксом b и потерять смысл кодировки, поэтому преобразование типов лучше вынести в одну проверяемую функцию.
Каталог Root содержит ссылки на Pages, Outlines, AcroForm, Names и другие узлы, но наличие ключа не гарантирует корректность всей ветви. Каждый узел проверяют по типу и обрабатывают независимо. Такая изоляция особенно важна для файлов, где страницы читаются, а повреждённая закладка или форма вызывает исключение. Ошибка служебной структуры не должна уничтожать уже извлечённый текст.
Дата в PDF может начинаться с префикса D:, содержать часовой пояс и неполный набор компонентов. Для индексации сохраняют исходное значение и отдельно нормализованную дату, если разбор однозначен. Нельзя безусловно трактовать строку как местное время: смещение может быть записано внутри значения либо отсутствовать. Неоднозначность отмечают явно, а не заполняют вымышленным часовым поясом.
Рекурсивный обход макета без потери объектов
LTPage и контейнеры внутри него образуют дерево. Универсальный обход принимает любой LTContainer, перебирает дочерние элементы и рекурсивно входит в LTTextBox, LTTextLine и LTFigure. На каждом уровне можно собирать LTChar, LTImage, линии, прямоугольники и кривые. Такой обход устойчивее списка конкретных классов верхнего уровня, потому что нужный текст нередко вложен в фигуру.
Рекурсия должна сохранять контекст: номер страницы, цепочку контейнеров и преобразование координат. Для диагностического JSON полезно записывать depth и parent_type. Тогда неожиданное повторение текста можно связать с Form XObject, а изображение — с конкретной фигурой. Без контекста одинаковые bbox из разных вложенных систем координат легко принять за дубликаты.
При извлечении текста нельзя автоматически складывать get_text каждого контейнера и затем ещё раз обходить его символы: это удваивает содержимое. Выбирают один уровень агрегации. Для читаемого текста берут LTTextBox или LTTextLine, а для типографики — LTChar. Если нужны оба представления, символы хранят отдельной коллекцией и не добавляют их повторно в строковое поле страницы.
Глубину и число посещённых узлов ограничивают для недоверенных файлов. Корректный PDF обычно имеет конечное дерево, но циклические или аномальные ссылки в служебных объектах могут привести к чрезмерной работе. Для layout-дерева полезны счётчик объектов и тайм-аут на файл; для PDF-объектов дополнительно ведут множество уже просмотренных идентификаторов.
Собственный конвертер и поток событий
Когда стандартных TXT, HTML и XML недостаточно, используют композицию PDFParser, PDFDocument, PDFResourceManager, PDFPageInterpreter и устройства вывода. Интерпретатор читает операторы содержимого страницы, обращается к ресурсам и передаёт результат устройству. Такая схема позволяет сохранять только нужные события и не строить лишнее представление для всего документа.
PDFPageAggregator создаёт LTPage после обработки страницы и подходит для координатного анализа. Устройство получают через get_result после interpreter.process_page. Результат следует забирать сразу для текущей страницы, а не хранить внутреннее состояние между документами. Один resource manager можно использовать в рамках согласованного процесса, однако независимая обработка файлов проще для контроля памяти и ошибок.
Собственное устройство полезно, когда требуется считать графические операции, отслеживать начало и конец фигур или записывать текст вместе с пользовательским контекстом. Но переопределение низкоуровневых методов требует понимания текстовой матрицы, состояния графики и ресурсов шрифта. Для большинства задач с bbox безопаснее расширять обработку LT-объектов, а не воспроизводить интерпретатор.
Выходной объект проектируют как стабильный контракт: page_number, width, height, rotation, blocks, images и warnings. Координаты хранят числами, не форматированными строками; текст — в Unicode; тип элемента — отдельным полем. Если позже добавляется цвет или шрифт, старые потребители продолжают читать базовые поля. Изменение схемы сопровождают номером версии результата.
Проектирование JSON с координатами
Наивный JSON, где каждый символ содержит полный набор полей, быстро разрастается. Для поиска обычно достаточно блоков и строк, а символы нужны только для задач выделения, типографики или восстановления слов. Поэтому делают уровни детализации: compact сохраняет страницы и блоки, words добавляет слова, chars — отдельные LTChar. Выбранный уровень записывают в метаданные.
bbox лучше хранить массивом [x0, y0, x1, y1] и явно указывать систему координат. PDF использует начало внизу слева, тогда как экранные интерфейсы часто считают y сверху вниз. Для экранного прямоугольника вычисляют top = page_height - y1 и bottom = page_height - y0. Исходные координаты не заменяют пересчитанными, чтобы не потерять возможность проверки.
Плавающие числа округляют только на границе экспорта. Чрезмерная точность увеличивает файл и создаёт ложные различия, но раннее округление меняет объединение соседних элементов. Практично выполнять геометрические сравнения с исходными значениями, а в JSON сохранять согласованное число знаков. Допуск сравнения фиксируют рядом с тестами.
Текстовые поля могут содержать переносы строк, управляющие символы и неразрывные пробелы. JSON-сериализатор корректно экранирует их, однако последующий индексатор может трактовать иначе. Хранят raw_text и при необходимости normalized_text, где правила нормализации задокументированы: форма Unicode, замена пробельных символов, переносы и удаление мягкого дефиса.
Поиск таблиц по линиям и выравниванию
pdfminer.six не возвращает готовую таблицу, но предоставляет данные для собственного алгоритма. Линейный подход собирает LTLine, LTRect и подходящие LTCurve, нормализует почти горизонтальные и почти вертикальные сегменты, объединяет коллинеарные участки и находит их пересечения. Из соседних координат строят клетки, после чего текст распределяют по площади пересечения bbox.
Таблица без границ требует текстовой стратегии. Строки формируют по вертикальному перекрытию, затем ищут устойчивые x-позиции левых, правых или центральных краёв слов. Колонка подтверждается на нескольких строках. Заголовок с объединённой ячейкой и многострочный текст нарушают простую сетку, поэтому алгоритм допускает пропуски и объединяет строки внутри одной области.
Качество оценивают не только совпадением текста, но и структурой: числом строк, числом колонок, пустыми клетками, объединениями и порядком чтения. Для финансовых таблиц отдельно проверяют знаки минуса, скобки, разделители тысяч и примечания. Ошибка одного символа в числе важнее лишнего пробела в заголовке, поэтому метрики зависят от поля.
Формы: наследование полей и виджеты
AcroForm представляет дерево полей. Имя, тип, значение и флаги могут находиться не в одном словаре, а наследоваться от родителя. Корректный обход поднимается по Parent, пока не найдёт требуемый ключ, и соединяет частичные имена T в полное имя. Если читать только конечный виджет, часть полей останется без названия или типа.
Ключ V хранит значение, а AS часто отражает состояние внешнего вида виджета, особенно для флажков и переключателей. Для экспортного результата полезно сохранять оба значения и список допустимых состояний из AP, если он доступен. Строки декодируют, имена PDF переводят в человекочитаемую форму, но исходное представление оставляют для диагностики.
Несколько виджетов могут относиться к одному логическому полю. Координаты находятся в аннотациях страницы, тогда как значение — в дереве AcroForm. Чтобы связать их, используют ссылки на объект и родительские отношения. Простое объединение по имени может ошибочно склеить независимые поля с одинаковой короткой частью имени.
XFA требует другого механизма и не покрывается документированным обходом AcroForm. Если в каталоге есть XFA, результат помечают как неполный, даже когда пара AcroForm-полей прочитана. Пользователь должен видеть различие между полей нет и тип формы не поддержан, иначе пустой словарь будет воспринят как корректный ответ.
Изображения, маски и цветовые пространства
LTImage сообщает имя, bbox, исходный поток и параметры, но видимая картинка может зависеть от фильтра, цветового пространства, декодирования, маски и внешней прозрачности. Извлечение потока сохраняет ресурс, а не гарантированный экранный результат. Поэтому файл после записи проверяют по magic bytes и пробуют открыть декодером, не доверяя одному расширению.
JPEG-поток часто можно сохранить без перекодирования, а FlateDecode может представлять необработанные пиксели, PNG-подобные данные или маску. ImageWriter выбирает доступный способ записи, но сложные комбинации требуют рендера страницы. Рендер и извлечение решают разные задачи: первый фиксирует внешний вид, второе сохраняет встроенный ресурс без композиции.
Одна визуальная иллюстрация может состоять из цветного изображения и отдельной маски. Если сохранить только основной поток, прозрачность потеряется. В журнале отмечают наличие imagemask, smask и размеры. Для последующей сборки потребуется библиотека обработки изображений и корректное применение альфа-канала; угадывать маску по совпадению размеров недостаточно.
Изображения внутри повторно используемого Form XObject могут встречаться на нескольких страницах. Хеш потока помогает найти идентичный ресурс, но bbox и страница остаются отдельными размещениями. В каталоге ресурсов можно хранить один бинарный файл и несколько записей placement. Это уменьшает дубликаты и не теряет информацию о расположении.
Оглавление, назначения и действия
get_outlines возвращает уровни, заголовки, destination, action и ссылки SE. Целевой номер страницы не всегда лежит в destination напрямую: назначение может быть именованным, массивом с ссылкой на страницу или действием GoTo. Надёжный резолвер последовательно проверяет эти варианты и использует get_page_number для полученной ссылки.
Уровень закладки описывает вложенность, но повреждённый файл может пропустить уровень или начать не с единицы. При построении дерева глубину нормализуют и не создают бесконечные пустые узлы. Заголовок декодируют как PDF-строку; пустой или недекодируемый заголовок сохраняют с предупреждением, а не удаляют всю ветвь.
Не каждое действие ведёт внутрь документа. URI, Launch, GoToR и JavaScript имеют иной смысл и могут быть опасны при автоматическом выполнении. pdfminer.six позволяет увидеть объекты, но конвейер не должен запускать внешние действия. Для индекса достаточно классифицировать тип, сохранить безопасные поля и отметить, что цель не является страницей текущего PDF.
Практическая проверка оглавления сравнивает число разрешённых целей, диапазон страниц и заголовки с визуальной панелью просмотрщика. Закладка на страницу за пределами документа или ссылка без цели попадает в warnings. Порядок списка сохраняют, поскольку он может отличаться от простого порядка страниц и отражать авторскую навигацию.
Потоки, файловые объекты и очистка ресурсов
Высокоуровневые функции принимают путь или файловый объект в зависимости от вызова. При работе с BytesIO указатель должен находиться в начале; после предварительного чтения выполняют seek(0). Поток обязан поддерживать операции, которые нужны парсеру. Для большого сетевого ответа безопаснее сначала записать ограниченный временный файл, чем держать непроверенный объём в памяти.
Файлы открывают через with, а выходной BytesIO или текстовый буфер закрывают после получения результата. Если обработка выбрасывает исключение, временные каталоги изображений и незавершённые файлы удаляют либо помечают. Ручное управление без finally приводит к утечкам дескрипторов в пакетной обработке и со временем вызывает ошибку открытия файлов.
Запись результата выполняют в файл с временным суффиксом в том же каталоге, затем делают атомарное переименование. Так потребитель не увидит наполовину записанный XML или JSON. При сбое сохраняют лог отдельно, а временный файл удаляют. Для сетевой файловой системы атомарность проверяют по её правилам, а не предполагают автоматически.
Один и тот же PDF не следует одновременно разбирать несколькими потоками через общий файловый объект: позиция чтения станет общей. Каждая задача получает собственный дескриптор или независимый байтовый буфер. Результаты страниц можно обрабатывать параллельно только после продуманного разделения, поскольку базовый генератор читает документ последовательно и использует общие ресурсы.
Логирование и воспроизводимая диагностика
Обычный режим записывает начало файла, выбранный профиль, число страниц, длительность, размер результата и итоговый статус. Debug включают для отдельного проблемного документа: низкоуровневые сообщения очень подробны и могут значительно увеличить лог. Уровень логирования не должен менять формат основного результата или скрывать исключение.
Вместо полного пути и пароля в общий журнал записывают безопасный идентификатор, имя без секретной части или хеш. Текст документа тоже может содержать персональные данные, поэтому пример проблемного фрагмента ограничивают и редактируют. Технический стек хранят с контролем доступа, а пользовательский отчёт содержит тип ошибки и действие для исправления.
Для воспроизведения сохраняют версию Python, пакетные зависимости, параметры LAParams, команду без секрета, платформу, SHA-256 PDF и код профиля. Сам номер пакета без параметров недостаточен: изменение char_margin или нормализации текста способно дать другой индекс. Конфигурация должна быть частью идентичности результата.
Профилирование разделяет время открытия, разбора страниц, построения layout, сериализации и последующей нормализации. Если медленной оказалась запись огромного XML, настройка парсера не поможет. Измерения проводят на одинаковом файле после прогрева дискового кеша и отдельно контролируют пиковую память.
Регрессионные тесты и эталонный набор
Эталонный набор должен отражать реальные риски: стандартный цифровой PDF, две колонки, вертикальный текст, встроенный шрифт без удобной кодировки, форму, оглавление, изображения, пароль, пустую страницу и повреждённый объект. Для каждого файла формулируют ожидаемые свойства, а не только один общий текстовый файл.
Тест блока проверяет ключевую фразу и bbox с допуском; тест символа — шрифт, размер и цвет на нескольких якорях; тест оглавления — заголовок и номер страницы; тест формы — полное имя и значение. Такие проверки локализуют регрессию. Полное побайтовое сравнение HTML хрупко из-за порядка атрибутов и форматирования.
Для текста применяют две метрики: строгую для значимых символов и нормализованную для пробелов и переносов. Если строгая изменилась, отчёт показывает страницу и контекст. Нормализация не должна скрывать перестановку колонок: порядок блоков проверяют отдельно последовательностью якорных фраз.
Обновление окружения сначала проходит эталонный набор в изолированном каталоге. Новый результат не заменяет старый автоматически. Отчёт содержит добавленные и исчезнувшие символы, изменения bbox, время и память. Принятое изменение фиксируют как новый эталон с объяснением, чтобы тест не превратился в формальное подтверждение любого вывода.
Безопасная обработка недоверенных документов
PDF способен содержать очень много объектов, глубоко вложенные структуры, огромные распакованные потоки и действия. Обработчик запускают с лимитами процессора, памяти, размера файла, времени и выходного каталога. Ограничение maxpages полезно для пробы, но не заменяет общий тайм-аут: сложной может быть первая страница.
Вход проверяют по размеру и сигнатуре, но сигнатура не доказывает корректность. Файл хранят под сгенерированным именем, не используя пользовательский путь. Выходные имена изображений нормализуют и не разрешают выход за предназначенный каталог. Результат открывают как данные, а не исполняют содержащиеся в PDF действия.
Процесс с минимальными правами отделяют от веб-приложения или очереди. Сетевой доступ ему обычно не нужен. Если библиотека или декодер завершается аварийно, управляющий процесс фиксирует статус и удаляет временные данные. Повтор выполняют только после классификации причины, иначе один файл может бесконечно занимать очередь.
Пароль передают через защищённый канал конфигурации и удаляют из команды, если список процессов доступен другим пользователям. Логи не содержат пароль. Расшифрованный текст получает ту же защиту, что и исходный документ, поскольку он может быть более удобен для поиска и поэтому не менее чувствителен.
Критерии готовности результата
Для пользовательского поиска достаточно чистого текста и границ страниц; для подсветки нужны слова или символы с bbox; для анализа оформления — шрифт, размер и цвет; для таблиц — линии и геометрические группы. Не следует сохранять максимальную детализацию по умолчанию: она увеличивает объём, замедляет индекс и усложняет проверку.
Приёмочная выборка включает документы разных источников и языков. Оператор открывает страницу рядом с визуализацией bbox и проверяет ключевые области: заголовок, колонку, таблицу, сноску, повёрнутую подпись и изображение. Найденное правило превращают в автоматический тест или предупреждение, а не оставляют как устное знание.
Итоговый конвейер должен отвечать на четыре вопроса: какой PDF обработан, какими параметрами, что именно извлечено и почему отдельный элемент отсутствует. Когда эти ответы записаны в структуре результата и журнале, ошибки воспроизводятся, параметры сравниваются, а последующие этапы получают данные с понятной геометрией и происхождением.