Преобразование HTML в Markdown с помощью Python: Полное руководство

Python для преобразования HTML в чистый, готовый для LLM Markdown

Содержимое страницы

Преобразование HTML в Markdown — это фундаментальная задача в современных разработческих процессах, особенно при подготовке веб-контента для больших языковых моделей (LLM), систем документации или статических генераторов сайтов, таких как Hugo.

Хотя HTML разработан для веб-браузеров с богатым стилем и структурой, Markdown предлагает чистый, удобочитаемый формат, идеальный для обработки текста, системы контроля версий и потребления ИИ. Если вы новичок в синтаксисе Markdown, ознакомьтесь с нашим Шпаргалкой по Markdown для всестороннего справочника.

инфографика: преобразование страницы из html в markdown

В этом всестороннем обзоре мы рассмотрим шесть пакетов Python для преобразования HTML в Markdown, предоставим практические примеры кода, бенчмарки производительности и реальные сценарии использования. Будь то создание конвейера обучения LLM, миграция блога в Hugo или скрейпинг документации, вы найдете идеальный инструмент для вашего рабочего процесса.

Альтернативный подход: Если вам нужна более интеллектуальная извлечение контента с семантическим пониманием, вы также можете рассмотреть преобразование HTML в Markdown с использованием LLM и Ollama, которое предлагает преобразование с использованием ИИ для сложных макетов.

Что вы узнаете:

  • Подробное сравнение 6 библиотек с преимуществами и недостатками каждой
  • Бенчмарки производительности с реальными образцами HTML
  • Готовые к производству примеры кода для распространенных сценариев использования
  • Лучшие практики для конвейеров предварительной обработки LLM
  • Конкретные рекомендации на основе ваших требований

Почему Markdown для предварительной обработки LLM?

Прежде чем погружаться в инструменты, давайте поймем, почему Markdown особенно ценен для рабочих процессов LLM:

  1. Эффективность токенов: Markdown использует значительно меньше токенов, чем HTML для того же контента
  2. Семантическая ясность: Markdown сохраняет структуру документа без громоздких тегов
  3. Читаемость: И люди, и LLM могут легко разбирать синтаксис Markdown
  4. Согласованность: Стандартизированный формат снижает неоднозначность во входных данных модели
  5. Хранение: Меньшие размеры файлов для данных обучения и окон контекста

Гибкость Markdown выходит за рамки преобразования HTML — вы также можете преобразовать документы Word в Markdown для рабочих процессов документации или использовать его в системах управления знаниями, таких как Obsidian для управления личными знаниями.

TL;DR - Быстрая матрица сравнения

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

Функция html2text markdownify html-to-markdown trafilatura domscribe html2md
Поддержка HTML5 Частичная Частичная Полная Полная Полная Полная
Указания типов Нет Нет Да Частичная Нет Частичная
Пользовательские обработчики Ограниченные Отличные Хорошие Ограниченные Хорошие Ограниченные
Поддержка таблиц Базовая Базовая Расширенная Хорошая Хорошая Хорошая
Асинхронная поддержка Нет Нет Нет Нет Нет Да
Извлечение контента Нет Нет Нет Отличное Нет Хорошее
Извлечение метаданных Нет Нет Да Отличное Нет Да
Инструмент командной строки Нет Нет Да Да Нет Да
Скорость Средняя Медленная Быстрая Очень быстрая Средняя Очень быстрая
Активная разработка Нет Да Да Да Ограниченная Да
Версия Python 3.6+ 3.7+ 3.9+ 3.6+ 3.8+ 3.10+
Зависимости Нет BS4 lxml lxml BS4 aiohttp

Быстрое руководство по выбору:

  • Нужна скорость? → trafilatura или html2md
  • Нужна настройка? → markdownify
  • Нужна безопасность типов? → html-to-markdown
  • Нужна простота? → html2text
  • Нужно извлечение контента? → trafilatura

Участники: сравнение 6 пакетов Python

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

1. html2text - Классический выбор

Разработанный Аароном Свартцем, html2text уже более десяти лет является основой экосистемы Python. Он сосредоточен на создании чистого, удобочитаемого вывода Markdown.

Установка:

pip install html2text

Базовое использование:

import html2text

# Создать экземпляр конвертера
h = html2text.HTML2Text()

# Настроить параметры
h.ignore_links = False
h.ignore_images = False
h.ignore_emphasis = False
h.body_width = 0  # Не переносить строки

html_content = """
<h1>Добро пожаловать в веб-скрейпинг</h1>
<p>Это **комплексное руководство** по извлечению контента.</p>
<ul>
    <li>Легко в использовании</li>
    <li>Проверено в боях</li>
    <li>Широко принято</li>
</ul>
<a href="https://example.com">Узнать больше</a>
"""

markdown = h.handle(html_content)
print(markdown)

Вывод:

# Добро пожаловать в веб-скрейпинг

Это **комплексное руководство** по извлечению контента.

  * Легко в использовании
  * Проверено в боях
  * Широко принято

[Узнать больше](https://example.com)

Расширенная конфигурация:

import html2text

h = html2text.HTML2Text()

# Пропустить определенные элементы
h.ignore_links = True
h.ignore_images = True

# Управление форматированием
h.body_width = 80  # Переносить на 80 символах
h.unicode_snob = True  # Использовать юникод-символы
h.emphasis_mark = '*'  # Использовать * для выделения вместо _
h.strong_mark = '**'

# Обработка таблиц
h.ignore_tables = False

# Защита предварительно отформатированного текста
h.protect_links = True

Преимущества:

  • Зрелый и стабильный (более 15 лет разработки)
  • Обширные варианты конфигурации
  • Хорошо обрабатывает крайние случаи
  • Нет внешних зависимостей

Недостатки:

  • Ограниченная поддержка HTML5
  • Может производить непостоянные отступы
  • Не активно поддерживается (последнее крупное обновление в 2020 году)
  • Только однопоточная обработка

Лучше всего для: Простых HTML-документов, устаревших систем, когда стабильность имеет первостепенное значение

Современное веб-разработка

Создание с использованием Python и современных фреймворков.

Простота — высшая степень изысканности.

Расширенное использование с пользовательскими обработчиками:

from markdownify import MarkdownConverter

class CustomConverter(MarkdownConverter):
    """
    Создание пользовательского конвертера с конкретной обработкой тегов
    """
    def convert_img(self, el, text, convert_as_inline):
        """Пользовательский обработчик изображений с текстом alt"""
        alt = el.get('alt', '')
        src = el.get('src', '')
        title = el.get('title', '')

        if title:
            return f'![{alt}]({src} "{title}")'
        return f'![{alt}]({src})'

    def convert_pre(self, el, text, convert_as_inline):
        """Улучшенная обработка блоков кода с детекцией языка"""
        code = el.find('code')
        if code:
            # Извлечение языка из атрибута class (например, 'language-python')
            classes = code.get('class', [''])
            language = classes[0].replace('language-', '') if classes else ''
            return f'\n```{language}\n{code.get_text()}\n```\n'
        return f'\n```\n{text}\n```\n'

# Использование пользовательского конвертера
html = '<pre><code class="language-python">def hello():\n    print("world")</code></pre>'
markdown = CustomConverter().convert(html)
print(markdown)

Для получения дополнительной информации о работе с блоками кода Markdown и синтаксическим выделением, см. наше руководство по Использованию блоков кода Markdown.

Селективная конвертация тегов:

from markdownify import markdownify as md

# Полное удаление определенных тегов
markdown = md(html, strip=['script', 'style', 'nav'])

# Конвертация только определенных тегов
markdown = md(
    html,
    heading_style="ATX",  # Использование # для заголовков
    bullets="-",  # Использование - для маркеров
    strong_em_symbol="*",  # Использование * для выделения
)

Преимущества:

  • Основано на BeautifulSoup4 (надежный парсинг HTML)
  • Высокая настраиваемость через подклассирование
  • Активное сопровождение
  • Хорошая документация

Недостатки:

  • Требуется зависимость BeautifulSoup4
  • Может быть медленнее для больших документов
  • Ограниченная встроенная поддержка таблиц

Лучше всего подходит для: пользовательской логики конвертации, проектов, уже использующих BeautifulSoup4


3. html-to-markdown - Современный мощный инструмент

html-to-markdown — это полностью типизированная, современная библиотека с всеобъемлющей поддержкой HTML5 и широкими возможностями конфигурации.

Установка:

pip install html-to-markdown

Базовое использование:

from html_to_markdown import convert

html = """
<article>
    <h1>Техническая документация</h1>
    <table>
        <thead>
            <tr>
                <th>Функция</th>
                <th>Поддержка</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>HTML5</td>
                <td>✓</td>
            </tr>
            <tr>
                <td>Таблицы</td>
                <td>✓</td>
            </tr>
        </tbody>
    </table>
</article>
"""

markdown = convert(html)
print(markdown)

Расширенная конфигурация:

from html_to_markdown import convert, Options

# Создание пользовательских опций
options = Options(
    heading_style="ATX",
    bullet_style="-",
    code_language_default="python",
    strip_tags=["script", "style"],
    escape_special_chars=True,
    table_style="pipe",  # Использование | для таблиц
    preserve_whitespace=False,
    extract_metadata=True,  # Извлечение мета-тегов
)

markdown = convert(html, options=options)

Интерфейс командной строки:

# Конвертация одного файла
html-to-markdown input.html -o output.md

# Конвертация с опциями
html-to-markdown input.html \
    --heading-style atx \
    --strip-tags script,style \
    --extract-metadata

# Пакетная конвертация
find ./html_files -name "*.html" -exec html-to-markdown {} -o ./markdown_files/{}.md \;

Преимущества:

  • Полная поддержка HTML5, включая семантические элементы
  • Типобезопасность с всеобъемлющими аннотациями типов
  • Улучшенная обработка таблиц (объединенные ячейки, выравнивание)
  • Возможности извлечения метаданных
  • Активное развитие и современная кодовая база

Недостатки:

  • Требуется Python 3.9+
  • Больший объем зависимостей
  • Более крутая кривая обучения

Лучше всего подходит для: сложных документов HTML5, типобезопасных проектов, производственных систем


4. trafilatura - Специалист по извлечению контента

trafilatura — это не просто конвертер HTML в Markdown, а интеллектуальная библиотека извлечения контента, специально разработанная для веб-скрейпинга и извлечения статей.

Установка:

pip install trafilatura

Базовое использование:

import trafilatura

# Загрузка и извлечение из URL
url = "https://example.com/article"
downloaded = trafilatura.fetch_url(url)
markdown = trafilatura.extract(downloaded, output_format='markdown')
print(markdown)

Примечание: Trafilatura включает встроенную загрузку URL, но для более сложных HTTP-операций вы можете найти наш cURL Cheatsheet полезным при работе с API или аутентифицированными конечными точками.

Расширенное извлечение контента:

import trafilatura
from trafilatura.settings import use_config

# Создание пользовательской конфигурации
config = use_config()
config.set("DEFAULT", "EXTRACTION_TIMEOUT", "30")

html = """
<html>
<head><title>Название статьи</title></head>
<body>
    <nav>Навигационное меню</nav>
    <article>
        <h1>Основная статья</h1>
        <p>Важный контент здесь.</p>
    </article>
    <aside>Реклама</aside>
    <footer>Контент в подвале</footer>
</body>
</html>
"""

# Извлечение только основного контента
markdown = trafilatura.extract(
    html,
    output_format='markdown',
    include_comments=False,
    include_tables=True,
    include_images=True,
    include_links=True,
    config=config
)

# Извлечение с метаданными
result = trafilatura.extract(
    html,
    output_format='markdown',
    with_metadata=True
)

if result:
    print(f"Название: {result.get('title', 'N/A')}")
    print(f"Автор: {result.get('author', 'N/A')}")
    print(f"Дата: {result.get('date', 'N/A')}")
    print(f"\nКонтент:\n{result.get('text', '')}")

Пакетная обработка:

import trafilatura
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

def process_url(url):
    """Извлечение markdown из URL"""
    downloaded = trafilatura.fetch_url(url)
    if downloaded:
        return trafilatura.extract(
            downloaded,
            output_format='markdown',
            include_links=True,
            include_images=True
        )
    return None

# Обработка нескольких URL параллельно
urls = [
    "https://example.com/article1",
    "https://example.com/article2",
    "https://example.com/article3",
]

with ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(process_url, urls))

for i, markdown in enumerate(results):
    if markdown:
        Path(f"article_{i}.md").write_text(markdown, encoding='utf-8')

Преимущества:

  • Интеллектуальное извлечение контента (удаляет шаблонный контент)
  • Встроенная загрузка URL с надежной обработкой ошибок
  • Извлечение метаданных (название, автор, дата)
  • Детекция языка
  • Оптимизировано для новостных статей и блогов
  • Быстрый C-основанный парсинг

Недостатки:

  • Может удалять слишком много контента для общего HTML
  • Сфокусировано на извлечении статей (не универсальное)
  • Сложность конфигурации для крайних случаев

Лучше всего подходит для: веб-скрейпинга, извлечения статей, подготовки данных для обучения LLM


5. domscribe - Сохранитель семантики

domscribe фокусируется на сохранении семантического смысла HTML при конвертации в Markdown.

Установка:

pip install domscribe

Базовое использование:

from domscribe import html_to_markdown

html = """
<article>
    <header>
        <h1>Понимание семантического HTML</h1>
        <time datetime="2024-10-24">24 октября 2024</time>
    </header>
    <section>
        <h2>Введение</h2>
        <p>Семантический HTML придает <mark>смысл</mark> контенту.</p>
    </section>
    <aside>
        <h3>Связанные темы</h3>
        <ul>
            <li>Доступность</li>
            <li>SEO</li>
        </ul>
    </aside>
</article>
"""

markdown = html_to_markdown(html)
print(markdown)

Пользовательские опции:

from domscribe import html_to_markdown, MarkdownOptions

options = MarkdownOptions(
    preserve_semantic_structure=True,
    include_aria_labels=True,
    strip_empty_elements=True
)

markdown = html_to_markdown(html, options=options)

Преимущества:

  • Сохраняет семантическую структуру HTML5
  • Хорошо обрабатывает современные веб-компоненты
  • Чистый дизайн API

Недостатки:

  • Все еще в ранней стадии разработки (API может измениться)
  • Ограниченная документация по сравнению с проверенными альтернативами
  • Меньшее сообщество и меньше примеров доступны

Лучше всего подходит для: документов HTML5 с семантикой, проектов, ориентированных на доступность, когда сохранение семантической структуры HTML5 критически важно

Примечание: Хотя domscribe новее и менее проверен, чем альтернативы, он заполняет конкретную нишу для сохранения семантики HTML, которую другие инструменты не приоритизируют.


6. html2md - Мощный асинхронный инструмент

html2md разработан для высокопроизводительных пакетных конвертаций с асинхронной обработкой.

Установка:

pip install html2md

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

# Конвертация всего каталога
m1f-html2md convert ./website -o ./docs

# С пользовательскими настройками
m1f-html2md convert ./website -o ./docs \
    --remove-tags nav,footer \
    --heading-offset 1 \
    --detect-language

# Конвертация одного файла
m1f-html2md convert index.html -o readme.md

Программное использование:

import asyncio
from html2md import convert_html

async def convert_files():
    """Асинхронная пакетная конвертация"""
    html_files = [
        'page1.html',
        'page2.html',
        'page3.html'
    ]

    tasks = [convert_html(file) for file in html_files]
    results = await asyncio.gather(*tasks)
    return results

# Запуск конвертации
results = asyncio.run(convert_files())

Преимущества:

  • Асинхронная обработка для высокой производительности
  • Интеллектуальное обнаружение селекторов контента
  • Генерация YAML frontmatter (отлично для Hugo!)
  • Детекция языка кода
  • Поддержка параллельной обработки

Недостатки:

  • Требуется Python 3.10+
  • Ориентирован на CLI (менее гибкий API)
  • Документация могла бы быть более всеобъемлющей

Лучше всего подходит для: масштабных миграций, пакетных конвертаций, миграций Hugo/Jekyll

Производительность и тестирование

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

Сравнительный анализ производительности:

На основе типичных паттернов использования, вот как эти библиотеки сравниваются в трех реалистичных сценариях:

  1. Простой HTML: Базовый блог с текстом, заголовками и ссылками (5КБ)
  2. Сложный HTML: Техническая документация с вложенными таблицами и блоками кода (50КБ)
  3. Реальный сайт: Полная веб-страница, включая навигацию, подвал, боковую панель и рекламу (200КБ)

Вот пример кода для тестирования, который вы можете использовать для проверки этих библиотек самостоятельно:

import time
import html2text
from markdownify import markdownify
from html_to_markdown import convert
import trafilatura

def benchmark(html_content, iterations=100):
    """Тестирование скорости конвертации"""

    # html2text
    start = time.time()
    h = html2text.HTML2Text()
    for _ in range(iterations):
        _ = h.handle(html_content)
    html2text_time = time.time() - start

    # markdownify
    start = time.time()
    for _ in range(iterations):
        _ = markdownify(html_content)
    markdownify_time = time.time() - start

    # html-to-markdown
    start = time.time()
    for _ in range(iterations):
        _ = convert(html_content)
    html_to_markdown_time = time.time() - start

    # trafilatura
    start = time.time()
    for _ in range(iterations):
        _ = trafilatura.extract(html_content, output_format='markdown')
    trafilatura_time = time.time() - start

    return {
        'html2text': html2text_time,
        'markdownify': markdownify_time,
        'html-to-markdown': html_to_markdown_time,
        'trafilatura': trafilatura_time
    }

Типичные характеристики производительности (представительные относительные скорости):

Пакет Простой (5КБ) Сложный (50КБ) Реальный сайт (200КБ)
html2text Умеренная Медленнее Медленнее
markdownify Медленнее Медленнее Самый медленный
html-to-markdown Быстрый Быстрый Быстрый
trafilatura Быстрый Очень быстрый Очень быстрый
html2md (асинхронный) Очень быстрый Очень быстрый Самый быстрый

Ключевые наблюдения:

  • html2md и trafilatura самые быстрые для сложных документов, что делает их идеальными для пакетной обработки
  • html-to-markdown предлагает лучший баланс скорости и функций для производственного использования
  • markdownify медленнее, но наиболее гибкий — компромисс стоит того, когда вам нужны пользовательские обработчики
  • html2text показывает свой возраст с более медленной производительностью, но остается стабильным для простых случаев использования

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


Реальные сценарии использования

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

Сценарий 1: Подготовка данных для обучения LLM

Требование: Извлечение чистого текста из тысяч страниц документации

Рекомендуется: trafilatura + параллельная обработка

import trafilatura
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor

def process_html_file(html_path):
    """Конвертация HTML-файла в markdown"""
    html = Path(html_path).read_text(encoding='utf-8')
    markdown = trafilatura.extract(
        html,
        output_format='markdown',
        include_links=False,  # Удалите для более чистых данных обучения
        include_images=False,
        include_comments=False
    )

    if markdown:
        output_path = html_path.replace('.html', '.md')
        Path(output_path).write_text(markdown, encoding='utf-8')
        return len(markdown)
    return 0

# Обработка 10,000 файлов параллельно
html_files = list(Path('./docs').rglob('*.html'))

with ProcessPoolExecutor(max_workers=8) as executor:
    token_counts = list(executor.map(process_html_file, html_files))

print(f"Обработано {len(html_files)} файлов")
print(f"Общее количество символов: {sum(token_counts):,}")

Сценарий 2: Миграция блога в Hugo

Требование: Миграция блога WordPress в Hugo с frontmatter

Рекомендуется: html2md CLI

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

# Конвертация всех постов с frontmatter
m1f-html2md convert ./wordpress-export \
    -o ./hugo/content/posts \
    --generate-frontmatter \
    --heading-offset 0 \
    --remove-tags script,style,nav,footer

Или программно:

from html_to_markdown import convert, Options
from pathlib import Path
import yaml

def migrate_post(html_file):
    """Конвертация HTML WordPress в markdown Hugo"""
    html = Path(html_file).read_text()

    # Извлечение заголовка и даты из HTML
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'html.parser')
    title = soup.find('h1').get_text() if soup.find('h1') else 'Без названия'

    # Конвертация в markdown
    options = Options(strip_tags=['script', 'style', 'nav', 'footer'])
    markdown = convert(html, options=options)

    # Добавление frontmatter Hugo
    frontmatter = {
        'title': title,
        'date': '2024-10-24',
        'draft': False,
        'tags': []
    }

    output = f"---\n{yaml.dump(frontmatter)}---\n\n{markdown}"

    # Сохранение
    output_file = html_file.replace('.html', '.md')
    Path(output_file).write_text(output, encoding='utf-8')

# Обработка всех постов
for html_file in Path('./wordpress-export').glob('*.html'):
    migrate_post(html_file)

Сценарий 3: Скрейпер документации с пользовательским форматированием

Требование: Скрейпинг технической документации с пользовательской обработкой блоков кода

Рекомендуется: markdownify с пользовательским конвертером

Этот подход особенно полезен для миграции документации из wiki-систем. Если вы управляете документацией, вам также может быть интересно DokuWiki - саморазмещаемый wiki и альтернативы для решений саморазмещаемой документации.

from markdownify import MarkdownConverter
import requests

class DocsConverter(MarkdownConverter):
    """Пользовательский конвертер для технической документации"""

    def convert_pre(self, el, text, convert_as_inline):
        """Улучшенный блок кода с подсветкой синтаксиса"""
        code = el.find('code')
        if code:
            # Извлечение языка из класса
            classes = code.get('class', [])
            language = next(
                (c.replace('language-', '') for c in classes if c.startswith('language-')),
                'text'
            )
            return f'\n```{language}\n{code.get_text()}\n```\n'
        return super().convert_pre(el, text, convert_as_inline)

    def convert_div(self, el, text, convert_as_inline):
        """Обработка специальных блоков документации"""
        classes = el.get('class', [])

        # Блоки предупреждений
        if 'warning' in classes:
            return f'\n> ⚠️ **Предупреждение**: {text}\n'

        # Информационные блоки
        if 'info' in classes or 'note' in classes:
            return f'\n> 💡 **Примечание**: {text}\n'

        return text

def scrape_docs(url):
    """Скрейпинг и конвертация страницы документации"""
    response = requests.get(url)
    markdown = DocsConverter().convert(response.text)
    return markdown

# Использование
docs_url = "https://docs.example.com/api-reference"
markdown = scrape_docs(docs_url)
Path('api-reference.md').write_text(markdown)

Сценарий 4: Архив рассылки в Markdown

Требование: Конвертация HTML-рассылок в читаемый markdown

Рекомендуется: html2text с конкретной конфигурацией

import html2text
import email
from pathlib import Path

def convert_newsletter(email_file):
    """Конвертация HTML-письма в markdown"""
    # Парсинг письма
    with open(email_file, 'r') as f:
        msg = email.message_from_file(f)

    # Получение HTML-части
    html_content = None
    for part in msg.walk():
        if part.get_content_type() == 'text/html':
            html_content = part.get_payload(decode=True).decode('utf-8')
            break

    if not html_content:
        return None

    # Настройка конвертера
    h = html2text.HTML2Text()
    h.ignore_images = False
    h.images_to_alt = True
    h.body_width = 0
    h.protect_links = True
    h.unicode_snob = True

    # Конвертация
    markdown = h.handle(html_content)

    # Добавление метаданных
    subject = msg.get('Subject', 'Без темы')
    date = msg.get('Date', '')

    output = f"# {subject}\n\n*Дата: {date}*\n\n---\n\n{markdown}"

    return output

# Обработка архива рассылок
for email_file in Path('./newsletters').glob('*.eml'):
    markdown = convert_newsletter(email_file)
    if markdown:
        output_file = email_file.with_suffix('.md')
        output_file.write_text(markdown, encoding='utf-8')

Рекомендации по сценариям

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

Для веб-скрейпинга и предварительной обработки LLM

Победитель: trafilatura

Trafilatura преуспевает в извлечении чистого контента, удаляя шаблонные элементы. Идеально для:

  • Создания наборов данных для обучения LLM
  • Агрегации контента
  • Сбора исследовательских статей
  • Извлечения новостных статей

Для миграции Hugo/Jekyll

Победитель: html2md

Асинхронная обработка и генерация frontmatter делают массовые миграции быстрыми и простыми:

  • Пакетные конвертации
  • Автоматическое извлечение метаданных
  • Генерация YAML frontmatter
  • Настройка уровня заголовков

Для пользовательской логики конвертации

Победитель: markdownify

Создавайте подклассы конвертера для полного контроля:

  • Пользовательские обработчики тегов
  • Конвертации, специфичные для домена
  • Специальные требования к форматированию
  • Интеграция с существующим кодом BeautifulSoup

Для типобезопасных производственных систем

Победитель: html-to-markdown

Современный, типобезопасный и функционально полный:

  • Полная поддержка HTML5
  • Подробные аннотации типов
  • Улучшенная обработка таблиц
  • Активное сопровождение

Для простых и стабильных конвертаций

Победитель: html2text

Когда вам нужно что-то, что “просто работает”:

  • Нет зависимостей
  • Проверено в боях
  • Расширенная конфигурация
  • Широкая поддержка платформ

Лучшие практики предварительной обработки LLM

Независимо от выбранной библиотеки, соблюдение этих лучших практик обеспечит высококачественный вывод Markdown, оптимизированный для потребления LLM. Эти шаблоны оказались необходимыми в производственных рабочих процессах, обрабатывающих миллионы документов.

1. Очистка перед преобразованием

Всегда удаляйте ненужные элементы перед преобразованием, чтобы получить более чистый вывод и лучшую производительность:

from bs4 import BeautifulSoup
import trafilatura

def clean_and_convert(html):
    """Удаление ненужных элементов перед преобразованием"""
    soup = BeautifulSoup(html, 'html.parser')

    # Удаление ненужных элементов
    for element in soup(['script', 'style', 'nav', 'footer', 'header', 'aside']):
        element.decompose()

    # Удаление рекламы и трекинга
    for element in soup.find_all(class_=['ad', 'advertisement', 'tracking']):
        element.decompose()

    # Преобразование очищенного HTML
    markdown = trafilatura.extract(
        str(soup),
        output_format='markdown'
    )

    return markdown

2. Нормализация пробелов

Разные конвертеры по-разному обрабатывают пробелы. Нормализуйте вывод, чтобы обеспечить согласованность по всему корпусу:

import re

def normalize_markdown(markdown):
    """Очистка форматирования markdown"""
    # Удаление множественных пустых строк
    markdown = re.sub(r'\n{3,}', '\n\n', markdown)

    # Удаление конечных пробелов
    markdown = '\n'.join(line.rstrip() for line in markdown.split('\n'))

    # Обеспечение одиночного переноса строки в конце
    markdown = markdown.rstrip() + '\n'

    return markdown

3. Проверка вывода

Контроль качества имеет решающее значение. Реализуйте проверку для выявления ошибок преобразования на ранних стадиях:

def validate_markdown(markdown):
    """Проверка качества markdown"""
    issues = []

    # Проверка на остатки HTML
    if '<' in markdown and '>' in markdown:
        issues.append("Обнаружены HTML-теги")

    # Проверка на некорректные ссылки
    if '[' in markdown and ']()' in markdown:
        issues.append("Обнаружена пустая ссылка")

    # Проверка на избыточное количество блоков кода
    code_block_count = markdown.count('```')
    if code_block_count % 2 != 0:
        issues.append("Незакрытый блок кода")

    return len(issues) == 0, issues

4. Шаблон пакетной обработки

При обработке больших коллекций документов используйте этот производственный шаблон с правильной обработкой ошибок, ведением журнала и параллельной обработкой:

from pathlib import Path
from concurrent.futures import ProcessPoolExecutor
import trafilatura
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def process_file(html_path):
    """Обработка одного HTML-файла"""
    try:
        html = Path(html_path).read_text(encoding='utf-8')
        markdown = trafilatura.extract(
            html,
            output_format='markdown',
            include_links=True,
            include_images=False
        )

        if markdown:
            # Нормализация
            markdown = normalize_markdown(markdown)

            # Проверка
            is_valid, issues = validate_markdown(markdown)
            if not is_valid:
                logger.warning(f"{html_path}: {', '.join(issues)}")

            # Сохранение
            output_path = Path(str(html_path).replace('.html', '.md'))
            output_path.write_text(markdown, encoding='utf-8')

            return True

        return False

    except Exception as e:
        logger.error(f"Ошибка при обработке {html_path}: {e}")
        return False

def batch_convert(input_dir, max_workers=4):
    """Преобразование всех HTML-файлов в директории"""
    html_files = list(Path(input_dir).rglob('*.html'))
    logger.info(f"Найдено {len(html_files)} HTML-файлов")

    with ProcessPoolExecutor(max_workers=max_workers) as executor:
        results = list(executor.map(process_file, html_files))

    success_count = sum(results)
    logger.info(f"Успешно преобразовано {success_count}/{len(html_files)} файлов")

# Использование
batch_convert('./html_docs', max_workers=8)

Заключение

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

  • Быстрые преобразования: Используйте html2text за его простоту и отсутствие зависимостей
  • Гибкая логика: Используйте markdownify для максимальной гибкости через подклассификацию
  • Веб-скрейпинг: Используйте trafilatura для интеллектуального извлечения контента с удалением шаблонов
  • Массовые миграции: Используйте html2md для асинхронной производительности в крупных проектах
  • Производственные системы: Используйте html-to-markdown для безопасности типов и всеобъемлющей поддержки HTML5
  • Сохранение семантики: Используйте domscribe для поддержания семантической структуры HTML5

Рекомендации для рабочих процессов LLM

Для рабочих процессов предварительной обработки LLM рекомендуется двухступенчатый подход:

  1. Начните с trafilatura для первоначального извлечения контента — он интеллектуально удаляет навигацию, рекламу и шаблоны, сохраняя основной контент
  2. Используйте html-to-markdown для сложных документов, требующих точного сохранения структуры, таких как техническая документация с таблицами и блоками кода

Это сочетание эффективно решает 95% реальных сценариев.

Следующие шаги

Все эти инструменты (кроме html2text) активно поддерживаются и готовы к производству. Лучше:

  1. Установить 2-3 библиотеки, соответствующие вашему случаю использования
  2. Проверить их с вашими реальными образцами HTML
  3. Замерить производительность с типичными размерами документов
  4. Выбрать на основе качества вывода, а не только скорости

Экосистема Python для преобразования HTML в Markdown значительно созрела, и вы не ошибетесь с любым из этих выборов для их предназначенных случаев использования.

Дополнительные ресурсы

Примечание: Это сравнение основано на анализе официальной документации, обратной связи сообщества и архитектуры библиотек. Характеристики производительности представляют типичные паттерны использования. Для конкретных случаев использования запускайте собственные бенчмарки с вашими реальными образцами HTML.

Другие полезные статьи