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

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

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

Конвертация HTML в Markdown является фундаментальной задачей в современных рабочих процессах разработки, особенно при подготовке веб-контента для крупных языковых моделей (LLM), систем документации или статических генераторов сайтов, таких как Hugo. Это руководство является частью нашего Инструментов документации в 2026 году: Markdown, LaTeX, PDF и рабочие процессы печати хаба.

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

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

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

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

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

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

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

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

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

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

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>Это <strong>комплексное руководство</strong> по извлечению содержимого.</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  # Использовать символы Unicode
h.emphasis_mark = '*'  # Использовать * для выделения вместо _
h.strong_mark = '**'

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

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

Плюсы:

  • Матурный и стабильный (более 15 лет разработки)
  • Широкие возможности настройки
  • Хорошо обрабатывает крайние случаи
  • Нет внешних зависимостей

Минусы:

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

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


2. markdownify - гибкий вариант

markdownify использует BeautifulSoup4 для предоставления гибкой парсинга HTML с настраиваемой обработкой тегов.

Установка:

pip install markdownify

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

from markdownify import markdownify as md

html = """
<article>
    <h2>Современное веб-развитие</h2>
    <p>Строительство с использованием <code>Python</code> и <em>современных фреймворков</em>.</p>
    <blockquote>
        <p>Простота — это верхнее совершенство.</p>
    </blockquote>
</article>
"""

markdown = md(html)
print(markdown)

Выходные данные:


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

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

> Простота — это верхнее совершенство.

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

from markdownify import MarkdownConverter

class CustomConverter(MarkdownConverter):
    """
    Создание пользовательского конвертера с конкретной обработкой тегов
    """
    def convert_img(self, el, text, convert_as_inline):
        """Пользовательский обработчик изображений с альт-текстом"""
        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:
            # Извлечь язык из атрибута класса (например, '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 полезным при работе с 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 и узнайте о добавлении структурированных данных в Hugo для лучшего SEO. В нашем хабе инструментов документации есть больше руководств по рабочим процессам Markdown и конвертации документов.

# Конвертировать все посты с 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% реальных сценариев.

Дальнейшие действия

Для получения дополнительных руководств по обработке Markdown, LaTeX, PDF и печати документов см. Инструменты документации 2026: Markdown, LaTeX, PDF и рабочие процессы печати.

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

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

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

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

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

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