Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Парсинг PDF и документов на Python

Извлечение данных из PDF и документов на Python: инструменты и реальность

Практика парсинга PDF на Python: pdfplumber и PyMuPDF для текста и таблиц, сканированные документы и OCR, docx/xlsx, извлечение структурированных данных — с честными ограничениями.

Прямой ответ

Парсинг PDF — задача про ожидания, а не код: PDF — формат отображения (где нарисовать глиф), а не структурированных данных, и «таблица» в нём — набор несвязанных текстовых позиций. Рабочая схема: сначала определить природу файла (текстовый PDF или скан — решает всё), для текстовых — pdfplumber (аккуратные таблицы и координаты) или PyMuPDF (скорость и большие объёмы), для сканов — OCR (Tesseract через pytesseract; качество = подготовка изображения), извлечённое — через явные правила извлечения (regex/координаты/якорные строки) с проверками качества на выходе. И честное правило: 100% автоматического извлечения из произвольных PDF не существует — пайплайн строится с допуском ошибок и человеческой проверкой критичных полей.

Шаг 0. Диагностика: текстовый или скан

pdfplumber.open(f).pages[0].extract_text() вернул внятный текст — файл текстовый (парсится напрямую); None/мусор — скан или «псевдотекст» (шрифт без Unicode-маппинга — текст визуально есть, извлекается кракозябрами). От диагноза зависит весь стек: текстовые — миллисекунды на страницу, нулевые зависимости кроме парсера; сканы — OCR-конвейер (секунды на страницу, качество зависит от разрешения/перекосов). Промежуточный класс — «смешанные» (скан с текстовым слоем из чужого OCR): текстовый слой может быть хуже вашего свежего OCR — сравнивать на выборке.

Текстовые PDF: pdfplumber и PyMuPDF

pdfplumber — аккуратность: extract_text() с настройками (layout-режим сохраняет колонки), extract_tables() (эвристики линий/пробелов — нарисованные таблицы распознаёт хорошо, «невидимые» — по настройке vertical/horizontal_strategy), координаты слов (words — bbox каждого слова: извлечение «значений в зоне» для типовых форм). PyMuPDF (fitz) — скорость и мощь: в разы быстрее на больших файлах, богатый API (поиск по тексту с координатами, рендеринг страниц в изображения для отладки глазами, работа с формами). Выбор: типовые счета/отчёты с таблицами — pdfplumber; потоковая обработка тысяч страниц — PyMuPDF; часто — PyMuPDF для навигации + pdfplumber для таблиц.

Таблицы и структурированное извлечение

Таблица из PDF → DataFrame — только начало: слияния ячеек, переносы строк внутри ячейки, «продолжение таблицы» на следующей странице с повтором шапки, итоговые строки — всё это чистится по паттернам очистки. Для полевых документов (счета, акты — «ИНН: ___, Сумма: ___») надёжнее табличного подхода якорные правила: найти строку-якорь («Итого к оплате»), взять значение справа/ниже по координатам или regex (дисциплина паттернов критична — документы полны почти-совпадений); каждый шаблон документа — свой набор правил (универсальный извлекатель «любых счетов» — миф). Валидация извлечённого обязательна: контрольные суммы (итог = сумма позиций), форматные проверки (ИНН/даты), «уверенность» ниже порога — на ручную проверку.

Скан: OCR и его цена

Конвейер OCR: рендер страницы в изображение с достаточным DPI (300 — стандарт; 150 теряет мелкий шрифт), предобработка (deskew/бинаризация — OpenCV, при перекосах качество прыгает), Tesseract (pytesseract, язык rus+eng — смешанные документы часты), постобработка (словарные правки очевидного — «0» в «О»). Реальность качества: чистый печатный скан — 98%+ символов, плохой скан с печатью/подписью поверх — заметно хуже, рукописный — практически нерешаем классическим OCR. Современная альтернатива для сложных случаев — мультимодальные LLM (страница картинкой → структурированный JSON) — качество выше на «нестандарте», цена — приватность и стоимость API (локальные варианты — Ollama/LM Studio); для массового потока классический OCR+правила остаются экономичнее.

Docx, xlsx и остальные форматы

Не-PDF документы парсятся надёжнее (форматы структурированы): docx — python-docx (параграфы, таблицы, стили) или pandoc-конвертация; xlsx — openpyxl/pandas (типы ячеек и их ловушки — в статье про экспорт/чтение Excel); html — selectolax/BeautifulSoup (веб-версии документов предпочтительнее их PDF-экспорта — берите HTML, если есть); email/.msg — email-модуль/extract-msg. Правило приоритета: при наличии выбора формата источника берите самый структурированный (HTML > DOCX > текстовый PDF > скан) — каждый шаг вниз по этой лестнице удваивает усилия извлечения.

Пайплайн промышленного извлечения

Схема, переживающая реальность: приём файлов (почта/загрузка — email-механика) → классификация типа документа (по якорям/первой странице) → маршрутизация в свой экстрактор типа → извлечение с confidence → валидация (контрольные соотношения) → «зелёное» в учётную систему, «жёлтое» в очередь ручной проверки (интерфейс «поле — фрагмент страницы» ускоряет правку в разы) → метрики (доля автообработки, точность по полям — без них «парсер работает» недоказуемо). Хранение оригиналов обязательно (перепроверка/аудит; форматы файлов — в статье про CSV/parquet для извлечённых данных). Масштабирование — очереди и воркеры (PDF тяжёлые по CPU/памяти — фоновые задачи).

Практический сценарий: извлечение реквизитов из типового счёта

Возьмём распространённую задачу: бухгалтерия получает десятки PDF-счетов одного поставщика, нужно вытянуть номер, дату, ИНН и итоговую сумму в учётную систему. Шаг первый — диагностика: pdfplumber извлекает текст (счёт текстовый, не скан — OCR не нужен). Шаг второй — разведка на пяти образцах: текст страницы показывает, что реквизиты стоят после устойчивых якорей («Счёт №», «Дата составления», «ИНН», «Итого к оплате»); пишем regex-набор под якоря с терпимостью к пробелам (дисциплина паттернов — квантификаторы без жадности, экранирование точек). Шаг третий — координатная страховка: у «Итого к оплате» значение берём не из той же строки (оно может перенестись), а по bbox — самое правое число ниже якоря в пределах двадцати пунктов; pdfplumber отдаёт координаты слов, и правило переживает переносы строк. Шаг четвёртый — валидация: дата парсится datetime.strptime с явным форматом, ИНН — десять/двенадцать цифр с контрольным числом, сумма сверяется с суммой позиций таблицы (extract_tables + сложение с копеечной точностью Decimal). Шаг пятый — уверенность и человек: все поля извлеклись и проверки прошли — запись уходит в систему автоматически; любое поле не найдено или контрольное соотношение не сошлось — документ в очередь ручной проверки с подсветкой проблемного поля. Итог: 95% потока обрабатывается без человека, ошибки не проникают в учёт — потому что «извлекли и записали» без валидации в таких пайплайнах не бывает.

FAQ

Какая библиотека «лучшая» для PDF? Зависит от задачи: таблицы — pdfplumber, скорость/объём — PyMuPDF, простой текст — обе; «лучшей вообще» нет, и pdfminer.six (низкий уровень) остаётся фундаментом под ними. Начните с pdfplumber на своей выборке документов.

Почему extract_tables возвращает мусор? Таблица без видимых линий (только пробелы) требует настройки стратегий распознавания (strategy="text", настройки snap/join) — дефолт рассчитан на нарисованные сетки. Не настраивается — переходите к координатному извлечению по словам.

OCR на русском — что нужно знать? Tesseract с lang='rus' (пакет языка установлен в систему), предобработка изображения решает больше, чем смена движка; ё/й и цифры 3/З — типичные ошибки, лечатся словарной постобработкой по предметной лексике.

LLM заменят regex-извлечение? Дополнят: LLM хороши на разнородных/нестандартных документах и «последней миле», но детерминированные правила дешевле, быстрее и объяснимее для типового потока. Зрелый пайплайн — правила для шаблонов + LLM для исключений + человек для критичного.

Источники: документация pdfplumber, PyMuPDF, Tesseract — ссылки в шапке.