English translation is not available yet. Showing Russian content.

Как вы парсите сложные PDF с таблицами и графиками (не просто текст)?

Краткий тезис

Парсинг сложных PDF с таблицами и графиками — это многоэтапный процесс, выходящий за рамки простого извлечения текста. Он включает детекцию и распознавание таблиц (с помощью моделей вроде Table Transformer или инструментов Unstructured.io), извлечение числовых данных из графиков через OCR и VL-LLM, а также понимание структуры документа (заголовки, колонки, сноски) с помощью LayoutLMv3. Конечная цель — получить семантический HTML или структурированный JSON, сохраняющий иерархию и взаимосвязи элементов, пригодный для дальнейшего использования в RAG-системах.


1. Термины и базовые понятия

  • PDF (Portable Document Format) — формат, предназначенный для представления документов в фиксированном макете. Сложность парсинга возникает из-за того, что PDF не хранит логическую структуру (заголовки, абзацы, таблицы) — только позиции символов и графические примитивы.
  • OCR (Optical Character Recognition) — технология распознавания текста на изображениях. Необходима для сканированных PDF (не текстовых слоёв).
  • LayoutLMv3 — модель от Microsoft для понимания макета документа. Она объединяет текст, изображения и координаты блоков, позволяя классифицировать элементы (заголовок, таблица, сноска, подпись к рисунку).
  • Table Transformer (TATR) — модель на основе DETR (Detection Transformer), обученная для детекции и распознавания таблиц в документах. Позволяет выделить границы таблиц и ячеек.
  • VL-LLM (Vision-Language Large Language Model) — LLM|мультимодальная LLM, способная обрабатывать изображения и текст. Примеры: GPT-4V, LLaVA, Qwen-VL. Используется для описания графиков и извлечения числовых значений.

2. Обзор инструментов для парсинга PDF

ИнструментТипСильные стороныОграничения
PyMuPDF (fitz)Библиотека PythonБыстрый, извлекает текст с координатами, поддерживает таблицы (через get_table())Сложные таблицы (объединённые ячейки) могут быть неверно распознаны
pdfplumberБиблиотека PythonХорошо извлекает таблицы с настройками (table_settings), работает с текстовыми PDFМедленнее PyMuPDF, не подходит для сканов
CamelotБиблиотека PythonСпециализируется на таблицах: два режима (Lattice и Stream)Требует текстовый PDF, не обрабатывает графики
TabulaJava-утилита / Python wrapperХорош для таблиц с чёткими линиямиЗависит от Java, не для сканов
Unstructured.ioПлатформа / библиотекаМодульный пайплайн: детекция таблиц, изображений, заголовков; поддержка OCR через TesseractТребует настройки, может быть избыточен для простых PDF
Table Transformer (TATR)Модель (Hugging Face)State-of-the-art детекция и распознавание таблиц на изображенияхТребует GPU, нужна постобработка
LayoutLMv3Модель (Hugging Face)Понимание структуры документа (классификация блоков)Не извлекает таблицы напрямую, используется как часть пайплайна
Donut / NougatМодели (Hugging Face)End-to-end распознавание документа (включая математику)Требуют много ресурсов, не всегда точны для сложных макетов

3. Детекция и извлечение таблиц

3.1. Подходы

  1. Правила и эвристики (Camelot, pdfplumber): ищут линии сетки или пробелы между колонками. Работают только на текстовых PDF с чёткой структурой.
  2. Глубокое обучение (TATR, TableNet): детектируют таблицы на изображении страницы, затем распознают ячейки. Работают на сканах и сложных макетах.
  3. Гибридный (Unstructured.io): сначала детекция таблиц через TATR, затем извлечение текста из ячеек с помощью OCR (Tesseract) или встроенного парсера.

3.2. Пример пайплайна с TATR

from transformers import TableTransformerForObjectDetection, TableTransformerImageProcessor
from PIL import Image
import torch

# Загрузка модели
processor = TableTransformerImageProcessor.from_pretrained("microsoft/table-transformer-detection")
model = TableTransformerForObjectDetection.from_pretrained("microsoft/table-transformer-detection")

# Открыть страницу PDF как изображение (предварительно конвертировать)
image = Image.open("page.png")
inputs = processor(images=image, return_tensors="pt")

# Детекция таблиц
with torch.no_grad():
    outputs = model(**inputs)

# Постобработка: получить bounding boxes таблиц
target_sizes = torch.tensor([image.size[::-1]])
results = processor.post_process_object_detection(outputs, threshold=0.7, target_sizes=target_sizes)[0]

for box, score, label in zip(results["boxes"], results["scores"], results["labels"]):
    if model.config.id2label[label.item()] == "table":
        # Вырезать область таблицы
        table_region = image.crop(box.tolist())
        # Далее — распознавание структуры таблицы (структурная модель TATR)

3.3. Форматы вывода таблиц

Пример вывода в HTML:

<table>
  <thead>
    <tr><th>Год</th><th>Доход</th><th>Расход</th></tr>
  </thead>
  <tbody>
    <tr><td>2023</td><td>100</td><td>80</td></tr>
    <tr><td>2024</td><td>120</td><td>90</td></tr>
  </tbody>
</table>

4. Извлечение графиков

Графики (линейные, столбчатые, круговые) — это изображения, из которых нужно получить числовые данные и семантическое описание.

4.1. Этапы

  1. Детекция графика на странице (можно использовать LayoutLMv3 или детектор изображений).
  2. Вырезание области графика.
  3. OCR числовых значений на осях и внутри графика (Tesseract, PaddleOCR).
  4. Извлечение легенды (также OCR + NLP для сопоставления меток).
  5. Генерация текстового описания с помощью VL-LLM.

4.2. Пример с VL-LLM (GPT-4V)

import base64
from openai import OpenAI

client = OpenAI()

def describe_chart(image_path):
    with open(image_path, "rb") as f:
        base64_image = base64.b64encode(f.read()).decode("utf-8")
    response = client.chat.completions.create(
        model="gpt-4-vision-preview",
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "Опиши этот график: какие оси, какие значения, тренды. Верни структурированный JSON с ключами: title, x_label, y_label, data_points (список {x, y, label}), legend."},
                    {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}}
                ]
            }
        ],
        max_tokens=1000
    )
    return response.choices[0].message.content

4.3. Альтернатива: специализированные модели

  • ChartQA — датасет и модель для вопросов по графикам.
  • PlotQA — генерация табличных данных из графиков.
  • DePlot — модель Google, преобразующая график в таблицу.

5. Понимание структуры документа с LayoutLMv3

LayoutLMv3 позволяет классифицировать каждый текстовый блок на странице: заголовок, абзац, таблица, рисунок, сноска, номер страницы и т.д. Это критически важно для восстановления иерархии.

5.1. Пример использования

from [transformers](/wiki/transformers) import LayoutLMv3Processor, LayoutLMv3ForTokenClassification
from PIL import [Image](/wiki/Image)
import torch

processor = LayoutLMv3Processor.from_pretrained("microsoft/layoutlmv3-base")
[model](/wiki/model) = LayoutLMv3ForTokenClassification.from_pretrained("microsoft/layoutlmv3-base")

[image](/wiki/Image) = [Image](/wiki/Image).open("page.png")
# Предположим, у нас есть OCR-боксы и текст
encoding = processor([image](/wiki/Image), [text](/wiki/text)="...", boxes=[541](/answers/541)

---


## Навигация
- Предыдущий: [541](/answers/541)
- Следующий: [543](/answers/543)
- Индекс: [00. Индекс разборов](/answers)