0Pricing
AI Agents · Урок

Разбор PDF с помощью PyMuPDF и pdfplumber

Программное извлечение текста, таблиц и метаданных из PDF.

«Разбор PDF с помощью PyMuPDF и pdfplumber» — бесплатный урок AI Agents на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Agents, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Agents содержит 4 уроков всего.

Почему разбор PDF — нетривиальная задача

PDF — это формат представления, а не формат данных. Текст хранится как глифы с координатами, а не как логические абзацы. Для извлечения осмысленного текста нужно учитывать структуру страницы, порядок чтения, свойства шрифта и такие особые случаи, как многоколоночная разметка, верхние и нижние колонтитулы и встроенные изображения.

Наиболее распространены две библиотеки: PyMuPDF (скорость) и pdfplumber (извлечение таблиц).

Основы PyMuPDF

PyMuPDF (импортируется как fitz) — самая быстрая библиотека Python для работы с PDF. Она поддерживает извлечение текста, метаданных и изображений, а также визуализацию. Установите её командой pip install pymupdf.

import fitz  # PyMuPDF

# Open a PDF
doc = fitz.open('document.pdf')

print(f'Pages: {len(doc)}')
print(f'Metadata: {doc.metadata}')

# Extract text from all pages
full_text = ''
for page_num in range(len(doc)):
    page = doc[page_num]
    text = page.get_text()  # plain text extraction
    full_text += f'--- Page {page_num + 1} ---\n{text}\n'

doc.close()
print(full_text[:500])

Режимы извлечения текста в PyMuPDF

page.get_text() поддерживает разные форматы вывода. Используйте 'text' для обычного текста, 'blocks' для текстовых блоков с ограничивающими прямоугольниками и 'dict' для расширенного структурированного вывода, включающего названия и размеры шрифтов.

import fitz

doc = fitz.open('report.pdf')
page = doc[0]

# Mode 1: plain text
plain = page.get_text('text')

# Mode 2: blocks (each block has bbox + text)
blocks = page.get_text('blocks')
for block in blocks:
    x0, y0, x1, y1, text, block_no, block_type = block
    if block_type == 0:  # text block (1 = image)
        print(f'Block at ({x0:.0f},{y0:.0f}): {text[:80]}')

# Mode 3: dict (full detail including font info)
page_dict = page.get_text('dict')
for block in page_dict['blocks']:
    if block.get('type') == 0:  # text
        for line in block['lines']:
            for span in line['spans']:
                print(f"Font: {span['font']}, Size: {span['size']:.1f}, Text: {span['text']}")

doc.close()

Извлечение метаданных страницы

Метаданные страницы помогают агентам понять структуру документа: количество страниц, название документа, автора, дату создания и размеры страницы. PyMuPDF предоставляет все эти данные.

import fitz

def extract_pdf_metadata(filepath):
    doc = fitz.open(filepath)
    meta = doc.metadata
    info = {
        'title':    meta.get('title', 'Unknown'),
        'author':   meta.get('author', 'Unknown'),
        'subject':  meta.get('subject', ''),
        'creator':  meta.get('creator', ''),
        'created':  meta.get('creationDate', ''),
        'modified': meta.get('modDate', ''),
        'pages':    len(doc),
        'page_size': {
            'width':  doc[0].rect.width,
            'height': doc[0].rect.height
        }
    }
    doc.close()
    return info

meta = extract_pdf_metadata('contract.pdf')
print(f"Title: {meta['title']}, Pages: {meta['pages']}")

pdfplumber для извлечения таблиц

pdfplumber отлично подходит для извлечения таблиц из PDF. Библиотека использует геометрический анализ для обнаружения границ ячеек даже в PDF без явной разметки таблиц.

Установите её командой pip install pdfplumber.

import pdfplumber

with pdfplumber.open('financial_report.pdf') as pdf:
    for page_num, page in enumerate(pdf.pages):
        tables = page.extract_tables()
        for table_idx, table in enumerate(tables):
            print(f'Page {page_num+1}, Table {table_idx+1}:')
            # table is a list of rows; each row is a list of cell strings
            headers = table[0]
            for row in table[1:]:
                row_dict = dict(zip(headers, row))
                print(row_dict)

Настройки таблиц в pdfplumber

Параметры извлечения таблиц в pdfplumber можно настроить для работы с разными стилями таблиц: явными линиями, столбцами, разделёнными пробелами, или смешанной структурой.

import pdfplumber

# Custom table settings for borderless tables
table_settings = {
    'vertical_strategy':   'text',   # 'lines', 'lines_strict', 'text', 'explicit'
    'horizontal_strategy': 'text',
    'snap_tolerance':       5,
    'join_tolerance':       3,
    'edge_min_length':     50,
    'min_words_vertical':   3,
    'min_words_horizontal': 1
}

with pdfplumber.open('nolines_table.pdf') as pdf:
    page = pdf.pages[0]
    table = page.extract_table(table_settings)
    if table:
        import csv
        import io
        output = io.StringIO()
        writer = csv.writer(output)
        writer.writerows(table)
        csv_string = output.getvalue()
        print(csv_string[:300])

Обработка многоколоночной разметки

В научных статьях и газетах используется многоколоночная разметка. Наивное извлечение текста читает строки слева направо через все столбцы, создавая искажённый текст. Исправьте это, сначала отсортировав текстовые блоки по столбцам.

import fitz

def extract_multicolumn_text(page, n_columns=2):
    page_width = page.rect.width
    col_width = page_width / n_columns

    blocks = page.get_text('blocks')
    # Filter text blocks only
    text_blocks = [b for b in blocks if b[6] == 0]

    # Assign each block to a column based on x position
    columns = [[] for _ in range(n_columns)]
    for block in text_blocks:
        x0 = block[0]
        col_idx = min(int(x0 / col_width), n_columns - 1)
        columns[col_idx].append(block)

    # Sort each column by vertical position
    for col in columns:
        col.sort(key=lambda b: b[1])  # sort by y0

    # Read columns left to right
    full_text = ''
    for col in columns:
        for block in col:
            full_text += block[4] + '\n'
    return full_text

Фильтрация верхних и нижних колонтитулов

Верхние и нижние колонтитулы PDF повторяются на каждой странице и засоряют извлечённый текст. Определяйте их по вертикальному положению (верхние или нижние 10% страницы) и исключайте при извлечении содержимого.

import fitz

def extract_without_headers_footers(page, margin_ratio=0.08):
    page_height = page.rect.height
    top_margin = page_height * margin_ratio
    bottom_margin = page_height * (1 - margin_ratio)

    blocks = page.get_text('blocks')
    content_blocks = []

    for block in blocks:
        x0, y0, x1, y1, text, block_no, block_type = block
        if block_type != 0:
            continue  # skip image blocks
        # Skip blocks in header or footer zone
        if y0 < top_margin or y1 > bottom_margin:
            continue
        content_blocks.append(text)

    return '\n'.join(content_blocks)

Разбиение текста PDF на фрагменты для агентов

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

import fitz

def pdf_to_chunks(filepath, chunk_size=1000, overlap=200):
    doc = fitz.open(filepath)
    chunks = []

    for page_num in range(len(doc)):
        page = doc[page_num]
        page_text = page.get_text()

        # Split into chunks with overlap
        start = 0
        while start < len(page_text):
            end = start + chunk_size
            chunk = page_text[start:end]
            chunks.append({
                'text': chunk,
                'page': page_num + 1,
                'char_start': start,
                'source': filepath
            })
            start += chunk_size - overlap  # overlap

    doc.close()
    return chunks

chunks = pdf_to_chunks('research_paper.pdf')
print(f'Total chunks: {len(chunks)}')
print(f'Sample: {chunks[0]["text"][:200]}')

Объединение PyMuPDF и pdfplumber

Используйте PyMuPDF для извлечения текста (быстрее), а pdfplumber — для обнаружения таблиц (точнее). Комбинированный экстрактор обрабатывает каждую страницу обеими библиотеками и возвращает структурированное содержимое, разделяя текст и таблицы.

import fitz
import pdfplumber

def full_pdf_extract(filepath):
    result = {'text_by_page': [], 'tables': []}

    # Text extraction with PyMuPDF
    doc = fitz.open(filepath)
    for i in range(len(doc)):
        text = extract_without_headers_footers(doc[i])
        result['text_by_page'].append({'page': i + 1, 'text': text})
    doc.close()

    # Table extraction with pdfplumber
    with pdfplumber.open(filepath) as pdf:
        for page_num, page in enumerate(pdf.pages):
            tables = page.extract_tables()
            for t in tables:
                result['tables'].append({
                    'page': page_num + 1,
                    'headers': t[0] if t else [],
                    'rows': t[1:] if t and len(t) > 1 else []
                })

    return result

Сохранение извлечённого текста в файлы

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

import json, os

class FakePage:
    def __init__(self, text): self.text = text
    def get_text(self): return self.text

class FakeDoc(list):
    def close(self): pass

def fitz_open(path):
    return FakeDoc([FakePage('Page 1 text'), FakePage('Page 2 text')])

def pdf_to_text_file(pdf_path, output_dir):
    doc = fitz_open(pdf_path)
    base = os.path.splitext(os.path.basename(pdf_path))[0]
    txt_path = os.path.join(output_dir, base + '.txt')
    with open(txt_path, 'w', encoding='utf-8') as f:
        for i, page in enumerate(doc):
            f.write(f'--- Page {i+1} ---\n{page.get_text()}\n')
    json_path = os.path.join(output_dir, base + '.json')
    pages = [{'page': i+1, 'text': p.get_text()} for i, p in enumerate(doc)]
    with open(json_path, 'w') as f:
        json.dump({'source': pdf_path, 'pages': pages}, f, indent=2)
    doc.close()
    print(f'Saved: {txt_path} and {json_path}')
    return txt_path, json_path

pdf_to_text_file('sample.pdf', '.')

Проверка знаний

Какая библиотека Python лучше всего подходит для извлечения таблиц из файлов PDF?

Итоги: разбор PDF с помощью PyMuPDF и pdfplumber

PyMuPDF (fitz) — быстрый выбор для извлечения текста и метаданных, а также обработки многоколоночной структуры. pdfplumber отлично подходит для извлечения таблиц с настраиваемыми геометрическими стратегиями.

Основные методы: используйте get_text('blocks') для извлечения с учётом положения, отфильтровывайте верхние и нижние колонтитулы по вертикальному положению, обрабатывайте многоколоночную структуру, сортируя блоки по колонкам, и разбивайте текст на фрагменты с перекрытием для систем поиска, используемых агентами. Для лучших результатов объединяйте обе библиотеки.

Часто задаваемые вопросы

Урок «Разбор PDF с помощью PyMuPDF и pdfplumber» бесплатный?

Да — полный текст урока «Разбор PDF с помощью PyMuPDF и pdfplumber» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Agents, подпишись на CoddyKit PRO. Курс AI Agents содержит 4 уроков всего.

Чему я научусь в уроке «Разбор PDF с помощью PyMuPDF и pdfplumber»?

Программное извлечение текста, таблиц и метаданных из PDF. Ты практикуешь AI Agents с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Agents?

Предыдущий опыт не требуется. AI Agents на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Разбор PDF с помощью PyMuPDF и pdfplumber»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Agents?

Да. Каждый урок AI Agents включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Разбор PDF с помощью PyMuPDF и pdfplumber
  2. OCR для отсканированных документов
  3. Агенты для вопросов и ответов по нескольким документам
  4. Классификация и маршрутизация документов
← Назад к AI Agents