Débutant en data ? parse XML using Python étape par étape

XML structure des données sous forme d’arborescence, avec des balises imbriquées qui décrivent à la fois le contenu et sa hiérarchie. Python dispose de plusieurs modules pour lire, parcourir et extraire ces données sans écrire de logique de parsing manuel. Cet article explique comment parse XML using Python en partant de la bibliothèque standard, puis en élargissant aux cas où le document provient du web.

Structure d’un document XML : balises, éléments et attributs

Un document XML repose sur une arborescence. Chaque noeud est un element délimité par une balise ouvrante et une balise fermante. Un element peut contenir du texte, des attributs (paires clé-valeur dans la balise ouvrante) et d’autres elements enfants.

A découvrir également : Ce qui façonne le développement web en 2024

Prenons un exemple minimal que le reste de l’article réutilisera :

<catalog><book id="1"><title>Python Data</title><price>29.99</price></book><book id="2"><title>Web Scraping</title><price>34.50</price></book></catalog>

A lire aussi : Installing Python with pip pour la data science : installer les bons modules

Ici, catalog est l’element racine. Chaque book possède un attribut id et deux enfants : title et price. Comprendre cette hiérarchie est le prérequis avant d’écrire la moindre ligne de code Python.

Parser du XML avec ElementTree en Python

Le module xml.etree.ElementTree fait partie de la bibliothèque standard. Aucune installation supplémentaire. Il couvre la majorité des besoins pour du XML bien formé.

Charger le document

Deux fonctions d’entrée existent : ET.parse() pour un fichier local, ET.fromstring() pour une chaîne de caractères. Dans les deux cas, le résultat donne accès à l’element racine.

import xml.etree.ElementTree as ET
tree = ET.parse('catalog.xml')
root = tree.getroot()

La variable root est un objet Element. À partir de là, tout le parcours se fait par itération sur les enfants.

Parcourir et extraire avec find et iter

La méthode find retourne le premier element correspondant au tag cherché. findall retourne une liste. iter parcourt récursivement toute l’arborescence.

for book in root.findall('book'):
    title = book.find('title').text
    price = book.find('price').text
    book_id = book.get('id')

La propriété .text récupère le contenu textuel d’un element. La méthode .get() récupère la valeur d’un attribut. Ce duo couvre la plupart des extractions courantes.

Développeur masculin analysant des fichiers XML avec Python sur deux écrans dans un bureau open space moderne

Traiter du XML récupéré depuis le web avec requests

Beaucoup de flux de donnees (RSS, API publiques, sitemaps) servent du XML via une URL. Le module requests télécharge le contenu, puis ElementTree le parse.

import requests
response = requests.get('https://example.com/feed.xml')
root = ET.fromstring(response.content)

Deux points à surveiller ici. D’abord, utiliser response.content (bytes) plutôt que response.text (str) pour laisser le parser gérer l’encodage déclaré dans le document XML. Ensuite, vérifier le code HTTP avant de parser :

if response.status_code == 200:
    root = ET.fromstring(response.content)

Cette approche fonctionne pour tout document XML accessible par URL, y compris les sitemaps de page web que l’on souhaite analyser.

BeautifulSoup pour du XML mal formé ou mixte HTML-XML

ElementTree exige un document XML strictement valide. Face à du contenu mal formé, des balises non fermées ou un mélange HTML/XML, BeautifulSoup (module beautifulsoup4, souvent importé sous bs4) offre une tolérance bien supérieure.

from bs4 import BeautifulSoup
soup = BeautifulSoup(xml_content, 'lxml-xml')

Le parser lxml-xml traite le contenu comme du XML. Pour du HTML, on utiliserait 'html.parser' ou 'lxml'. La distinction est réelle : le mode XML respecte la casse des balises, le mode HTML la normalise.

BeautifulSoup expose des méthodes proches d’ElementTree mais avec une syntaxe légèrement différente :

  • soup.find('title') retourne le premier element title trouvé, comme un appel find classique
  • soup.find_all('book') renvoie une liste de tous les elements book du document
  • element.get_text() extrait le contenu text d’un element, en ignorant les balises enfants
  • element['id'] accède directement à un attribut, comme un dictionnaire Python

Pour du scraper de flux RSS ou de pages web hybrides, BeautifulSoup reste le choix le plus pragmatique. La contrepartie : il faut installer beautifulsoup4 et lxml via pip, là où ElementTree ne demande rien.

Erreurs fréquentes quand on débute le parsing XML en Python

Certaines erreurs reviennent systématiquement lors des premiers essais. Les identifier en amont fait gagner du temps.

  • Oublier les namespaces XML : beaucoup de documents déclarent un namespace par défaut. Sans le préfixer dans les appels find ou findall, ElementTree ne trouve aucun element. La syntaxe est root.findall('{http://namespace-uri}tag')
  • Confondre .text et .tail : dans ElementTree, le texte qui suit la balise fermante d’un element (avant la balise suivante) est stocké dans .tail, pas dans .text. Ignorer cette distinction produit des extractions incomplètes
  • Parser du HTML avec un parser XML : un document HTML classique n’est presque jamais du XML valide. ElementTree lèvera une exception. Il faut alors passer par BeautifulSoup avec le parser html adapté

Vue aérienne d'un bureau de programmeur avec un IDE Python affichant du code de parsing XML et des notes manuscrites

Choisir entre ElementTree et BeautifulSoup pour parser du XML

Le choix dépend du document source. ElementTree convient pour du XML propre, généré par une application ou un service structuré (API REST, fichiers de configuration, sitemaps). Aucune dépendance externe, performance correcte, code lisible.

BeautifulSoup prend le relais quand le document est douteux : flux RSS mal encodés, contenu mixte récupéré par un scraper, pages web converties. Sa tolérance aux erreurs de balisage justifie la dépendance supplémentaire.

Dans un projet data, les deux cohabitent sans problème. ElementTree pour les sources fiables, BeautifulSoup pour tout le reste. La logique d’extraction (boucle for, appels find, accès au text et aux attributs) reste quasiment identique d’un module à l’autre, ce qui facilite le passage de l’un à l’autre selon le type de document rencontré.