Convertir HTML en Markdown avec Python : Un guide complet
Python pour convertir HTML en Markdown propre et prêt à l'utilisation par un LLM
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.

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 :
- Efficacité des tokens : Le Markdown utilise nettement moins de tokens que le HTML pour le même contenu
- Clarté sémantique : Le Markdown préserve la structure du document sans balises verbeuses
- Lisibilité : À la fois les humains et les LLM peuvent facilement analyser la syntaxe Markdown
- Consistance : Le format standardisé réduit l’ambiguïté des entrées du modèle
- 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''
return f''
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 :
- HTML simple : Article de blog basique avec du texte, des titres et des liens (5KB)
- HTML complexe : Documentation technique avec des tableaux imbriqués et des blocs de code (50KB)
- 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 :
html2mdettrafilaturasont les plus rapides pour les documents complexes, les rendant idéaux pour le traitement en lotshtml-to-markdownoffre le meilleur équilibre entre vitesse et fonctionnalités pour l’utilisation en productionmarkdownifyest plus lent mais le plus flexible — le compromis est justifié lorsque vous avez besoin de gestionnaires personnaliséshtml2textmontre 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
html2textpour sa simplicité et l’absence de dépendances - Logique personnalisée : Utilisez
markdownifypour la flexibilité maximale grâce à la sous-classification - Scraping web : Utilisez
trafilaturapour l’extraction intelligente du contenu avec suppression des éléments superflus - Migrations en masse : Utilisez
html2mdpour les performances asynchrones sur de grands projets - Systèmes de production : Utilisez
html-to-markdownpour la sécurité typée et le support complet de HTML5 - Préservation sémantique : Utilisez
domscribepour 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 :
- Commencer par
trafilaturapour 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 - Passer à
html-to-markdownpour 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 :
- Installer 2 à 3 bibliothèques correspondant à votre cas d’utilisation
- Les tester avec vos échantillons HTML réels
- Benchmarker les performances avec vos tailles de documents typiques
- 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
- Documentation html2text
- markdownify sur PyPI
- html-to-markdown sur GitHub
- Documentation trafilatura
- Documentation html2md
- domscribe sur PyPI
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
- Feuille de triche Markdown
- Utilisation des blocs de code Markdown
- Convertir des documents Word en Markdown : un guide complet
- Convertir du contenu HTML en Markdown à l’aide d’un LLM et d’Ollama
- Feuille de triche cURL
- Feuille de triche Hugo - générateur de site statique
- Ajouter des balises structurées à Hugo
- Dokuwiki - wiki autohébergé et alternatives
- Utiliser Obsidian pour la gestion de la connaissance personnelle