Convertir HTML en Markdown avec Python : Un guide complet

Python pour convertir HTML en Markdown propre et prêt à l'utilisation par un LLM

Sommaire

Conversion de HTML en Markdown est une tâche fondamentale dans les workflows de développement modernes, particulièrement lors de la préparation du contenu web pour les grands modèles de langage (LLM), les systèmes de documentation ou les générateurs de sites statiques comme Hugo.

Bien que le HTML ait été conçu pour les navigateurs web avec un style et une structure riches, le Markdown offre un format propre et lisible, idéal pour le traitement du texte, le contrôle de version et la consommation par l’IA. Si vous débutez avec la syntaxe Markdown, consultez notre Feuille de rappel Markdown pour un référentiel complet.

infographie : conversion d’une page de HTML en Markdown

Dans ce examen complet, nous explorerons six bibliothèques Python pour la conversion HTML en Markdown, en fournissant des exemples de code pratiques, des benchmarks de performance et des cas d’utilisation réels. Que vous construisez un pipeline de formation d’un LLM, migrez un blog vers Hugo ou extrayez des documents, vous trouverez le meilleur outil pour votre workflow.

Approche alternative : Si vous avez besoin d’une extraction de contenu plus intelligente avec une compréhension sémantique, vous pouvez également envisager la conversion de HTML en Markdown à l’aide d’un LLM et d’Ollama, qui propose une conversion alimentée par l’IA pour les dispositions complexes.

Ce que vous apprendrez :

  • Comparaison détaillée de 6 bibliothèques avec les avantages/inconvénients de chacune
  • Benchmarks de performance avec des exemples d’HTML réels
  • Exemples de code prêts pour la production pour des cas d’utilisation courants
  • Bonnes pratiques pour les workflows de prétraitement des LLM
  • Recommandations spécifiques en fonction de vos besoins

Pourquoi le Markdown pour le prétraitement des LLM ?

Avant de plonger dans les outils, comprenons pourquoi le Markdown est particulièrement précieux pour les workflows des LLM :

  1. Efficacité des tokens : Le Markdown utilise nettement moins de tokens que le HTML pour le même contenu
  2. Clarté sémantique : Le Markdown préserve la structure du document sans balises verbeuses
  3. Lisibilité : À la fois les humains et les LLM peuvent facilement analyser la syntaxe Markdown
  4. Consistance : Le format standardisé réduit l’ambiguïté des entrées du modèle
  5. Stockage : Tailles de fichiers plus petites pour les données d’entraînement et les fenêtres de contexte

La polyvalence du Markdown dépasse la conversion HTML : vous pouvez également convertir des documents Word en Markdown pour les workflows de documentation, ou l’utiliser dans des systèmes de gestion des connaissances comme Obsidian pour la gestion des connaissances personnelles.

TL;DR - Matrice de comparaison rapide

Si vous êtes pressé, voici une comparaison complète des six bibliothèques en un coup d’œil. Ce tableau vous aidera à identifier rapidement quel outil correspond à vos besoins spécifiques :

Fonctionnalité html2text markdownify html-to-markdown trafilatura domscribe html2md
Support HTML5 Partiel Partiel Complet Complet Complet Complet
Indications de type Non Non Oui Partiel Non Partiel
Gestionnaires personnalisés Limité Excellent Bon Limité Bon Limité
Support des tableaux Basique Basique Avancé Bon Bon Bon
Support asynchrone Non Non Non Non Non Oui
Extraction du contenu Non Non Non Excellent Non Bon
Extraction des métadonnées Non Non Oui Excellent Non Oui
Outil CLI Non Non Oui Oui Non Oui
Vitesse Moyenne Lente Rapide Très rapide Moyenne Très rapide
Développement actif Non Oui Oui Oui Limité Oui
Version Python 3.6+ 3.7+ 3.9+ 3.6+ 3.8+ 3.10+
Dépendances Aucune BS4 lxml lxml BS4 aiohttp

Guide de sélection rapide :

  • Besoin de vitesse ? → trafilatura ou html2md
  • Besoin de personnalisation ? → markdownify
  • Besoin de sécurité de type ? → html-to-markdown
  • Besoin de simplicité ? → html2text
  • Besoin d’extraction de contenu ? → trafilatura

Les candidats : 6 bibliothèques Python comparées

Plongeons profondément dans chaque bibliothèque avec des exemples de code pratiques, des options de configuration et des insights du monde réel. Chaque section inclut des instructions d’installation, des schémas d’utilisation et des évaluations honnêtes des forces et des limites.

1. html2text - Le choix classique

Initialement développé par Aaron Swartz, html2text a été un pilier de l’écosystème Python depuis plus d’une décennie. Il se concentre sur la production de sortie Markdown propre et lisible.

Installation :

pip install html2text

Utilisation de base :

import html2text

# Créer une instance de convertisseur
h = html2text.HTML2Text()

# Configurer les options
h.ignore_links = False
h.ignore_images = False
h.ignore_emphasis = False
h.body_width = 0  # Ne pas enrouler les lignes

html_content = """
<h1>Bienvenue dans le Web Scraping</h1>
<p>Ceci est un <strong>guide complet</strong> pour extraire du contenu.</p>
<ul>
    <li>Facile à utiliser</li>
    <li>Bien testé</li>
    <li>Très adopté</li>
</ul>
<a href="https://example.com">En savoir plus</a>
"""

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

Sortie :

# Bienvenue dans le Web Scraping

Ceci est un **guide complet** pour extraire du contenu.

  * Facile à utiliser
  * Bien testé
  * Très adopté

[En savoir plus](https://example.com)

Configuration avancée :

import html2text

h = html2text.HTML2Text()

# Ignorer certains éléments
h.ignore_links = True
h.ignore_images = True

# Contrôler le formatage
h.body_width = 80  # Enrouler à 80 caractères
h.unicode_snob = True  # Utiliser les caractères unicode
h.emphasis_mark = '*'  # Utiliser * pour l'accentuation au lieu de _
h.strong_mark = '**'

# Gérer les tableaux
h.ignore_tables = False

# Protéger le texte pré-formaté
h.protect_links = True

Avantages :

  • Mature et stable (plus de 15 ans de développement)
  • Options de configuration étendues
  • Gère bien les cas limites
  • Aucune dépendance externe

Inconvénients :

  • Support HTML5 limité
  • Peut produire un espacement incohérent
  • Pas activement maintenu (dernière mise à jour majeure en 2020)
  • Traitement uniquement en mode synchrone

Meilleur pour : Documents HTML simples, systèmes hérités, lorsque la stabilité est primordiale


2. markdownify - L’option flexible

markdownify utilise BeautifulSoup4 pour fournir un parsing HTML flexible avec une gestion personnalisée des balises.

Installation :

pip install markdownify

Utilisation de base :

from markdownify import markdownify as md

html = """
<article>
    <h2>Développement web moderne</h2>
    <p>Construire avec <code>Python</code> et <em>des cadres modernes</em>.</p>
    <blockquote>
        <p>La simplicité est la sophistication ultime.</p>
    </blockquote>
</article>
"""

markdown = md(html)
print(markdown)

Sortie :


## Développement web moderne

Construire avec `Python` et *des cadres modernes*.

> La simplicité est la sophistication ultime.

Utilisation avancée avec des gestionnaires personnalisés :

from markdownify import MarkdownConverter

class CustomConverter(MarkdownConverter):
    """
    Créer un convertisseur personnalisé avec une gestion spécifique des balises
    """
    def convert_img(self, el, text, convert_as_inline):
        """Gestionnaire personnalisé des images avec le texte alternatif"""
        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):
        """Gestion renforcée des blocs de code avec détection de la langue"""
        code = el.find('code')
        if code:
            # Extraire la langue à partir de l'attribut de classe (ex. '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'

# Utiliser le convertisseur personnalisé
html = '<pre><code class="language-python">def hello():\n    print("world")</code></pre>'
markdown = CustomConverter().convert(html)
print(markdown)

Pour plus de détails sur l’utilisation des blocs de code Markdown et la mise en surbrillance de la syntaxe, consultez notre guide sur L’utilisation des blocs de code Markdown.

Conversion sélective des balises :

from markdownify import markdownify as md

# Supprimer entièrement certaines balises
markdown = md(html, strip=['script', 'style', 'nav'])

# Convertir uniquement certaines balises
markdown = md(
    html,
    heading_style="ATX",  # Utiliser # pour les titres
    bullets="-",  # Utiliser - pour les éléments de liste
    strong_em_symbol="*",  # Utiliser * pour l'accentuation
)

Avantages :

  • Construit sur BeautifulSoup4 (analyse HTML robuste)
  • Très personnalisable par héritage
  • Maintenance active
  • Bonne documentation

Inconvénients :

  • Dépendance BeautifulSoup4 requise
  • Peut être plus lent pour de grands documents
  • Support de table limité

Meilleur pour : Logique de conversion personnalisée, projets utilisant déjà BeautifulSoup4


3. html-to-markdown - Le puissant outil moderne

html-to-markdown est une bibliothèque moderne entièrement typée avec un support complet de HTML5 et des options de configuration étendues.

Installation :

pip install html-to-markdown

Utilisation de base :

from html_to_markdown import convert

html = """
<article>
    <h1>Documentation technique</h1>
    <table>
        <thead>
            <tr>
                <th>Fonctionnalité</th>
                <th>Support</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>HTML5</td>
                <td>✓</td>
            </tr>
            <tr>
                <td>Tableaux</td>
                <td>✓</td>
            </tr>
        </tbody>
    </table>
</article>
"""

markdown = convert(html)
print(markdown)

Configuration avancée :

from html_to_markdown import convert, Options

# Créer des options personnalisées
options = Options(
    heading_style="ATX",
    bullet_style="-",
    code_language_default="python",
    strip_tags=["script", "style"],
    escape_special_chars=True,
    table_style="pipe",  # Utiliser | pour les tableaux
    preserve_whitespace=False,
    extract_metadata=True,  # Extraire les balises meta
)

markdown = convert(html, options=options)

Interface en ligne de commande :

# Convertir un seul fichier
html-to-markdown input.html -o output.md

# Convertir avec des options
html-to-markdown input.html \
    --heading-style atx \
    --strip-tags script,style \
    --extract-metadata

# Conversion en lot
find ./html_files -name "*.html" -exec html-to-markdown {} -o ./markdown_files/{}.md \;

Avantages :

  • Support complet de HTML5 y compris les éléments sémantiques
  • Sécurité de type avec des indices de type complets
  • Gestion renforcée des tableaux (cellules fusionnées, alignement)
  • Capacités d’extraction de métadonnées
  • Développement actif et codebase moderne

Inconvénients :

  • Requiert Python 3.9+
  • Plus grande empreinte de dépendance
  • Courbe d’apprentissage plus raide

Meilleur pour : Documents HTML5 complexes, projets typés, systèmes de production


4. trafilatura - Le spécialiste de l’extraction de contenu

trafilatura n’est pas seulement un convertisseur HTML en Markdown — c’est une bibliothèque intelligente d’extraction de contenu spécifiquement conçue pour le web scraping et l’extraction d’articles.

Installation :

pip install trafilatura

Utilisation de base :

import trafilatura

# Télécharger et extraire à partir d'une URL
url = "https://example.com/article"
downloaded = trafilatura.fetch_url(url)
markdown = trafilatura.extract(downloaded, output_format='markdown')
print(markdown)

Note : Trafilatura inclut une téléchargeur intégré, mais pour des opérations HTTP plus complexes, vous pouvez trouver notre Feuille de rappel cURL utile lors du travail avec des API ou des points de terminaison authentifiés.

Extraction avancée du contenu :

import trafilatura
from trafilatura.settings import use_config

# Créer une configuration personnalisée
config = use_config()
config.set("DEFAULT", "EXTRACTION_TIMEOUT", "30")

html = """
<html>
<head><title>Titre de l'article</title></head>
<body>
    <nav>Menu de navigation</nav>
    <article>
        <h1>Article principal</h1>
        <p>Contenu important ici.</p>
    </article>
    <aside>Publicité</aside>
    <footer>Contenu du pied de page</footer>
</body>
</html>
"""

# Extraire uniquement le contenu principal
markdown = trafilatura.extract(
    html,
    output_format='markdown',
    include_comments=False,
    include_tables=True,
    include_images=True,
    include_links=True,
    config=config
)

# Extraire avec les métadonnées
result = trafilatura.extract(
    html,
    output_format='markdown',
    with_metadata=True
)

if result:
    print(f"Titre : {result.get('title', 'N/A')}")
    print(f"Auteur : {result.get('author', 'N/A')}")
    print(f"Date : {result.get('date', 'N/A')}")
    print(f"\nContenu:\n{result.get('text', '')}")

Traitement en lot :

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

def process_url(url):
    """Extraire le markdown à partir d'une URL"""
    downloaded = trafilatura.fetch_url(url)
    if downloaded:
        return trafilatura.extract(
            downloaded,
            output_format='markdown',
            include_links=True,
            include_images=True
        )
    return None

# Traiter plusieurs URLs en parallèle
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')

Avantages :

  • Extraction intelligente du contenu (supprime les éléments superflus)
  • Téléchargement intégré avec une gestion robuste des erreurs
  • Extraction des métadonnées (titre, auteur, date)
  • Détection de la langue
  • Optimisé pour les articles de presse et les blogs
  • Parsing rapide basé sur C

Inconvénients :

  • Peut supprimer trop de contenu pour le HTML général
  • Axé sur l’extraction d’articles (non généraliste)
  • Complexité de configuration pour les cas limites

Meilleur pour : Web scraping, extraction d’articles, préparation des données d’entraînement des LLM


5. domscribe - Le conservateur de signification sémantique

domscribe se concentre sur la préservation de la signification sémantique de l’HTML lors de la conversion en Markdown.

Installation :

pip install domscribe

Utilisation de base :

from domscribe import html_to_markdown

html = """
<article>
    <header>
        <h1>Comprendre le HTML sémantique</h1>
        <time datetime="2024-10-24">24 octobre 2024</time>
    </header>
    <section>
        <h2>Introduction</h2>
        <p>Le HTML sémantique donne <mark>un sens</mark> au contenu.</p>
    </section>
    <aside>
        <h3>Sujets liés</h3>
        <ul>
            <li>Accessibilité</li>
            <li>SEO</li>
        </ul>
    </aside>
</article>
"""

markdown = html_to_markdown(html)
print(markdown)

Options personnalisées :

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)

Avantages :

  • Préservation de la structure HTML5 sémantique
  • Gestion bien des composants web modernes
  • Conception d’API propre

Inconvénients :

  • Toujours en développement initial (l’API peut changer)
  • Documentation limitée par rapport aux alternatives matures
  • Communauté plus petite et moins d’exemples disponibles

Meilleur pour : Documents HTML5 sémantiques, projets axés sur l’accessibilité, lorsque la préservation de la structure sémantique HTML5 est critique

Note : Bien que domscribe soit plus récent et moins testé que les alternatives, il remplit un besoin spécifique de préservation du HTML sémantique que d’autres outils ne privilégient pas.


6. html2md - Le puissant outil asynchrone

html2md est conçu pour des conversions de grande performance en lots avec un traitement asynchrone.

Installation :

pip install html2md

Utilisation en ligne de commande :

# Convertir un répertoire entier
m1f-html2md convert ./website -o ./docs

# Avec des paramètres personnalisés
m1f-html2md convert ./website -o ./docs \
    --remove-tags nav,footer \
    --heading-offset 1 \
    --detect-language

# Convertir un seul fichier
m1f-html2md convert index.html -o readme.md

Utilisation programmable :

import asyncio
from html2md import convert_html

async def convert_files():
    """Conversion asynchrone en lot"""
    html_files = [
        'page1.html',
        'page2.html',
        'page3.html'
    ]

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

# Lancer la conversion
results = asyncio.run(convert_files())

Avantages :

  • Traitement asynchrone pour une haute performance
  • Détection intelligente du sélecteur de contenu
  • Génération de métadonnées YAML (parfait pour Hugo !)
  • Détection de la langue de code
  • Support de traitement parallèle

Inconvénients :

  • Requiert Python 3.10+
  • CLI orienté (moins d’API flexible)
  • Documentation pouvant être plus complète

Meilleur pour : Migrations à grande échelle, conversions en lots, migrations Hugo/Jekyll


Benchmarks de performance

La performance compte, surtout lorsqu’on traite des milliers de documents pour l’entraînement des LLM ou des migrations à grande échelle. Comprendre les différences relatives de vitesse entre les bibliothèques vous aide à prendre des décisions éclairées pour votre workflow.

Analyse comparative de performance :

Sur la base des schémas d’utilisation typiques, voici comment ces bibliothèques se comparent dans trois scénarios réalistes :

  1. HTML simple : Article de blog basique avec du texte, des titres et des liens (5KB)
  2. HTML complexe : Documentation technique avec des tableaux imbriqués et des blocs de code (50KB)
  3. Site web réel : Page web complète incluant la navigation, le pied de page, la barre latérale et les publicités (200KB)

Voici un exemple de code de benchmark que vous pouvez utiliser pour tester ces bibliothèques vous-même :

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

def benchmark(html_content, iterations=100):
    """Benchmark de vitesse de conversion"""

    # 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
    }

Caractéristiques de performance typiques (vitesses relatives représentatives) :

Package Simple (5KB) Complexe (50KB) Site réel (200KB)
html2text Modérée Plus lente Plus lente
markdownify Plus lente Plus lente La plus lente
html-to-markdown Rapide Rapide Rapide
trafilatura Rapide Très rapide Très rapide
html2md (asynchrone) Très rapide Très rapide La plus rapide

Observations clés :

  • html2md et trafilatura sont les plus rapides pour les documents complexes, les rendant idéaux pour le traitement en lots
  • html-to-markdown offre le meilleur équilibre entre vitesse et fonctionnalités pour l’utilisation en production
  • markdownify est plus lent mais le plus flexible — le compromis est justifié lorsque vous avez besoin de gestionnaires personnalisés
  • html2text montre son âge avec une performance plus lente, mais reste stable pour les cas d’utilisation simples

Note : Les différences de performance deviennent significatives uniquement lorsqu’on traite des centaines ou des milliers de fichiers. Pour des conversions occasionnelles, toute bibliothèque fonctionnera bien. Concentrez-vous sur les fonctionnalités et les options de personnalisation.

Cas d’utilisation réels

La théorie est utile, mais des exemples concrets démontrent comment ces outils fonctionnent en production. Voici quatre scénarios courants avec du code complet et prêt pour la production que vous pouvez adapter à vos propres projets.

Cas d’utilisation 1 : Préparation des données d’entraînement LLM

Exigence : Extraire du texte propre à partir de milliers de pages de documentation

Recommandé : trafilatura + traitement parallèle

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

def process_html_file(html_path):
    """Convertir un fichier HTML en markdown"""
    html = Path(html_path).read_text(encoding='utf-8')
    markdown = trafilatura.extract(
        html,
        output_format='markdown',
        include_links=False,  # Supprimer pour des données d'entraînement plus propres
        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

# Traiter 10 000 fichiers en parallèle
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"Traité {len(html_files)} fichiers")
print(f"Total de caractères : {sum(token_counts):,}")

Cas d’utilisation 2 : Migration de blog Hugo

Exigence : Migrer un blog WordPress vers Hugo avec des frontmatter

Recommandé : html2md CLI

Hugo est un générateur de site statique populaire qui utilise Markdown pour le contenu. Pour plus de conseils spécifiques à Hugo, consultez notre Feuille de triche Hugo et découvrez comment ajouter des balises structurées à Hugo pour une meilleure SEO.

# Convertir tous les posts avec des frontmatter
m1f-html2md convert ./wordpress-export \
    -o ./hugo/content/posts \
    --generate-frontmatter \
    --heading-offset 0 \
    --remove-tags script,style,nav,footer

Ou de manière programmée :

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

def migrate_post(html_file):
    """Convertir un HTML WordPress en markdown Hugo"""
    html = Path(html_file).read_text()

    # Extraire le titre et la date depuis le HTML
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'html.parser')
    title = soup.find('h1').get_text() if soup.find('h1') else 'Sans titre'

    # Convertir en markdown
    options = Options(strip_tags=['script', 'style', 'nav', 'footer'])
    markdown = convert(html, options=options)

    # Ajouter le frontmatter Hugo
    frontmatter = {
        'title': title,
        'date': '2024-10-24',
        'draft': False,
        'tags': []
    }

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

    # Sauvegarder
    output_file = html_file.replace('.html', '.md')
    Path(output_file).write_text(output, encoding='utf-8')

# Traiter tous les posts
for html_file in Path('./wordpress-export').glob('*.html'):
    migrate_post(html_file)

Cas d’utilisation 3 : Scraper de documentation avec un formatage personnalisé

Exigence : Scraper des documents techniques avec un traitement personnalisé des blocs de code

Recommandé : markdownify avec un convertisseur personnalisé

Cette approche est particulièrement utile pour migrer la documentation depuis des systèmes de wiki. Si vous gérez de la documentation, vous pourriez également être intéressé par DokuWiki - wiki autohébergé et alternatives pour des solutions de documentation autohébergées.

from markdownify import MarkdownConverter
import requests

class DocsConverter(MarkdownConverter):
    """Convertisseur personnalisé pour la documentation technique"""

    def convert_pre(self, el, text, convert_as_inline):
        """Bloc de code amélioré avec mise en évidence de la syntaxe"""
        code = el.find('code')
        if code:
            # Extraire la langue depuis la classe
            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):
        """Gérer les blocs spécifiques de documentation"""
        classes = el.get('class', [])

        # Blocs d'avertissement
        if 'warning' in classes:
            return f'\n> ⚠️ **Avertissement** : {text}\n'

        # Blocs d'information
        if 'info' in classes or 'note' in classes:
            return f'\n> 💡 **Note** : {text}\n'

        return text

def scrape_docs(url):
    """Scraper et convertir une page de documentation"""
    response = requests.get(url)
    markdown = DocsConverter().convert(response.text)
    return markdown

# Utilisation
docs_url = "https://docs.example.com/api-reference"
markdown = scrape_docs(docs_url)
Path('api-reference.md').write_text(markdown)

Cas d’utilisation 4 : Newsletter vers archive Markdown

Exigence : Convertir des newsletters HTML en markdown lisible

Recommandé : html2text avec une configuration spécifique

import html2text
import email
from pathlib import Path

def convert_newsletter(email_file):
    """Convertir une newsletter HTML en markdown"""
    # Parser l'email
    with open(email_file, 'r') as f:
        msg = email.message_from_file(f)

    # Obtenir le contenu 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

    # Configurer le convertisseur
    h = html2text.HTML2Text()
    h.ignore_images = False
    h.images_to_alt = True
    h.body_width = 0
    h.protect_links = True
    h.unicode_snob = True

    # Convertir
    markdown = h.handle(html_content)

    # Ajouter les métadonnées
    subject = msg.get('Subject', 'Aucun sujet')
    date = msg.get('Date', '')

    output = f"# {subject}\n\n*Date : {date}*\n\n---\n\n{markdown}"

    return output

# Traiter l'archive des newsletters
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')

Recommandations par scénario

Vous ne savez toujours pas quel bibliothèque choisir ? Voici mon guide définitif basé sur des cas d’utilisation spécifiques. Ces recommandations proviennent d’une expérience pratique avec chaque bibliothèque dans des environnements de production.

Pour le scraping web et le prétraitement LLM

Gagnant : trafilatura

Trafilatura excelle dans l’extraction de contenu propre tout en supprimant les éléments superflus. Idéal pour :

  • Créer des jeux de données d’entraînement LLM
  • Agrégation de contenu
  • Collecte d’articles de recherche
  • Extraction d’articles de presse

Pour les migrations Hugo/Jekyll

Gagnant : html2md

Le traitement asynchrone et la génération de frontmatter rendent les migrations en masse rapides et faciles :

  • Conversions en lots
  • Extraction automatique des métadonnées
  • Génération de frontmatter YAML
  • Ajustement des niveaux d’en-tête

Pour la logique de conversion personnalisée

Gagnant : markdownify

Sous-classez le convertisseur pour avoir un contrôle complet :

  • Gestion personnalisée des balises
  • Conversions spécifiques à un domaine
  • Exigences de formatage spéciales
  • Intégration avec le code BeautifulSoup existant

Pour les systèmes de production typés

Gagnant : html-to-markdown

Moderne, typé et complet en termes de fonctionnalités :

  • Support complet de HTML5
  • Indications de type complètes
  • Gestion avancée des tableaux
  • Maintenance active

Pour des conversions simples et stables

Gagnant : html2text

Lorsque vous avez besoin de quelque chose qui “fonctionne” :

  • Aucune dépendance
  • Testé et éprouvé
  • Configuration extensive
  • Support large des plateformes

Bonnes pratiques pour le prétraitement LLM

Quelle que soit la bibliothèque que vous choisissez, suivre ces bonnes pratiques assurera une sortie Markdown de qualité optimisée pour la consommation par les LLM. Ces modèles se sont avérés essentiels dans les flux de travail de production traitant des millions de documents.

1. Nettoyer avant la conversion

Supprimez toujours les éléments indésirables avant la conversion pour obtenir une sortie plus propre et une meilleure performance :

from bs4 import BeautifulSoup
import trafilatura

def clean_and_convert(html):
    """Supprimer les éléments indésirables avant la conversion"""
    soup = BeautifulSoup(html, 'html.parser')

    # Supprimer les éléments indésirables
    for element in soup(['script', 'style', 'nav', 'footer', 'header', 'aside']):
        element.decompose()

    # Supprimer les publicités et le suivi
    for element in soup.find_all(class_=['ad', 'advertisement', 'tracking']):
        element.decompose()

    # Convertir le HTML nettoyé
    markdown = trafilatura.extract(
        str(soup),
        output_format='markdown'
    )

    return markdown

2. Normaliser les espaces blancs

Les convertisseurs gèrent les espaces blancs différemment. Normalisez la sortie pour assurer la cohérence à travers votre corpus :

import re

def normalize_markdown(markdown):
    """Nettoyer l'espacement markdown"""
    # Supprimer les lignes vides multiples
    markdown = re.sub(r'\n{3,}', '\n\n', markdown)

    # Supprimer les espaces blancs en fin de ligne
    markdown = '\n'.join(line.rstrip() for line in markdown.split('\n'))

    # Assurer une seule ligne vide à la fin
    markdown = markdown.rstrip() + '\n'

    return markdown

3. Valider la sortie

Le contrôle de qualité est essentiel. Implémentez une validation pour détecter les erreurs de conversion précocement :

def validate_markdown(markdown):
    """Valider la qualité du markdown"""
    issues = []

    # Vérifier les restes d'HTML
    if '<' in markdown and '>' in markdown:
        issues.append("Tags HTML détectés")

    # Vérifier les liens brisés
    if '[' in markdown and ']()' in markdown:
        issues.append("Lien vide détecté")

    # Vérifier les blocs de code excessifs
    code_block_count = markdown.count('```')
    if code_block_count % 2 != 0:
        issues.append("Bloc de code non fermé")

    return len(issues) == 0, issues

4. Modèle de traitement par lots

Lorsque vous traitez de grandes collections de documents, utilisez ce modèle prêt pour la production avec une gestion correcte des erreurs, du journalisation et du traitement parallèle :

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):
    """Traiter un seul fichier 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:
            # Normaliser
            markdown = normalize_markdown(markdown)

            # Valider
            is_valid, issues = validate_markdown(markdown)
            if not is_valid:
                logger.warning(f"{html_path}: {', '.join(issues)}")

            # Sauvegarder
            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"Erreur lors du traitement de {html_path}: {e}")
        return False

def batch_convert(input_dir, max_workers=4):
    """Convertir tous les fichiers HTML dans un répertoire"""
    html_files = list(Path(input_dir).rglob('*.html'))
    logger.info(f"Trouvé {len(html_files)} fichiers HTML")

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

    success_count = sum(results)
    logger.info(f"Converti avec succès {success_count}/{len(html_files)} fichiers")

# Utilisation
batch_convert('./html_docs', max_workers=8)

Conclusion

L’écosystème Python propose des outils mûrs et prêts pour la production pour la conversion HTML-to-Markdown, chacun optimisé pour des scénarios différents. Votre choix doit s’aligner sur vos besoins spécifiques :

  • Conversions rapides : Utilisez html2text pour sa simplicité et l’absence de dépendances
  • Logique personnalisée : Utilisez markdownify pour la flexibilité maximale grâce à la sous-classification
  • Scraping web : Utilisez trafilatura pour l’extraction intelligente du contenu avec suppression des éléments superflus
  • Migrations en masse : Utilisez html2md pour les performances asynchrones sur de grands projets
  • Systèmes de production : Utilisez html-to-markdown pour la sécurité typée et le support complet de HTML5
  • Préservation sémantique : Utilisez domscribe pour la préservation de la structure sémantique HTML5

Recommandations pour les workflows LLM

Pour les workflows de prétraitement LLM, il est recommandé d’adopter une approche à deux niveaux :

  1. Commencer par trafilatura pour l’extraction initiale du contenu – il supprime intelligemment les éléments de navigation, les publicités et les éléments superflus tout en préservant le contenu principal
  2. Passer à html-to-markdown pour les documents complexes nécessitant une préservation précise de la structure, tels que la documentation technique avec des tableaux et des blocs de code

Cette combinaison gère efficacement 95 % des scénarios réels.

Étapes suivantes

Tous ces outils (sauf html2text) sont activement maintenus et prêts pour la production. Il est préférable de :

  1. Installer 2 à 3 bibliothèques correspondant à votre cas d’utilisation
  2. Les tester avec vos échantillons HTML réels
  3. Benchmarker les performances avec vos tailles de documents typiques
  4. Choisir en fonction de la qualité de la sortie, pas seulement de la vitesse

L’écosystème Python pour la conversion HTML-to-Markdown a mûri considérablement, et vous ne pouvez pas vous tromper avec l’un de ces choix pour leurs cas d’utilisation respectifs.

Ressources supplémentaires

Note : Cette comparaison est basée sur l’analyse de la documentation officielle, des retours de la communauté et de l’architecture des bibliothèques. Les caractéristiques de performance sont représentatives des schémas d’utilisation typiques. Pour les cas d’utilisation spécifiques, exécutez vos propres benchmarks avec vos propres échantillons HTML.

Autres articles utiles