Python et collecte de données

Web scraping avec Python : extraire des données efficacement

Le web scraping permet de transformer des pages web en jeux de données exploitables. Bien mené, il devient un outil de veille, d'analyse et d'automatisation particulièrement utile pour suivre des prix, constituer des bases produits, enrichir des études ou alimenter des tableaux de bord. Encore faut-il savoir récupérer l'information proprement, sans surcharger les sites ni produire des données fragiles.

Niveau : débutant à intermédiaire | Outils : Requests, BeautifulSoup, Scrapy, Playwright | Mise à jour : mars 2026

Comprendre le web scraping

Le web scraping consiste à récupérer automatiquement des données présentes sur des pages web pour les transformer en informations structurées. Dans les faits, il s'agit souvent de télécharger le code HTML d'une page, d'identifier les éléments utiles, puis de les extraire dans un format plus simple à manipuler, comme un tableau CSV, un fichier JSON ou une base SQLite.

Cette pratique ne relève pas seulement de la programmation. Elle touche aussi à l'observation du web, à la qualité des données, à la logique métier et au respect des conditions d'usage du site exploré. Un bon script n'est pas uniquement un script qui fonctionne une fois. C'est un script qui résiste aux variations mineures de la page, qui échoue proprement lorsqu'un élément manque, et qui limite son impact sur le serveur distant.

Définition utile Scraper ne signifie pas aspirer tout un site sans discernement. L'objectif réaliste est d'extraire une information précise, dans un périmètre clair, avec un rythme mesuré et une logique de stockage exploitable.

Les cas d'usage sont nombreux : veille tarifaire, suivi de publications, récupération d'annonces, constitution d'un corpus textuel, analyse concurrentielle, enrichissement d'un catalogue, surveillance d'indicateurs publics, ou encore collecte de données pour entraîner ou tester des modèles. Il existe toutefois une différence importante entre consulter une page pour un usage humain et en extraire massivement les données pour un usage automatisé. Cette différence impose de la méthode.

Préparer un scraping propre et durable

Avant même d'écrire une ligne de Python, il convient d'examiner trois dimensions : la structure de la page, l'origine réelle des données et le cadre d'usage. De nombreuses pages affichent du contenu qui semble statique alors qu'il est chargé via une API en arrière-plan. Dans ce cas, parser le HTML n'est pas toujours la meilleure option. Il faut parfois inspecter les requêtes réseau et cibler directement l'endpoint qui fournit les données.

Une autre étape souvent négligée consiste à lire le fichier robots.txt du site, à consulter ses conditions d'utilisation et à vérifier si le contenu est destiné à être réexploité. Tout n'est pas automatiquement libre parce que tout est visible dans un navigateur. Il faut aussi éviter de collecter des données personnelles sans base claire et limiter la fréquence des requêtes.

< 1 s
Temporisation minimale prudente
Bonne pratique opérationnelle, 2026
3
Étapes avant extraction
Structure, source, cadre d'usage
1
Session HTTP réutilisée
Réduit la charge et stabilise les requêtes
0
Supposition tolérée
Toujours vérifier le DOM et les réponses réseau

La préparation méthodologique évite la majorité des scripts jetables. Un scraping efficace n'est pas celui qui enchaîne le plus de requêtes, mais celui qui comprend où se trouvent réellement les données. Une page produit, par exemple, peut afficher un titre, un prix, une disponibilité, des variantes et des avis. Mais ces informations peuvent venir de plusieurs sources différentes. Le HTML initial ne raconte pas toujours toute l'histoire.

Installer l'environnement Python

Pour démarrer, un environnement léger suffit. Les bibliothèques les plus utiles pour un scraping classique sont requests pour envoyer les requêtes HTTP, beautifulsoup4 pour analyser le HTML et, selon les besoins, lxml pour accélérer le parsing. Pour les pages fortement dépendantes du JavaScript, playwright devient une option pertinente. Quand le périmètre s'élargit à des centaines ou des milliers de pages, scrapy offre un cadre plus robuste.

Commandes utiles

python -m venv .venv

source .venv/bin/activate ou .venv\Scripts\activate sous Windows

pip install requests beautifulsoup4 lxml pandas

Ajouter pandas n'est pas obligatoire, mais cette bibliothèque simplifie l'export vers CSV et le contrôle rapide des données collectées. Pour un projet plus sérieux, il est également conseillé de figer les dépendances dans un fichier requirements.txt afin de garantir la reproductibilité.

Écrire un premier script d'extraction

Le scénario le plus simple consiste à récupérer une page HTML puis à sélectionner les balises qui contiennent les données visées. Imaginons un site listant des articles avec un titre, une URL et une date. Le script ci-dessous montre la logique minimale.

import requests
from bs4 import BeautifulSoup

url = "https://example.com/articles"
headers = {
    "User-Agent": "Mozilla/5.0 (compatible; DataResearchBot/1.0)"
}

response = requests.get(url, headers=headers, timeout=15)
response.raise_for_status()

soup = BeautifulSoup(response.text, "lxml")

articles = []

for card in soup.select("article.post"):
    title_tag = card.select_one("h2 a")
    date_tag = card.select_one("time")

    title = title_tag.get_text(strip=True) if title_tag else None
    link = title_tag["href"] if title_tag and title_tag.has_attr("href") else None
    date = date_tag.get_text(strip=True) if date_tag else None

    articles.append({
        "title": title,
        "link": link,
        "date": date
    })

print(articles)

Trois éléments méritent déjà l'attention. D'abord, raise_for_status() interrompt le script si le serveur répond avec une erreur HTTP. Ensuite, l'usage de select et select_one permet de cibler les éléments avec des sélecteurs CSS, souvent plus lisibles que d'autres approches. Enfin, les tests conditionnels évitent les erreurs quand un bloc HTML ne contient pas exactement la structure attendue.

Dans un vrai projet, il est préférable de séparer les responsabilités : une fonction pour télécharger la page, une autre pour parser le HTML, une troisième pour nettoyer les champs et une dernière pour exporter les données. Cette séparation rend les tests plus faciles et limite les effets de bord lors des modifications.

Point clé Le web scraping devient fragile quand les sélecteurs sont trop dépendants de classes générées automatiquement. Mieux vaut cibler une structure stable, des attributs sémantiques, ou un chemin DOM simple plutôt qu'un nom de classe obfusqué.

Nettoyer et structurer les données

Extraire une chaîne de caractères n'est que le début. Les données issues du web sont souvent hétérogènes : espaces multiples, caractères invisibles, devises mélangées, dates sous plusieurs formats, URLs relatives, variantes textuelles d'une même catégorie. Sans nettoyage, l'analyse qui suit devient approximative.

Prenons l'exemple d'un prix affiché sous la forme "1 299,00 €". Pour l'exploiter correctement, il faut le convertir en valeur numérique, standardiser la devise et éventuellement conserver la chaîne d'origine pour audit. Même logique pour les dates. Un site peut présenter 12 mars 2026, 2026-03-12 ou 12/03/2026. L'idéal est de ramener ces formats vers une représentation unique.

from urllib.parse import urljoin
from datetime import datetime

base_url = "https://example.com"

def clean_price(raw):
    if not raw:
        return None
    raw = raw.replace("€", "").replace(" ", "").replace(",", ".")
    return float(raw)

def clean_link(href):
    if not href:
        return None
    return urljoin(base_url, href)

def clean_date(raw):
    if not raw:
        return None
    return datetime.strptime(raw, "%d/%m/%Y").date().isoformat()

Structurer les données signifie aussi leur attribuer des noms de colonnes cohérents et durables. Une bonne table évite les intitulés flous comme info1 ou div_text. Il faut privilégier des champs explicites : product_name, price_eur, published_at, category, source_url, scraped_at. Le champ scraped_at est précieux : il permet de savoir quand la donnée a été collectée et de reconstituer un historique.

Extraire efficacement sans casser le site cible

L'efficacité en scraping n'a rien à voir avec la brutalité. Faire cinquante requêtes par seconde sur un petit site n'a rien d'impressionnant ; c'est surtout une manière rapide d'être bloqué. Une stratégie efficace repose sur quelques principes simples : réutiliser une session HTTP, limiter le nombre de pages utiles, temporiser entre les requêtes, prévoir des tentatives de reprise et mettre en cache ce qui peut l'être.

import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()

retries = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=["GET"]
)

session.mount("http://", HTTPAdapter(max_retries=retries))
session.mount("https://", HTTPAdapter(max_retries=retries))

headers = {
    "User-Agent": "Mozilla/5.0 (compatible; DataResearchBot/1.0)"
}

for url in urls:
    response = session.get(url, headers=headers, timeout=20)
    response.raise_for_status()
    # traitement ici
    time.sleep(1.5)

La session conserve certaines informations de connexion et évite de repartir de zéro à chaque requête. Le mécanisme de retry gère mieux les erreurs temporaires, notamment les codes 429 ou 503. Quant à la pause explicite, elle réduit la pression sur le serveur et diminue les risques de blocage.

Une autre dimension de l'efficacité concerne le volume réellement nécessaire. Si l'objectif est d'obtenir les articles publiés cette semaine, il est inutile de parcourir les archives sur dix ans. Si une API fournit les vingt derniers éléments triés par date, il est absurde de parser des dizaines de pages HTML pour reconstituer le même résultat. L'efficacité technique commence souvent par la réduction du périmètre.

Gérer le JavaScript, les API et le contenu dynamique

De nombreux débutants pensent que le web scraping échoue parce que BeautifulSoup serait limité. En réalité, l'échec vient souvent du fait que le HTML récupéré avec requests ne contient pas encore les données affichées par le navigateur. La page s'appuie sur du JavaScript pour aller chercher les informations après le chargement initial. Dans ce cas, deux approches sont possibles.

1. Chercher l'API utilisée par la page

C'est généralement la meilleure option. En inspectant l'onglet Réseau du navigateur, il est fréquent de repérer une requête fetch ou XHR qui renvoie directement du JSON. Si cette ressource est accessible, il devient beaucoup plus simple de récupérer les données de manière structurée.

2. Simuler un navigateur avec Playwright

Lorsque les données sont injectées dans le DOM après exécution du JavaScript, Playwright peut piloter un navigateur réel, attendre que les éléments apparaissent puis extraire le contenu final.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://example.com/dashboard", wait_until="networkidle")
    page.wait_for_selector(".result-card")

    cards = page.query_selector_all(".result-card")
    results = []

    for card in cards:
        title = card.query_selector("h2")
        results.append({
            "title": title.inner_text().strip() if title else None
        })

    browser.close()

Cette solution est plus lourde, plus lente et plus coûteuse que l'analyse d'un JSON renvoyé par une API. C'est pourquoi Playwright ne doit pas être le réflexe initial. Il faut d'abord vérifier si les données ne sont pas déjà disponibles d'une manière plus simple.

Bon réflexe Quand une page semble vide avec requests, il ne faut pas conclure trop vite que le scraping est impossible. Il faut vérifier si la donnée est chargée par une API, injectée par JavaScript ou protégée par une logique d'authentification.

Exporter vers CSV, JSON ou SQLite

La sortie du scraping doit être pensée dès le départ. Le format dépend de l'usage final. Le CSV reste pratique pour des tableaux simples et une ouverture rapide dans un tableur. Le JSON convient mieux à des structures imbriquées. SQLite, quant à lui, offre un compromis très intéressant pour historiser les données sans déployer une base de données plus lourde.

import csv
import json
import sqlite3

# CSV
with open("articles.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "link", "date"])
    writer.writeheader()
    writer.writerows(articles)

# JSON
with open("articles.json", "w", encoding="utf-8") as f:
    json.dump(articles, f, ensure_ascii=False, indent=2)

# SQLite
conn = sqlite3.connect("articles.db")
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS articles (
    title TEXT,
    link TEXT,
    date TEXT
)
""")
cur.executemany(
    "INSERT INTO articles (title, link, date) VALUES (:title, :link, :date)",
    articles
)
conn.commit()
conn.close()

Dans un contexte analytique, SQLite présente un intérêt souvent sous-estimé. Il devient possible de rejouer des requêtes SQL, de dédupliquer, de filtrer par date de collecte et de comparer les changements d'un jour à l'autre. Pour des projets de veille ou de benchmark, cet historique compte souvent autant que la donnée elle-même.

Comparer les principaux outils Python

Tous les projets de scraping ne demandent pas la même architecture. Un script court peut suffire pour un site simple. À l'inverse, un projet de collecte régulier, multi-pages, avec pagination, gestion d'erreurs et pipeline de données bénéficiera d'un framework plus complet. Le tableau suivant résume les principaux choix.

Critère Requests + BeautifulSoup Scrapy / Playwright
Prise en main Très simple pour démarrer Plus structurée, apprentissage plus long
Pages statiques Excellente option recommandé Utile mais parfois surdimensionné
Grand volume de pages Possible, mais demande plus d'organisation Très adapté avec pipelines et middlewares avantage
Pages JavaScript Souvent insuffisant Playwright mieux adapté avantage
Débogage Rapide et lisible Plus riche, mais plus technique
Scalabilité Bonne pour de petits projets Supérieure pour les collectes récurrentes avantage
Choix idéal Prototype, tutoriel, extraction ciblée Projet industriel, site dynamique, pipeline robuste

Quand rester léger

  • Une dizaine de pages à explorer.
  • Une structure HTML stable.
  • Un besoin ponctuel ou exploratoire.
  • Un export simple vers CSV ou JSON.

Quand passer à un framework

  • Une collecte régulière à planifier.
  • Un volume important de pages ou de catégories.
  • La nécessité de gérer les erreurs à grande échelle.
  • La présence d'un contenu fortement dynamique.

Éviter les erreurs les plus fréquentes

La première erreur consiste à scraper sans inspecter le HTML réel renvoyé par le serveur. Beaucoup de scripts échouent parce qu'ils ciblent ce que le navigateur affiche visuellement, sans vérifier ce que requests reçoit effectivement. Il faut presque toujours commencer par sauvegarder une réponse dans un fichier local et examiner sa structure.

La deuxième erreur est d'écrire des sélecteurs trop fragiles. Une classe CSS générée automatiquement ou un chemin DOM très précis peuvent disparaître au moindre redesign. Il vaut mieux rechercher une ancre robuste : une balise, un attribut data-*, une section identifiable, ou une combinaison simple de sélecteurs.

La troisième erreur est d'ignorer les cas limites. Une carte peut ne pas avoir de prix, un lien peut être relatif, une date peut manquer, une page peut répondre 403, 404 ou 429. Un script sérieux n'échoue pas silencieusement. Il journalise les problèmes, conserve éventuellement les URLs en erreur et permet une reprise partielle.

Méthode recommandée

Un scraping fiable repose sur un enchaînement assez sobre : observer la page, comprendre la source des données, écrire des sélecteurs stables, gérer les erreurs, ralentir volontairement le rythme et stocker les résultats dans un format exploitable.

À faire

  • Tester sur un petit échantillon avant d'élargir.
  • Réutiliser une session HTTP.
  • Ajouter des délais et des retries.
  • Conserver l'URL source et l'horodatage de collecte.

À éviter

  • Lancer des boucles rapides sans temporisation.
  • Supposer que le HTML visible est le HTML reçu.
  • Utiliser des sélecteurs opaques et fragiles.
  • Exporter des données non nettoyées puis analyser quand même.

FAQ

Le web scraping est-il légal ?
La réponse dépend du site, du type de données collectées, des conditions d'utilisation, du rythme des requêtes et de la réutilisation envisagée. Il faut vérifier le cadre juridique applicable, éviter les données personnelles non justifiées et respecter autant que possible les règles techniques et contractuelles du site cible.
Faut-il toujours utiliser BeautifulSoup ?
Non. BeautifulSoup est excellent pour parser du HTML relativement simple. Si les données sont déjà disponibles via une API JSON, il vaut mieux consommer directement cette API. Si la page dépend fortement du JavaScript, Playwright peut être plus approprié.
Scrapy est-il réservé aux gros projets ?
Pas uniquement, mais il devient vraiment intéressant quand le projet comporte beaucoup de pages, des pipelines de traitement, une reprise d'erreurs, un scheduling ou plusieurs spiders. Pour un tutoriel ou un prototype, Requests et BeautifulSoup suffisent souvent.
Comment savoir si une page charge ses données avec JavaScript ?
Il faut comparer le HTML obtenu via le navigateur et celui renvoyé par requests, puis observer l'onglet Réseau des outils de développement. Si les données arrivent dans une requête XHR ou fetch, la page s'appuie probablement sur une source externe appelée après le chargement initial.
Quel format de sortie choisir ?
Le CSV convient aux tableaux plats, le JSON aux structures imbriquées et SQLite aux projets de veille ou d'historisation. Le bon choix dépend moins du scraping lui-même que de l'analyse ou du pipeline prévu ensuite.

Conclusion

Le web scraping avec Python reste l'une des portes d'entrée les plus concrètes vers l'automatisation de la collecte de données. La technique paraît simple au départ : envoyer une requête, récupérer une page, lire son HTML. Pourtant, l'efficacité réelle vient d'autre chose. Elle vient de la précision avec laquelle le besoin est défini, de la compréhension de la page, du soin apporté au nettoyage, et d'une certaine discipline dans la manière d'interroger les serveurs.

Commencer avec requests et BeautifulSoup est souvent la meilleure approche. Cela permet de comprendre le cycle complet, depuis la requête HTTP jusqu'au stockage. Ensuite, selon l'évolution du projet, il devient possible d'introduire Scrapy pour structurer la collecte, ou Playwright pour traiter des interfaces plus dynamiques. Le plus important, au fond, n'est pas d'utiliser l'outil le plus impressionnant, mais celui qui correspond à la réalité de la page ciblée et au volume de données à traiter.

Un bon scraper ne se reconnaît pas à la longueur de son code. Il se reconnaît à la stabilité de ses résultats, à la propreté de ses données et à la modération de son comportement. C'est là que l'extraction devient réellement efficace.

Sources

  • Documentation Python 3.14 - modules standard utiles pour HTTP, CSV, JSON, SQLite et parsing de dates.
  • Documentation Requests - sessions, timeouts, adapters et gestion des erreurs HTTP.
  • Documentation Beautiful Soup 4 - sélection d'éléments, parsing HTML et navigation dans le DOM.
  • Documentation lxml - parsing HTML/XML performant pour Python.
  • Documentation Scrapy - architecture des spiders, pipelines, throttling et export de données.
  • Documentation Playwright for Python - automatisation de navigateur, attente d'éléments et rendu JavaScript.
  • Références générales sur robots.txt et bonnes pratiques de collecte automatisée des contenus web.
 

Recevez la veille IA & Data qui compte vraiment

 

    Analyses claires, outils concrets et tendances IA sans bruit.     Rejoignez les lecteurs de IANA Data.