Разбор 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 — локальная установка не требуется.
Все уроки этого курса
- Разбор PDF с помощью PyMuPDF и pdfplumber
- OCR для отсканированных документов
- Агенты для вопросов и ответов по нескольким документам
- Классификация и маршрутизация документов