Analyse et extraction de données HTML/XML avec Beautiful Soup 4

Introduction à Beautiful Soup 4

Beautiful Soup est une bibliothèque Python largement utilisée pour extraire des informations à partir de fichiers HTML et XML. Bien que la version 3 ait existé par le passé, la version actuelle et recommandée est Beautiful Soup 4 (BS4).

Pour commencer, installez la bibliothèque via pip :

pip install beautifulsoup4

Beautiful Soup nécessite un analyseur (parser) pour traiter le code source. Bien que Python inclue html.parser par défaut, l'utilisation de lxml est fortement recommandée pour sa rapidité et sa flexibilité :

pip install lxml

Concepts de base et types d'objets

BS4 transforme un document complexe en une structure d'objets Python imbriqués. On distingue principalement quatre types d'objets :

1. L'objet Tag

Un objet Tag correspond à une balise HTML ou XML réelle. Par exemple, dans <b class="titre">Hello</b>, le tag est "b".

  • Name : Accessible via tag.name. Il est possible de le modifier pour refléter un changement dans l'arbre syntaxique.
  • Attributes : Les attributs d'une balise se manipulent comme un dictionnaire Python. tag['class'] renverra la valeur de l'attribut.

2. NavigableString

Il s'agit du texte contenu à l'intérieur d'une balise. On y accède via tag.string. Contrairement à une chaîne de caractères classique, cet objet supporte certaines fonctionnalités de navigation de Beautiful Soup.

3. BeautifulSoup

C'est l'objet racine qui représente l'intégralité du document analysé. Il se comporte globalement comme un objet Tag.

Exemples pratiques de manipulation

Voici comment initialiser l'analyse d'un document :

from bs4 import BeautifulSoup

html_doc = """
<div id="main">
    <p class="description">Bienvenue sur notre site</p>
    <a href="http://example.com/1" class="lien" id="link1">Lien 1</a>
    <a href="http://example.com/2" class="lien" id="link2">Lien 2</a>
</div>
"""

# Création de l'objet soup
analyseur = BeautifulSoup(html_doc, 'lxml')

Recherche d'éléments avec find_all()

La méthode find_all() parcourt les descendants d'un tag et récupère tous ceux qui correspondent aux filtres appliqués.

# Trouver toutes les balises 'a'
tous_les_liens = analyseur.find_all('a')

# Utilisation d'une liste pour plusieurs types de balises
elements = analyseur.find_all(['p', 'a'])

# Recherche par attribut spécifique
lien_specifique = analyseur.find_all(id="link2")

Le cas particulier de l'attribut "class"

Puisque class est un mot-clé réservé en Python, Beautiful Soup utilise l'argument class_ pour filtrer par classe CSS :

# Trouver les balises avec la classe 'lien'
liens_css = analyseur.find_all("a", class_="lien")

Navigation avancée et filtres

Il est possible de filtrer les résultats en utilisant des dictionnaires pour des attributs personnalisés (comme data-* en HTML5) :

# Recherche avec un dictionnaire d'attributs
bloc = analyseur.find_all("div", attrs={"id": "main"})

Pour limiter la recherche aux enfants directs (sans descendre dans toute l'arborescence), utilisez l'argument recursive :

# Ne cherche que parmi les enfants directs
resultats = analyseur.find_all("p", recursive=False)

Navigation dans l'arborescence

Beautiful Soup permet de se déplacer horizontalement ou verticalement dans le DOM :

  • Parent : find_parent() et find_parents() permettent de remonter vers les éléments ancêtres.
  • Frères (Siblings) : find_next_sibling() et find_previous_sibling() accèdent aux éléments situés au même niveau hiérarchique.
  • Directionnel : find_next() cherche l'élément suivant dans l'ordre de lecture du document, qu'il soit un frère ou non.

Extraction de texte brut

Pour récupérer uniquement le contenu textuel d'un élément ou d'un document, la méthode get_text() est la plus efficace. Elle concatène tout le texte des fils de manière récursive :

contenu_global = analyseur.get_text()
# On peut spécifier un séparateur
texte_propre = analyseur.div.get_text(separator=" | ")

La différence majeure entre .string et get_text() est que .string renvoie None si la balise contient plusieurs sous-balises, alors que get_text() récupère l'intégralité du contenu visible.

Étiquettes: Python beautifulsoup4 web-scraping html-parsing lxml

Publié le 9 juin à 23h03