Парсинг PDF с таблицами для RAG: Camelot vs Docling сравнение 2026 | AiManual
AiManual Logo Ai / Manual.
30 Янв 2026 Гайд

Как парсить 500-страничные PDF с таблицами для RAG: Camelot против Docling и черный ход через OCR

Практический гайд по парсингу больших PDF с таблицами для RAG-систем. Сравнение Camelot, Docling, Tabula и альтернатив на реальных примерах фармацевтических док

Таблицы в PDF - это боль. Особенно когда их 500 страниц

Вы открываете очередной 500-страничный PDF с клиническими исследованиями. Там таблицы, которые начинаются на одной странице, продолжаются на другой, содержат объединенные ячейки, а внизу - примечания мелким шрифтом. Ваша RAG-система превращает это в кашу. LLM получает обрывки данных и генерирует ответы, которые не просто неверны - они опасны в медицинском контексте.

В RAG плохой парсинг таблиц убивает точность ответов. LLM не может восстановить структуру данных из хаотичных фрагментов.

Почему стандартные методы не работают

PyPDF2? Текстовая каша. pdfplumber? Пропускает таблицы со сложным форматированием. Tesseract OCR? Требует тонкой настройки и все равно ломает структуру. Особенно страдают:

  • Фармацевтические исследования (таблицы побочных эффектов)
  • Финансовые отчеты (объединенные ячейки с иерархией)
  • Научные статьи (таблицы, разбитые на несколько страниц)
  • Техническая документация (таблицы со ссылками на другие разделы)

В моем последнем проекте по RAG-чатботу для корпоративных знаний именно таблицы стали узким местом. Пришлось перебрать все инструменты, чтобы найти работающее решение.

Camelot: когда нужно точное извлечение, но есть время ждать

Camelot-py 0.11.1 (актуальная версия на январь 2026) использует два подхода: lattice (для таблиц с четкими границами) и stream (для таблиц без границ). В теории - идеально. На практике...

Camelot на реальном PDF: что работает, а что нет

import camelot
import pandas as pd
from datetime import datetime

# Замер времени выполнения
start_time = datetime.now()

# Пытаемся парсить таблицу с границами
# Здесь Camelot обычно работает хорошо
tables_lattice = camelot.read_pdf(
    'clinical_study.pdf', 
    pages='1-10',
    flavor='lattice',
    edge_tol=500  # Чувствительность к границам
)

# Таблицы без явных границ - здесь начинаются проблемы
tables_stream = camelot.read_pdf(
    'financial_report.pdf',
    pages='45-50',
    flavor='stream',
    row_tol=10  # Расстояние между строками
)

print(f"Время выполнения: {(datetime.now() - start_time).total_seconds()} секунд")
print(f"Найдено таблиц (lattice): {len(tables_lattice)}")
print(f"Найдено таблиц (stream): {len(tables_stream)}")

# Экспорт в CSV для проверки
for i, table in enumerate(tables_lattice):
    table.to_csv(f'table_lattice_{i}.csv')
💡
Camelot требует Ghostscript. На Windows установка может быть болезненной. На Linux/Mac - проще, но все равно нужны системные зависимости.

Плюсы Camelot:

  • Высокая точность для таблиц с четкими границами
  • Возможность тонкой настройки параметров
  • Экспорт в Pandas DataFrame (удобно для дальнейшей обработки)

Минусы, которые бесят:

  • Медленно. Очень медленно. 500 страниц - это часы
  • Плохо справляется с таблицами, разбитыми на несколько страниц
  • Требует ручной настройки параметров для каждого документа
  • Иногда пропускает таблицы без объяснения причин

Docling 2.3.1: новая надежда с машинным обучением

Docling позиционирует себя как современное решение с использованием ML для понимания структуры документа. На бумаге - революция. На деле...

from docling.document import Document
from docling.datamodel.base_models import DocumentType
import time

# Инициализация документа
start_time = time.time()

doc = Document('large_report.pdf')
# Анализ структуры
doc.parse()

# Извлечение таблиц
tables = doc.tables
print(f"Время парсинга: {time.time() - start_time:.2f} секунд")
print(f"Найдено таблиц: {len(tables)}")

# Пример работы с таблицей
if tables:
    first_table = tables[0]
    # Конвертация в pandas
    df = first_table.df
    print(f"Размер таблицы: {df.shape}")
    
    # Получение контекста вокруг таблицы
    context = first_table.get_context()
    print(f"Контекст: {context[:200]}...")

Docling действительно лучше справляется с пониманием структуры документа. Он определяет заголовки, подписи к таблицам, сохраняет иерархию. Но есть нюанс.

Docling требует GPU для оптимальной работы. На CPU он работает медленнее Camelot. На Nvidia L40S (актуальная карта для инференса в 2026) он показывает хорошую скорость, но не у всех она есть.

Что Docling делает хорошо:

  • Понимает структуру документа (заголовки, подзаголовки, списки)
  • Сохраняет контекст вокруг таблиц
  • Лучше работает со сложным форматированием
  • Имеет встроенную поддержку чанкинга для RAG (актуально для длинных документов)

Проблемы, с которыми столкнулся:

  • Тяжелые зависимости (PyTorch, трансформеры)
  • Потребление памяти растет с размером документа
  • Для некоторых типов таблиц дает худший результат, чем Camelot
  • Лицензия может быть проблемой для коммерческого использования

Сравнительная таблица: что выбрать для вашего случая

Критерий Camelot Docling Tabula-py
Таблицы с границами Отлично Хорошо Отлично
Таблицы без границ Средне Хорошо Плохо
Скорость (100 страниц) 5-10 минут 2-3 минуты (GPU) 1-2 минуты
Потребление памяти Низкое Высокое Низкое
Сохранение контекста Нет Да Нет
Поддержка RAG Требует доработки Встроенная Требует доработки

Гибридный подход: как я парсю 500-страничные PDF за разумное время

После десятков неудачных попыток я выработал стратегию, которая работает на реальных проектах. Секрет - комбинация инструментов и предварительный анализ документа.

1 Анализ структуры документа

Сначала определяю, какие типы таблиц преобладают в документе. Использую легковесный инструмент для быстрого сканирования:

def analyze_pdf_structure(pdf_path, sample_pages=10):
    """Быстрый анализ первых страниц для определения стратегии"""
    import fitz  # PyMuPDF
    
    doc = fitz.open(pdf_path)
    results = {
        'total_pages': len(doc),
        'has_visible_grid': False,
        'has_scanned_pages': False,
        'table_density': []
    }
    
    # Анализируем выборочные страницы
    for page_num in range(min(sample_pages, len(doc))):
        page = doc[page_num]
        
        # Проверяем на отсканированные страницы
        if page.get_text().strip() == '' and len(page.get_images()) > 0:
            results['has_scanned_pages'] = True
            
        # Ищем прямоугольники (возможные таблицы)
        drawings = page.get_drawings()
        line_count = sum(1 for d in drawings if d['type'] == 'l')
        results['table_density'].append(line_count)
        
        if line_count > 20:  # Много линий - вероятно таблица
            results['has_visible_grid'] = True
    
    doc.close()
    return results

2 Разделяй и властвуй: стратегия парсинга

На основе анализа выбираю стратегию:

def parse_large_pdf_hybrid(pdf_path, strategy='auto'):
    """Гибридный парсинг больших PDF"""
    analysis = analyze_pdf_structure(pdf_path)
    
    if strategy == 'auto':
        if analysis['has_scanned_pages']:
            strategy = 'ocr_heavy'
        elif analysis['has_visible_grid']:
            strategy = 'camelot_priority'
        else:
            strategy = 'docling_priority'
    
    all_tables = []
    
    if strategy == 'camelot_priority':
        # Для документов с четкими таблицами
        all_tables.extend(parse_with_camelot(pdf_path, flavor='lattice'))
        
        # Дополняем Docling для сложных случаев
        remaining_pages = identify_missed_tables(all_tables, pdf_path)
        if remaining_pages:
            all_tables.extend(parse_with_docling(pdf_path, pages=remaining_pages))
            
    elif strategy == 'docling_priority':
        # Для сложных документов без четких границ
        all_tables = parse_with_docling(pdf_path)
        
        # Проверяем качество и дополняем Camelot при необходимости
        low_confidence = filter_low_confidence_tables(all_tables)
        if low_confidence:
            all_tables.extend(parse_with_camelot(pdf_path, flavor='stream'))
    
    elif strategy == 'ocr_heavy':
        # Для отсканированных документов
        all_tables = parse_with_ocr(pdf_path)
    
    return post_process_tables(all_tables)

3 Постобработка для RAG: сохраняем контекст

Самая важная часть для RAG - не просто извлечь таблицу, а сохранить ее смысловой контекст:

def prepare_tables_for_rag(tables_with_context, chunk_size=1000):
    """Подготовка таблиц для RAG-системы"""
    rag_chunks = []
    
    for table_data in tables_with_context:
        table_df = table_data['table']
        context = table_data['context']
        page_num = table_data['page']
        
        # Создаем текстовое представление таблицы с контекстом
        table_text = f"Таблица на странице {page_num}:\n"
        table_text += f"Контекст: {context}\n\n"
        table_text += "Данные таблицы:\n"
        
        # Конвертируем DataFrame в читаемый текст
        for idx, row in table_df.iterrows():
            row_text = ", ".join([f"{col}: {val}" for col, val in row.items()])
            table_text += f"- {row_text}\n"
        
        # Разбиваем на чанки, если таблица большая
        if len(table_text) > chunk_size:
            chunks = split_table_chunks(table_text, chunk_size)
            rag_chunks.extend(chunks)
        else:
            rag_chunks.append({
                'text': table_text,
                'metadata': {
                    'type': 'table',
                    'page': page_num,
                    'context': context[:200]
                }
            })
    
    return rag_chunks

Альтернативы, о которых мало говорят

Camelot и Docling - не единственные игроки. Есть инструменты, которые лучше справляются с конкретными задачами:

Tabula-py: простой и быстрый для базовых случаев

import tabula

# Самый простой API
tables = tabula.read_pdf("document.pdf", pages="all", multiple_tables=True)
# За 5 минут работы

Tabula отлично работает с простыми таблицами, но не справляется со сложным форматированием. Зато работает быстро и без лишних зависимостей.

pdfplumber с доработками

pdfplumber 0.10.3 (актуальная на 2026) можно доработать для парсинга таблиц. Не идеально, но для некоторых типов документов работает лучше Camelot:

import pdfplumber

def extract_tables_pdfplumber(pdf_path):
    tables = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            # Пробуем разные стратегии
            table = page.extract_table({
                "vertical_strategy": "lines",
                "horizontal_strategy": "lines",
                "explicit_vertical_lines": [],
                "explicit_horizontal_lines": [],
                "snap_tolerance": 3
            })
            if table:
                tables.append({
                    'page': page.page_number,
                    'table': table
                })
    return tables

Kreuzberg v4: Rust-решение для максимальной скорости

Если скорость критична, посмотрите на Kreuzberg v4. Rust-библиотека, которая в 3-5 раз быстрее Python-решений. Требует интеграции через FFI, но для production-систем может быть оптимальным выбором.

Ошибки, которые все совершают (и как их избежать)

Ошибка 1: Парсить весь документ одним инструментом. Результат: либо медленно, либо некачественно.

Решение: Анализируйте документ перед парсингом. Определяйте тип таблиц и выбирайте инструмент под конкретную задачу.

Ошибка 2: Игнорировать контекст таблиц. В RAG таблица без контекста - просто набор чисел.

Решение: Всегда сохраняйте заголовки, подписи, примечания вокруг таблицы. Используйте Docling или дорабатывайте Camelot для извлечения контекста.

Ошибка 3: Не проверять качество парсинга. Доверяете инструменту на 100% и получаете ошибки в данных.

Решение: Реализуйте валидацию. Проверяйте количество строк/столбцов, ищите аномалии, сравнивайте с эталонными страницами.

Практический пример: фармацевтический отчет на 500 страниц

В реальном проекте с клиническими исследованиями я использовал такой пайплайн:

  1. Быстрый анализ первых 50 страниц для определения типов таблиц
  2. Параллельный парсинг: Camelot для таблиц с границами, Docling для сложных случаев
  3. Валидация: сравнение количества извлеченных таблиц с визуальной оценкой
  4. Постобработка: объединение таблиц, разбитых на страницы, добавление контекста
  5. Подготовка для RAG: чанкинг с сохранением семантических границ

Результат: 98% таблиц извлечены корректно, время обработки - 45 минут вместо 5 часов при использовании только Camelot.

Что будет дальше? Прогноз на 2026-2027

Тренды, которые уже видны:

  • Специализированные модели: Появятся LLM, обученные specifically на понимании структуры таблиц
  • Multimodal подход: Комбинация компьютерного зрения и NLP для лучшего понимания документов
  • Rust-инструменты: Скорость станет критичным фактором, Python-решения будут дополняться Rust-библиотеками
  • Облачные сервисы: AWS, Google и Azure предложат специализированные API для парсинга таблиц

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

💡
Совет из практики: начните с Tabula для быстрого прототипа, затем переходите к гибридному подходу с Camelot/Docling для production. И всегда, всегда проверяйте качество на выборке документов перед запуском в продакшен.

FAQ: частые вопросы и ответы

Какой инструмент лучше для RAG?

Для RAG важнее всего сохранение контекста. Docling здесь выигрывает, но требует больше ресурсов. Если нужно быстрое решение - Camelot с доработкой для извлечения контекста.

Как ускорить парсинг 500-страничного PDF?

1. Параллельная обработка по страницам. 2. Предварительный анализ для пропуска страниц без таблиц. 3. Использование GPU для Docling. 4. Кэширование результатов.

Что делать с отсканированными PDF?

Используйте OCR (Tesseract 5.0+ с LSTM). Но помните: качество парсинга таблиц после OCR будет ниже. Для критичных случаев рассмотрите ручную проверку.

Как интегрировать парсинг в RAG-пайплайн?

Создайте отдельный микросервис для парсинга документов. Он должен принимать PDF, возвращать структурированные данные с контекстом. Затем эти данные подаются в этап чанкинга и эмбеддинга вашего RAG. Подробнее о RAG-архитектуре здесь.

Есть ли готовые решения для корпоративного использования?

Да, но они дорогие. AWS Textract, Google Document AI, Azure Form Recognizer. Для локального развертывания смотрите в сторону локальных фабрик анализа документов.