
Vous construisez un système RAG et avez besoin d’extraire du contenu web propre ? Trafilatura résout ce problème : il télécharge une page HTML, supprime automatiquement les menus, publicités, footers et autres éléments parasites, puis vous retourne uniquement le texte utile — avec les métadonnées (titre, auteur, date) prêtes pour l’indexation.
Ce guide vous montre comment utiliser Trafilatura 2.0.0 en Python, de l’extraction basique jusqu’à la constitution d’un corpus complet pour RAG.
Le problème : le HTML brut est inutilisable
Section intitulée « Le problème : le HTML brut est inutilisable »Quand vous téléchargez une page web, vous récupérez du HTML brut contenant :
- Le contenu utile (l’article que vous voulez)
- Des menus de navigation
- Des publicités et trackers
- Des sidebars, footers, pop-ups
- Du JavaScript et du CSS
Pour un pipeline RAG, ce bruit dégrade la qualité de votre index vectoriel. Vos recherches sémantiques retournent des fragments de menus ou de publicités au lieu du contenu pertinent.
Pourquoi Trafilatura plutôt qu’une autre bibliothèque ?
Section intitulée « Pourquoi Trafilatura plutôt qu’une autre bibliothèque ? »| Critère | Trafilatura | BeautifulSoup | newspaper3k |
|---|---|---|---|
| Extraction intelligente | ✓ Automatique | ✗ Manuelle (CSS selectors) | ✓ Limité |
| Métadonnées | ✓ Titre, auteur, date | ✗ | ✓ Partiel |
| Export JSON | ✓ Natif | ✗ | ✗ |
| Langues non-anglaises | ✓ Excellent | N/A | ✗ Anglais-centré |
| Déduplication | ✓ Simhash intégré | ✗ | ✗ |
| Sitemaps/RSS | ✓ Intégré | ✗ | ✗ |
BeautifulSoup est puissant mais nécessite d’écrire des sélecteurs CSS/XPath pour chaque site. newspaper3k est abandonné et fonctionne mal sur les sites non-anglophones. Trafilatura offre une extraction “plug and play” qui fonctionne sur la majorité des sites.
Installation
Section intitulée « Installation »-
Créez un environnement virtuel pour isoler les dépendances :
Fenêtre de terminal python -m venv venvsource venv/bin/activate # Linux/macOS# ou: venv\Scripts\activate # Windows -
Installez Trafilatura avec toutes les dépendances optionnelles :
Fenêtre de terminal pip install "trafilatura[all]" lxml_html_cleanLe package
lxml_html_cleanest requis depuis la version 2.0. -
Vérifiez l’installation :
Fenêtre de terminal trafilatura --versionVous devriez voir :
Trafilatura 2.0.0 - Python 3.12.x
Première extraction : en ligne de commande
Section intitulée « Première extraction : en ligne de commande »Avant de coder, testez Trafilatura en ligne de commande pour comprendre ce qu’il fait.
Extraire le texte d’une page
Section intitulée « Extraire le texte d’une page »trafilatura -u "https://fr.wikipedia.org/wiki/Python_(langage)"Résultat : Trafilatura affiche uniquement le contenu de l’article Wikipedia, sans les menus, sidebars ou footers. Vous obtenez plusieurs milliers de caractères de texte propre.
Obtenir les métadonnées en JSON
Section intitulée « Obtenir les métadonnées en JSON »Pour un pipeline RAG, vous avez besoin du texte et des métadonnées :
trafilatura -u "https://fr.wikipedia.org/wiki/Python_(langage)" --jsonRésultat : Un objet JSON structuré :
{ "title": "Python (langage)", "author": null, "date": "2025-02-10", "text": "Python est un langage de programmation...", "source": "https://fr.wikipedia.org/wiki/Python_(langage)", "hostname": "fr.wikipedia.org"}Vous avez maintenant le titre, la date, la source — tout ce qu’il faut pour enrichir vos chunks lors de l’indexation.
Conserver la structure en Markdown
Section intitulée « Conserver la structure en Markdown »Si vous voulez garder les titres et les listes :
trafilatura -u "https://fr.wikipedia.org/wiki/Python_(langage)" --markdownRésultat : Le texte avec la hiérarchie ##, ###, les listes à puces, etc.
Utile si votre chunker exploite la structure du document.
Utilisation en Python : les fondamentaux
Section intitulée « Utilisation en Python : les fondamentaux »La ligne de commande est utile pour tester, mais en production vous utiliserez l’API Python.
Étape 1 : Télécharger et extraire une page
Section intitulée « Étape 1 : Télécharger et extraire une page »from trafilatura import fetch_url, extract
# 1. Télécharger le HTMLurl = "https://fr.wikipedia.org/wiki/Python_(langage)"html = fetch_url(url)
# 2. Extraire le textetexte = extract(html)
# 3. Afficher un aperçuprint(f"Longueur: {len(texte)} caractères")print(texte[:500])Ce que fait ce code :
fetch_url()télécharge la page et retourne le HTML brutextract()analyse le HTML et retourne uniquement le contenu textuel- Vous obtenez une chaîne de caractères prête à être découpée en chunks
Étape 2 : Récupérer les métadonnées
Section intitulée « Étape 2 : Récupérer les métadonnées »Pour un pipeline RAG, le texte seul ne suffit pas. Vous avez besoin de la source, de la date, du titre — ces métadonnées permettent de filtrer les résultats et d’afficher des citations.
import jsonfrom trafilatura import fetch_url, extract
url = "https://fr.wikipedia.org/wiki/Python_(langage)"html = fetch_url(url)
# Extraire en JSON avec les métadonnéesresultat = extract( html, output_format="json", with_metadata=True)
# Parser le JSONdata = json.loads(resultat)
print(f"Titre: {data['title']}")print(f"Date: {data['date']}")print(f"Source: {data['source']}")print(f"Texte ({len(data['text'])} car.): {data['text'][:200]}...")Sortie attendue :
Titre: Python (langage)Date: 2025-02-10Source: https://fr.wikipedia.org/wiki/Python_\(langage\)Texte (45231 car.): Python est un langage de programmation...Étape 3 : Conserver la structure (Markdown)
Section intitulée « Étape 3 : Conserver la structure (Markdown) »Si votre stratégie de chunking exploite la structure du document (découper par sections), exportez en Markdown :
from trafilatura import fetch_url, extract
url = "https://fr.wikipedia.org/wiki/Python_(langage)"html = fetch_url(url)
markdown = extract(html, output_format="markdown")
# Afficher les premières lignesfor ligne in markdown.split('\n')[:20]: print(ligne)Résultat : Les titres sont préfixés par ##, ###, les listes sont
formatées — vous pouvez découper par section.
Affiner l’extraction : les options essentielles
Section intitulée « Affiner l’extraction : les options essentielles »Selon votre cas d’usage, vous pouvez ajuster ce que Trafilatura extrait.
Inclure les liens hypertextes
Section intitulée « Inclure les liens hypertextes »Par défaut, les liens sont supprimés. Pour les conserver (utile pour la navigation ou les citations) :
texte = extract(html, include_links=True)Résultat : Les liens apparaissent au format [texte](url) dans la sortie.
Inclure les tableaux
Section intitulée « Inclure les tableaux »Les tableaux sont inclus par défaut, mais vous pouvez les désactiver si vous ne les voulez pas :
texte = extract(html, include_tables=False)Précision vs Rappel : le compromis qualité/quantité
Section intitulée « Précision vs Rappel : le compromis qualité/quantité »Pour un pipeline RAG où la qualité prime :
# Mode précision : moins de bruit, idéal pour RAGtexte = extract(html, favor_precision=True)Pour des pages complexes où vous voulez tout récupérer :
# Mode rappel : plus de contenu, risque de bruittexte = extract(html, favor_recall=True)Recommandation RAG : Utilisez favor_precision=True par défaut. Le bruit
dans votre index vectoriel dégrade la pertinence des recherches.
Combinaison des options
Section intitulée « Combinaison des options »Voici la configuration recommandée pour un pipeline RAG :
resultat = extract( html, output_format="json", # Format structuré with_metadata=True, # Titre, date, source include_links=True, # Conserver les références include_tables=True, # Inclure les tableaux favor_precision=True # Minimiser le bruit)Traiter plusieurs pages à la fois
Section intitulée « Traiter plusieurs pages à la fois »Extraire une page, c’est bien. Extraire 500 pages pour constituer un corpus, c’est mieux. Trafilatura offre des outils pour le batch processing.
Téléchargement parallèle
Section intitulée « Téléchargement parallèle »import jsonfrom trafilatura import extractfrom trafilatura.downloads import ( add_to_compressed_dict, buffered_downloads, load_download_buffer)
# Liste des URLs à traiterurls = [ "https://fr.wikipedia.org/wiki/Python_(langage)", "https://fr.wikipedia.org/wiki/JavaScript", "https://fr.wikipedia.org/wiki/Rust_(langage)",]
# Préparer le gestionnaire d'URLsurl_store = add_to_compressed_dict(urls)bufferlist, url_store = load_download_buffer(url_store, sleep_time=1)
# Télécharger en parallèle (4 threads)corpus = []for url, html_content in buffered_downloads(bufferlist, download_threads=4): if html_content: resultat = extract(html_content, output_format="json", with_metadata=True) if resultat: corpus.append(json.loads(resultat)) print(f"✓ {url}")
print(f"\n{len(corpus)} documents extraits")Ce que fait ce code :
add_to_compressed_dict()crée un store optimisé pour les URLsload_download_buffer()prépare les téléchargements avec un délai de 1sbuffered_downloads()télécharge en parallèle (4 threads ici)- Chaque page est extraite et ajoutée au corpus
Découvrir automatiquement les URLs d’un site
Section intitulée « Découvrir automatiquement les URLs d’un site »Plutôt que de lister manuellement les URLs, Trafilatura peut explorer un site.
Via le sitemap :
from trafilatura import sitemap_search
# Récupérer toutes les URLs du sitemapurls = sitemap_search("https://blog.stephane-robert.info")print(f"{len(urls)} URLs trouvées dans le sitemap")Via les flux RSS :
from trafilatura import feeds_search
# Récupérer les URLs des flux RSSurls = feeds_search("https://blog.stephane-robert.info")print(f"{len(urls)} URLs trouvées dans les flux RSS")Via le crawler :
from trafilatura.spider import focused_crawler
# Explorer le site (max 50 pages)urls_trouvees = focused_crawler( "https://blog.stephane-robert.info", max_seen_urls=50, max_known_urls=100)print(f"{len(urls_trouvees)} URLs découvertes par le crawler")Éviter les doublons avec Simhash
Section intitulée « Éviter les doublons avec Simhash »Quand vous crawlez un site, vous pouvez récupérer plusieurs fois le même contenu (pages dupliquées, versions multiples). Trafilatura intègre Simhash pour détecter les doublons.
Comment fonctionne Simhash ?
Section intitulée « Comment fonctionne Simhash ? »Simhash calcule une empreinte du contenu. Deux textes similaires auront des empreintes proches. En comparant les empreintes, vous détectez les doublons sans comparer caractère par caractère.
from trafilatura.deduplication import Simhash
# Créer des empreintestexte1 = "Python est un langage de programmation interprété"texte2 = "Python est un langage de programmation interprété" # Identiquetexte3 = "JavaScript est un langage de programmation" # Différent
hash1 = Simhash(texte1)hash2 = Simhash(texte2)hash3 = Simhash(texte3)
# Comparer les similaritésprint(f"Similarité 1-2: {hash1.similarity(hash2)}") # 1.0 (identique)print(f"Similarité 1-3: {hash1.similarity(hash3)}") # ~0.6 (différent)Intégrer la déduplication dans votre pipeline
Section intitulée « Intégrer la déduplication dans votre pipeline »from trafilatura import fetch_url, extractfrom trafilatura.deduplication import Simhash
SEUIL_DOUBLON = 0.95 # 95% de similarité = doublon
urls = [ "https://example.com/article-v1", "https://example.com/article-v2", # Peut être un doublon "https://example.com/autre-article",]
hashes_vus = []corpus = []
for url in urls: html = fetch_url(url) texte = extract(html)
if texte: # Calculer l'empreinte hash_contenu = Simhash(texte)
# Vérifier si c'est un doublon est_doublon = any( hash_contenu.similarity(h) > SEUIL_DOUBLON for h in hashes_vus )
if not est_doublon: hashes_vus.append(hash_contenu) corpus.append({"url": url, "texte": texte}) print(f"✓ Ajouté: {url}") else: print(f"✗ Doublon ignoré: {url}")
print(f"\n{len(corpus)} documents uniques")Pipeline complet : de l’URL au corpus RAG
Section intitulée « Pipeline complet : de l’URL au corpus RAG »Voici un script complet qui combine tout ce que nous avons vu :
import jsonfrom pathlib import Pathfrom trafilatura import fetch_url, extract, sitemap_searchfrom trafilatura.deduplication import Simhash
def creer_corpus_rag( site_url: str, output_dir: str = "corpus", max_pages: int = 100) -> list[dict]: """ Crée un corpus RAG à partir d'un site web.
1. Découvre les URLs via le sitemap 2. Extrait le contenu avec métadonnées 3. Déduplique automatiquement 4. Sauvegarde en JSON """ output_path = Path(output_dir) output_path.mkdir(exist_ok=True)
# 1. Découvrir les URLs print(f"Découverte des URLs de {site_url}...") urls = sitemap_search(site_url) urls = list(urls)[:max_pages] print(f" {len(urls)} URLs à traiter")
# 2. Extraire et dédupliquer hashes_vus = [] documents = [] SEUIL = 0.95
for i, url in enumerate(urls): print(f"[{i+1}/{len(urls)}] {url[:60]}...")
try: html = fetch_url(url) if not html: print(" ✗ Échec téléchargement") continue
resultat = extract( html, output_format="json", with_metadata=True, include_links=True, favor_precision=True )
if not resultat: print(" ✗ Pas de contenu") continue
data = json.loads(resultat) texte = data.get("text", "")
# Déduplication hash_contenu = Simhash(texte) if any(hash_contenu.similarity(h) > SEUIL for h in hashes_vus): print(" ✗ Doublon") continue
hashes_vus.append(hash_contenu)
# Structurer le document doc = { "id": f"doc_{i:04d}", "source": url, "title": data.get("title", "Sans titre"), "author": data.get("author"), "date": data.get("date"), "text": texte, }
documents.append(doc)
# Sauvegarder fichier = output_path / f"{doc['id']}.json" fichier.write_text(json.dumps(doc, ensure_ascii=False, indent=2)) print(f" ✓ {doc['title'][:40]}...")
except Exception as e: print(f" ✗ Erreur: {e}")
# 3. Créer l'index index = { "site": site_url, "total": len(documents), "documents": [ {"id": d["id"], "title": d["title"], "source": d["source"]} for d in documents ] } (output_path / "index.json").write_text( json.dumps(index, ensure_ascii=False, indent=2) )
print(f"\n{'='*50}") print(f"Corpus créé: {len(documents)} documents") print(f"Sauvegardé dans: {output_path}")
return documents
# Utilisationif __name__ == "__main__": docs = creer_corpus_rag( "https://blog.stephane-robert.info", output_dir="corpus_devops", max_pages=50 )Configuration avancée
Section intitulée « Configuration avancée »Utiliser la classe Extractor
Section intitulée « Utiliser la classe Extractor »Pour réutiliser une configuration sur plusieurs extractions :
from trafilatura import fetch_url, extractfrom trafilatura.settings import Extractor
# Configuration réutilisableconfig = Extractor( output_format="json", links=True, # Équivaut à include_links tables=True, # Équivaut à include_tables precision=True, # Équivaut à favor_precision with_metadata=True)
# Utiliser sur plusieurs pagesfor url in urls: html = fetch_url(url) resultat = extract(html, options=config)Accès direct aux métadonnées avec bare_extraction
Section intitulée « Accès direct aux métadonnées avec bare_extraction »Pour un accès programmatique sans passer par JSON :
from trafilatura import fetch_urlfrom trafilatura.core import bare_extraction
html = fetch_url("https://example.com/article")doc = bare_extraction(html, with_metadata=True)
# Accès direct aux attributsprint(doc.title)print(doc.author)print(doc.date)print(doc.text[:200])Dépannage
Section intitulée « Dépannage »”ImportError: lxml_html_clean”
Section intitulée « ”ImportError: lxml_html_clean” »pip install lxml_html_cleanCette dépendance est requise depuis Trafilatura 2.0.
Extraction vide sur certaines pages
Section intitulée « Extraction vide sur certaines pages »Causes possibles :
- La page nécessite JavaScript (Trafilatura ne l’exécute pas)
- Le contenu est derrière un paywall
- Le User-Agent est bloqué
Solutions :
- Essayez avec
favor_recall=Truepour être moins strict - Pour JavaScript : téléchargez d’abord avec Playwright/Selenium, puis passez
le HTML à
extract() - Configurez un User-Agent personnalisé dans un fichier
settings.cfg
Pages très longues : timeout
Section intitulée « Pages très longues : timeout »texte = extract(html, max_tree_size=5000000)Augmente la limite de taille de l’arbre DOM.