Aller au contenu
Développement medium

Extraire du contenu web pour un pipeline RAG

11 min de lecture

Logo Trafilatura

Construire un RAG commence par collecter le contenu à indexer. Si ce contenu est sur le web, le télécharger ne suffit pas : une page HTML mêle l'article utile à des menus, des publicités et des pieds de page. Indexer ce bruit dégrade tout le reste du pipeline. Trafilatura résout cette première étape : il isole le contenu principal d'une page et le rend en texte propre ou en Markdown, avec ses métadonnées — titre, auteur, date. Ce guide montre comment extraire une page, récupérer ses métadonnées, traiter un lot d'URL et constituer un corpus prêt pour l'indexation. Public visé : développeur qui prépare les données d'un RAG.

  • Pourquoi le HTML brut est inexploitable pour un RAG.
  • Extraire le contenu principal d'une page en texte ou en Markdown.
  • Récupérer les métadonnées : titre, auteur, date.
  • Arbitrer entre précision et rappel selon l'usage.
  • Traiter un lot d'URL et écrire un corpus sur disque.
  • Python 3.10+ et les bases de la manipulation de fichiers.
  • Ce guide ouvre le parcours RAG — utile pour situer cette étape.

Télécharger une page web, c'est récupérer du HTML brut. Dedans, l'article que vous visez côtoie une navigation, des bannières publicitaires, des encarts latéraux, un pied de page légal, sans compter le JavaScript et le CSS.

Pour un RAG, ce mélange est toxique. Chaque morceau de menu ou de publicité indexé devient un chunk parasite : vos recherches sémantiques remontent des fragments de navigation au lieu du contenu pertinent. La qualité d'un RAG se joue dès cette étape — un corpus sale produit un RAG sale.

Il faut donc une étape d'extraction du contenu principal : repérer, dans le HTML, le bloc qui porte l'information, et jeter le reste.

Repérer le contenu principal « à la main » — avec des sélecteurs CSS — est fragile : chaque site a une structure différente, et elle change. Trafilatura fait ce travail par des heuristiques robustes, indépendantes du site : densité de texte, balises sémantiques, longueur des blocs.

Trois atouts en font un bon choix pour un pipeline RAG. Il extrait proprement sans configuration par site. Il récupère les métadonnées — titre, auteur, date — utiles pour tracer et filtrer. Et il rend plusieurs formats — texte, Markdown, JSON — directement exploitables par l'étape suivante.

Trafilatura s'installe dans un environnement virtuel, comme tout projet Python.

Fenêtre de terminal
python3 -m venv .venv
source .venv/bin/activate
pip install trafilatura==2.0.0 lxml-html-clean==0.4.5

Le second paquet, lxml-html-clean, n'est pas optionnel. Depuis la version 6 de lxml, le module html.clean a été sorti dans un paquet séparé ; une dépendance interne de Trafilatura en a besoin. Sans lui, le simple import trafilatura échoue.

En production, on télécharge la page avec fetch_url, puis on l'extrait avec extract. Pour un lab reproductible, on travaille sur un fichier HTML local — l'extraction est identique.

import trafilatura
def extraire_texte(html: str) -> str:
"""Extrait le contenu principal d'une page HTML en texte propre."""
return trafilatura.extract(html) or ""

extract renvoie le texte du contenu principal — ou None si la page n'a rien d'exploitable, d'où le or "" qui garantit toujours une chaîne. Sur une page d'article noyée dans un menu, une publicité et un pied de page, la sortie ne contient que l'article :

Un conteneur Docker est éphémère : dès qu'il est supprimé, tout ce qu'il
contenait disparaît. Pour conserver des données au-delà de la vie d'un
conteneur, Docker fournit les volumes...

Le menu, la bannière « PROMOTION », le pied de page « Mentions légales » ont disparu — sans qu'on ait écrit un seul sélecteur CSS.

Pour télécharger une vraie page, on enchaîne fetch_url et extract :

html = trafilatura.fetch_url("https://exemple.fr/article")
texte = extraire_texte(html)

Le texte seul ne suffit pas : un corpus RAG a besoin de tracer d'où vient chaque document — pour citer ses sources, filtrer par date, attribuer un auteur. Trafilatura extrait ces métadonnées en demandant le format JSON.

import json
def extraire_donnees(html: str) -> dict:
"""Extrait le contenu et ses métadonnées (titre, auteur, date)."""
brut = trafilatura.extract(html, output_format="json", with_metadata=True)
if not brut:
return {}
donnees = json.loads(brut)
return {
"titre": donnees.get("title"),
"auteur": donnees.get("author"),
"date": donnees.get("date"),
"texte": donnees.get("text", ""),
}

L'option with_metadata=True demande à Trafilatura de joindre les métadonnées ; le format json les renvoie dans une structure facile à parser. Le résultat est un dictionnaire propre, prêt à être stocké :

Titre : Comprendre les volumes Docker
Auteur : Équipe Infrastructure
Date : 2026-03-12

Le texte brut aplatit tout : titres, listes et paragraphes se confondent. Pour un RAG, garder la structure aide — un découpage par sections (vu dans le guide sur le chunking) s'appuie dessus. Le format markdown préserve cette hiérarchie.

def extraire_markdown(html: str) -> str:
"""Extrait le contenu principal en Markdown — titres et listes conservés."""
return trafilatura.extract(html, output_format="markdown") or ""

La sortie garde les # de titres et les puces de liste. C'est le format à privilégier quand le chunking structurel est prévu en aval.

Toute extraction arbitre entre deux risques : laisser passer du bruit, ou jeter du contenu utile. Trafilatura expose ce réglage par deux options.

Le mode précisionfavor_precision=True — est strict : il ne garde que ce dont il est sûr. Moins de bruit, mais quelques passages utiles peuvent être écartés. C'est le bon défaut pour un RAG : un index propre vaut mieux qu'un index complet mais bruité.

Le mode rappelfavor_recall=True — est permissif : il garde le maximum de contenu, au risque de laisser entrer du bruit. Utile quand rien ne doit être perdu, et qu'un nettoyage suivra.

# Pour un RAG : on privilégie un corpus propre.
texte = trafilatura.extract(html, favor_precision=True)

Un corpus se constitue rarement page par page. Le schéma habituel est une boucle sur une liste d'URL : télécharger, extraire, collecter.

def constituer_corpus(urls: list[str]) -> list[dict]:
"""Télécharge et extrait une liste d'URL en documents structurés."""
corpus = []
for url in urls:
html = trafilatura.fetch_url(url)
if html is None:
continue # page injoignable : on passe à la suivante
donnees = extraire_donnees(html)
if donnees.get("texte"):
donnees["source"] = url
corpus.append(donnees)
return corpus

Deux précautions comptent. On ignore les pages injoignables plutôt que de planter tout le lot. Et on conserve l'URL source dans chaque document — c'est elle que le RAG citera plus tard.

L'étape se termine en écrivant le corpus sur disque — un format que l'étape de nettoyage, puis de chunking, viendra lire.

import json
from pathlib import Path
def ecrire_corpus(corpus: list[dict], dossier: str) -> None:
"""Écrit chaque document du corpus dans un fichier JSON."""
base = Path(dossier)
base.mkdir(parents=True, exist_ok=True)
for i, document in enumerate(corpus):
(base / f"doc_{i:03d}.json").write_text(
json.dumps(document, ensure_ascii=False, indent=2),
encoding="utf-8",
)

Un fichier JSON par document, avec son texte et ses métadonnées : c'est un corpus simple, inspectable, et stable pour la suite du pipeline. La prochaine étape — le nettoyage — partira de ces fichiers.

SymptômeCause probableSolution
ImportError: lxml.html.cleanPaquet lxml-html-clean absentL'installer en plus de Trafilatura
extract renvoie NonePage sans contenu principal détectableEssayer favor_recall=True
fetch_url renvoie NonePage injoignable, bloquée ou hors ligneIgnorer l'URL, vérifier le réseau
Du bruit dans le texte extraitMode rappel trop permissifPasser en favor_precision=True
Métadonnées videsPage sans balises meta exploitablesAccepter les champs absents, ne pas planter
  • Le HTML brut mêle l'article au bruit ; l'indexer dégrade tout le RAG.
  • Trafilatura isole le contenu principal par heuristiques, sans configuration par site.
  • extract rend du texte, du Markdown ou du JSON avec métadonnées.
  • Pour un RAG, privilégier la précision — un corpus propre plutôt que complet.
  • Un traitement par lot ignore les pages injoignables et conserve l'URL source.
  • Le corpus s'écrit sur disque, un JSON par document, prêt pour le nettoyage.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn