# Web scraping Python : extraire des données web et les analyser avec Pandas, pas à pas

> Pratiquez le web scraping Python avec Requests et BeautifulSoup, puis nettoyez et analysez vos données dans un DataFrame Pandas, code complet à l'appui.

- URL : https://guides-numeriques.fr/data/web-scraping-python-pandas/
- Thématique : Data & business intelligence
- Mis à jour : 2026-09-26
- Formation associée : [Python Data Science : Du Web Scraping à l'Analyse Pandas](https://espritacademique.com/formations/python-data-science-du-web-scraping-a-lanalyse-pandas/)

## L'essentiel

- Le web scraping Python consiste à télécharger le code HTML d'une page avec Requests, puis à en extraire les informations utiles avec BeautifulSoup.
- Pandas range ensuite les données collectées dans un DataFrame, une table en mémoire que l'on nettoie, filtre, trie, agrège et exporte vers Excel ou CSV.
- Avant de scraper un site, vérifiez s'il propose une API, lisez ses conditions d'utilisation et son fichier robots.txt, et espacez vos requêtes.
- Les pages dont le contenu est généré en JavaScript nécessitent un navigateur automatisé comme Selenium ou Playwright, car Requests ne récupère que le HTML initial.
- Travailler dans un environnement virtuel (venv) isole les bibliothèques de chaque projet et évite les conflits de versions.

Le **web scraping Python** consiste à écrire un script qui télécharge des pages web et en extrait automatiquement les informations utiles : prix, titres, caractéristiques de produits, annonces, résultats sportifs. Associé à Pandas, il permet ensuite de nettoyer ces données, de les analyser et de les exporter vers Excel, en quelques lignes de code.

Ce guide s'adresse aux débutants en programmation comme aux analystes qui veulent automatiser une collecte d'informations. Vous y verrez comment préparer votre environnement, lire la structure d'une page HTML, écrire un script d'extraction complet, parcourir plusieurs pages, puis manipuler les résultats dans un DataFrame Pandas.

## Qu'est-ce que le web scraping avec Python ?

Le web scraping est l'extraction automatisée de données depuis des pages web. En Python, un script envoie une requête HTTP au site (bibliothèque Requests), reçoit le code HTML de la page, l'analyse (bibliothèque BeautifulSoup) pour isoler les éléments voulus, puis enregistre le résultat dans une structure exploitable, le plus souvent un DataFrame Pandas.

Le processus suit toujours quatre temps :

1. **Télécharger** la page (requête HTTP GET).
2. **Analyser** le HTML pour construire un arbre de balises navigable.
3. **Extraire** les éléments ciblés grâce à leurs balises, classes ou attributs.
4. **Structurer et exporter** les données : liste de dictionnaires, DataFrame, puis fichier Excel ou CSV.

Python domine ce domaine pour une raison simple : il réunit dans un même langage la collecte (Requests, BeautifulSoup, Selenium, Scrapy) et l'analyse de données (Pandas, Matplotlib, scikit-learn). On passe de la page web au graphique sans changer d'outil.

## À quoi sert le web scraping en data science ?

Les usages professionnels sont nombreux, dès lors qu'une information est publique mais qu'aucun export n'est proposé :

- **Veille tarifaire** : suivre l'évolution des prix d'un catalogue concurrent.
- **Études de marché** : recenser des offres, des annonces ou des caractéristiques de produits.
- **Constitution de jeux de données** : alimenter une analyse statistique ou un modèle de machine learning.
- **Suivi de contenus** : repérer les nouveautés d'une page de publications ou d'un site institutionnel.
- **Consolidation** : rassembler dans un tableau unique des informations dispersées sur des dizaines de pages.

Avant de coder, posez-vous une question : **le site propose-t-il une API ou un export ?** Une API renvoie des données déjà structurées (souvent en JSON), plus fiables et plus stables qu'un scraping qui cassera à la prochaine refonte du site.

## Scraper de façon responsable : les règles à respecter

Le scraping touche aux droits des sites et, parfois, aux données personnelles. Quelques règles s'imposent :

- **Lisez les conditions d'utilisation** du site : certaines interdisent explicitement la collecte automatisée.
- **Consultez le fichier robots.txt** (à la racine du domaine, par exemple `/robots.txt`) : il indique les zones que le site ne souhaite pas voir parcourues par des robots.
- **Espacez vos requêtes** avec une pause entre chaque page, et ne lancez pas des centaines de requêtes simultanées.
- **Identifiez-vous** avec un en-tête User-Agent explicite plutôt que de vous faire passer pour un autre service.
- **Ne contournez jamais** une authentification, un paywall ou une protection anti-robot.
- **Données personnelles** : noms, e-mails, téléphones sont soumis au RGPD, même s'ils sont publiés en ligne.

Pour vous entraîner sans risque, utilisez des sites conçus pour cela, comme *books.toscrape.com*, un faux catalogue de livres créé spécialement pour apprendre le scraping. C'est lui que nous utilisons dans les exemples ci-dessous.

## Comment faire du web scraping avec Python : les étapes


**Schéma — Faire du web scraping avec Python en 6 étapes**

1. **Préparer l'environnement** : Python, venv, puis requests, beautifulsoup4, pandas
2. **Tester une requête** : Vérifier que Python communique avec le web
3. **Inspecter le HTML** : Clic droit > Inspecter pour trouver les balises
4. **Extraire les données** : BeautifulSoup : titre, prix et note des livres
5. **Parcourir les pages** : Une boucle avec une pause entre chaque requête
6. **Analyser et exporter** : DataFrame Pandas, puis Excel ou CSV


### Étape 1 — Installer Python et créer un environnement virtuel

Installez la dernière version stable de Python depuis le site officiel [python.org](https://www.python.org/). Sous Windows, cochez l'option **Add python.exe to PATH** pendant l'installation.

Créez ensuite un dossier de projet et un **environnement virtuel**, qui isole les bibliothèques de ce projet :

```bash
mkdir scraping-livres
cd scraping-livres
python -m venv .venv

# Activation sous Windows
.venv\Scripts\activate

# Activation sous macOS / Linux
source .venv/bin/activate

pip install requests beautifulsoup4 pandas openpyxl jupyter
```

Dans Visual Studio Code, installez l'extension Python, ouvrez le dossier, puis choisissez l'interpréteur de l'environnement virtuel avec **Ctrl+Maj+P > Python: Select Interpreter**.

### Étape 2 — Tester une première requête

Commencez par vérifier que Python communique bien avec le web. Sur une API de test, la réponse arrive directement en JSON :

```python
import requests

reponse = requests.get("https://jsonplaceholder.typicode.com/users", timeout=10)
print(reponse.status_code)      # 200 si tout va bien
utilisateurs = reponse.json()   # liste de dictionnaires Python
print(utilisateurs[0]["name"])
```

Sur une page web classique, la réponse est du HTML : `reponse.text` contient le code source de la page, que l'on va maintenant analyser.

### Étape 3 — Comprendre la structure HTML de la page

Ouvrez la page dans votre navigateur, faites un clic droit sur un élément (le prix d'un livre) puis **Inspecter**. Les outils de développement affichent la balise correspondante. Sur *books.toscrape.com*, chaque livre est décrit ainsi :

- un bloc `article` de classe `product_pod` ;
- le titre complet dans l'attribut `title` du lien situé dans le `h3` ;
- le prix dans un paragraphe de classe `price_color` ;
- la note dans un paragraphe de classe `star-rating`, suivie d'un mot (`One` à `Five`).

Repérer ce motif répété est la clé : on écrit l'extraction pour **un** bloc, puis on la répète sur tous.

### Étape 4 — Écrire le script d'extraction

```python
import requests
from bs4 import BeautifulSoup

URL = "https://books.toscrape.com/catalogue/page-1.html"
EN_TETES = {"User-Agent": "Mozilla/5.0 (projet de formation Python)"}

reponse = requests.get(URL, headers=EN_TETES, timeout=10)
reponse.raise_for_status()          # stoppe le script en cas d'erreur HTTP
reponse.encoding = "utf-8"          # évite les caractères mal décodés

soup = BeautifulSoup(reponse.text, "html.parser")

livres = []
for bloc in soup.select("article.product_pod"):
    livres.append({
        "titre": bloc.h3.a["title"],
        "prix": bloc.select_one("p.price_color").get_text(strip=True),
        "note": bloc.select_one("p.star-rating")["class"][1],
    })

print(len(livres), "livres extraits")
print(livres[0])
```

Les deux méthodes essentielles de BeautifulSoup sont `select()`, qui renvoie tous les éléments correspondant à un sélecteur CSS, et `select_one()`, qui renvoie le premier. `get_text(strip=True)` récupère le texte sans espaces superflus, et la notation `element["attribut"]` lit la valeur d'un attribut.

### Étape 5 — Automatiser le scraping sur plusieurs pages

Le catalogue est réparti sur plusieurs pages numérotées. On transforme le code en fonction, puis on boucle sur les numéros de page, avec une pause entre chaque requête :

```python
import time
import requests
from bs4 import BeautifulSoup

EN_TETES = {"User-Agent": "Mozilla/5.0 (projet de formation Python)"}
session = requests.Session()

def extraire_page(numero):
    url = f"https://books.toscrape.com/catalogue/page-{numero}.html"
    reponse = session.get(url, headers=EN_TETES, timeout=10)
    if reponse.status_code == 404:
        return None                      # plus de page : on s'arrête
    reponse.raise_for_status()
    reponse.encoding = "utf-8"
    soup = BeautifulSoup(reponse.text, "html.parser")
    resultats = []
    for bloc in soup.select("article.product_pod"):
        resultats.append({
            "titre": bloc.h3.a["title"],
            "prix": bloc.select_one("p.price_color").get_text(strip=True),
            "note": bloc.select_one("p.star-rating")["class"][1],
            "page": numero,
        })
    return resultats

tous_les_livres = []
numero = 1
while True:
    page = extraire_page(numero)
    if not page:
        break
    tous_les_livres.extend(page)
    numero += 1
    time.sleep(1)                        # une seconde entre deux pages

print(len(tous_les_livres), "livres au total")
```

Cette version a trois qualités : elle s'arrête d'elle-même quand il n'y a plus de page, elle réutilise la connexion grâce à `requests.Session()`, et elle ménage le serveur avec `time.sleep()`. C'est le type de **refactoring** qui rend un script maintenable : une fonction par tâche, des constantes en haut, aucune valeur répétée.

### Étape 6 — Charger les résultats dans un DataFrame Pandas

```python
import pandas as pd

df = pd.DataFrame(tous_les_livres)

print(df.shape)       # (nombre de lignes, nombre de colonnes)
print(df.head())      # 5 premières lignes
df.info()             # types et valeurs non nulles par colonne
```

Une liste de dictionnaires se convertit directement en DataFrame : chaque clé devient une colonne, chaque dictionnaire une ligne.

### Étape 7 — Exporter vers Excel ou CSV

```python
df.to_excel("livres.xlsx", index=False)                       # nécessite openpyxl
df.to_csv("livres.csv", index=False, encoding="utf-8-sig")    # accents lisibles dans Excel
```

Certains tutoriels utilisent la bibliothèque xlwt, qui produit l'ancien format .xls. Elle fonctionne, mais n'est plus maintenue : pour un fichier .xlsx moderne, passez par Pandas et openpyxl.

> **Formation recommandée** : [Python Data Science : Du Web Scraping à l'Analyse Pandas](https://espritacademique.com/formations/python-data-science-du-web-scraping-a-lanalyse-pandas/) — 3h15 de vidéo, 59 €.

## Analyser les données avec Pandas

Une fois les données dans un DataFrame, Pandas devient votre tableur programmable. Le plus confortable pour explorer est **Jupyter Notebook** (lancez `jupyter notebook` dans le terminal, ou ouvrez un fichier .ipynb dans VS Code) : chaque cellule s'exécute séparément et affiche son résultat juste en dessous.

### Series et DataFrame : les deux structures de base

Une **Series** est une colonne de valeurs avec un index ; un **DataFrame** est un ensemble de Series qui partagent le même index. `df["prix"]` renvoie une Series, `df[["titre", "prix"]]` renvoie un DataFrame de deux colonnes.

### Nettoyer et typer les colonnes

Les prix extraits sont du texte (« £51.77 ») et les notes des mots (« Three »). Il faut les convertir pour calculer :

```python
df["prix"] = (
    df["prix"]
    .str.replace("£", "", regex=False)
    .astype(float)
)

correspondance = {"One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5}
df["note"] = df["note"].map(correspondance)

df = df.drop_duplicates(subset="titre")
print(df.isna().sum())      # valeurs manquantes par colonne
```

### Filtrer, trier et agréger

```python
# Livres à plus de 50 £, du plus cher au moins cher
chers = df[df["prix"] > 50].sort_values("prix", ascending=False)

# Livres bien notés et abordables
bons_plans = df[(df["note"] >= 4) & (df["prix"] < 20)]

# Statistiques par note
synthese = df.groupby("note")["prix"].agg(["count", "mean", "min", "max"]).round(2)
print(synthese)

# Statistiques descriptives globales
print(df["prix"].describe())
```

Les conditions se combinent avec `&` (et) et `|` (ou), chaque condition entre parenthèses. `groupby()` joue le rôle d'un tableau croisé dynamique : il regroupe les lignes et calcule une agrégation par groupe.

### Les opérations Pandas à connaître

| Besoin | Code Pandas | Équivalent Excel |
|---|---|---|
| Aperçu des données | `df.head()`, `df.info()` | Parcourir la feuille |
| Sélectionner des colonnes | `df[["titre", "prix"]]` | Masquer des colonnes |
| Filtrer des lignes | `df[df["prix"] > 50]` | Filtre automatique |
| Trier | `df.sort_values("prix")` | Trier de A à Z |
| Créer une colonne | `df["prix_ttc"] = df["prix"] * 1.2` | Formule dans une colonne |
| Agréger par groupe | `df.groupby("note")["prix"].mean()` | Tableau croisé dynamique |
| Joindre deux tables | `pd.merge(df1, df2, on="id")` | RECHERCHEX |
| Supprimer les doublons | `df.drop_duplicates()` | Supprimer les doublons |

## Astuces et bonnes pratiques de scraping

- **Commencez par pandas.read_html** : si les données sont déjà dans un tableau HTML, `pd.read_html(url)` renvoie directement une liste de DataFrames (bibliothèque lxml requise).
- **Protégez chaque extraction** : si un élément manque sur une fiche, `select_one()` renvoie `None` et l'accès à un attribut provoque une erreur. Testez la présence de l'élément avant de lire son contenu.
- **Enregistrez le HTML brut** d'une page pendant le développement pour travailler hors ligne et ne pas solliciter le site à chaque test.
- **Journalisez** la page en cours et les erreurs rencontrées : sur un long scraping, vous saurez où reprendre.
- **Sauvegardez régulièrement** les résultats intermédiaires, par exemple toutes les dix pages.
- **Surveillez les changements du site** : une refonte suffit à casser les sélecteurs. Un script de scraping demande une maintenance régulière.

### Repérer l'API cachée d'un site dynamique

Avant de sortir un navigateur automatisé, ouvrez les outils de développement (F12), onglet **Réseau**, puis filtrez sur **Fetch/XHR** et rechargez la page. Beaucoup de sites dynamiques chargent leurs données depuis une URL qui renvoie du JSON. Si cette requête est accessible sans authentification et que les conditions du site le permettent, l'interroger directement avec `requests.get(...).json()` est plus rapide, plus léger et plus stable que d'analyser le HTML affiché.

### Visualiser rapidement les résultats

Pandas s'appuie sur Matplotlib pour produire un premier graphique en une ligne, pratique pour vérifier la cohérence des données collectées :

```python
df["prix"].plot(kind="hist", bins=20, title="Répartition des prix")
df.groupby("note")["prix"].mean().plot(kind="bar", title="Prix moyen par note")
```

Un histogramme montre immédiatement une valeur aberrante (un prix à zéro, un prix multiplié par cent) qui trahit une erreur d'extraction ou de conversion. Pour des analyses statistiques plus poussées, le [langage R](https://guides-numeriques.fr/data/langage-r-rstudio/) est une alternative solide à Pandas, très utilisée dans la recherche et les études.

## Les erreurs fréquentes en web scraping Python

| Erreur | Cause | Solution |
|---|---|---|
| `AttributeError: 'NoneType' object has no attribute...` | Le sélecteur ne trouve pas l'élément | Vérifier le sélecteur dans l'inspecteur, tester `if element:` |
| La liste extraite est vide | Contenu généré en JavaScript | Chercher l'API appelée par la page ou utiliser Selenium/Playwright |
| Caractères bizarres (« Â£ ») | Mauvais encodage détecté | Définir `reponse.encoding = "utf-8"` |
| Erreur 403 ou 429 | Blocage ou trop de requêtes | Ralentir, respecter les règles du site, ne pas insister |
| `ModuleNotFoundError` | Bibliothèque installée hors de l'environnement virtuel | Activer le venv puis relancer `pip install` |
| Somme ou moyenne impossible sur une colonne | Valeurs restées en texte | Nettoyer puis convertir avec `astype(float)` ou `pd.to_numeric` |
| Fichier CSV illisible dans Excel | Encodage ou séparateur | `encoding="utf-8-sig"` et, si besoin, `sep=";"` |

## Quel outil choisir pour extraire des données web ?

| Outil | Idéal pour | Limites |
|---|---|---|
| API officielle | Données structurées et stables | N'existe pas toujours, quotas possibles |
| `pandas.read_html` | Tableaux HTML simples | Uniquement les balises de tableau |
| Requests + BeautifulSoup | La majorité des sites statiques | Ne lit pas le contenu généré en JavaScript |
| Selenium ou Playwright | Sites dynamiques, clics, défilement | Plus lent, plus lourd à installer |
| Scrapy | Collectes à grande échelle, nombreux sites | Courbe d'apprentissage plus élevée |
| Power Query (onglet Web) | Récupérer un tableau web sans coder | Peu adapté aux pages complexes et à la pagination |

Si votre objectif est seulement d'importer un tableau web dans un rapport, sans écrire de code, le connecteur Web de Power Query suffit souvent : notre guide [Power Query dans Power BI](https://guides-numeriques.fr/data/power-query-power-bi/) le présente.


**Schéma — Quel outil choisir pour extraire des données web ?**

| API officielle | Requests + BeautifulSoup | Selenium ou Playwright |
|---|---|---|
| Données structurées et stables | La majorité des sites statiques | Sites dynamiques |
| N'existe pas toujours | Récupère le HTML initial | Clics et défilement automatisés |
| Quotas possibles | Ne lit pas le contenu JavaScript | Plus lent, plus lourd à installer |


## Comment progresser en web scraping et en data science Python ?

Voici un parcours réaliste pour devenir autonome :

1. **Les bases de Python** (une à deux semaines) : variables, listes, dictionnaires, boucles, fonctions. Notre guide pour [apprendre Python](https://guides-numeriques.fr/developpement/apprendre-python/) détaille cette étape.
2. **HTML et sélecteurs CSS** (quelques heures) : balises, classes, attributs, inspecteur du navigateur.
3. **Premier scraper** : une page, puis plusieurs pages avec pagination et export.
4. **Pandas** : Series, DataFrames, nettoyage, filtres, groupby, jointures.
5. **Aller plus loin** : sites dynamiques, stockage en base de données, visualisation, puis modèles prédictifs.

Pour être accompagné sur les premières étapes, [la formation vidéo Python du web scraping à l'analyse Pandas](https://espritacademique.com/formations/python-data-science-du-web-scraping-a-lanalyse-pandas/) d'EspritAcadémique dure 3 h 15, ne demande aucun prérequis et suit une démarche 100 % pratique. Elle couvre notamment :

- l'installation de Python, la création d'un environnement virtuel et la configuration de VS Code ;
- le test d'une première API et l'affichage de données brutes ;
- l'analyse du code HTML et l'écriture pas à pas d'un script d'extraction de prix ;
- l'automatisation sur plusieurs pages et l'export des résultats vers Excel ;
- la découverte de Jupyter Notebook et les fondamentaux de Pandas, des Series aux DataFrames.

Une fois vos données collectées, deux prolongements naturels s'offrent à vous : les stocker et les interroger dans une base, avec notre guide pour [apprendre SQL](https://guides-numeriques.fr/data/apprendre-sql/), ou les exploiter dans des modèles prédictifs, présentés dans notre article sur le [machine learning](https://guides-numeriques.fr/data/machine-learning-deep-learning/).

## En résumé

Le web scraping avec Python repose sur un enchaînement simple : Requests télécharge la page, BeautifulSoup en extrait les éléments grâce aux sélecteurs CSS, une boucle parcourt les pages avec des pauses, et Pandas transforme le résultat en DataFrame que l'on nettoie, analyse et exporte. Vérifiez toujours l'existence d'une API et les règles du site avant de collecter, et structurez votre code en fonctions pour qu'il reste facile à maintenir.

## Sources et documentation officielle

- [Quickstart (documentation Requests)](https://requests.readthedocs.io/en/latest/user/quickstart/)
- [Beautiful Soup Documentation (Beautiful Soup)](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
- [10 minutes to pandas (documentation pandas)](https://pandas.pydata.org/docs/user_guide/10min.html)
- [Fiche focus sur la collecte de données par moissonnage, web scraping (CNIL)](https://www.cnil.fr/fr/focus-interet-legitime-collecte-par-moissonnage)

## Questions fréquentes

### Le web scraping est-il légal ?

Le scraping n'est pas interdit en soi, mais son usage est encadré. Respectez les conditions d'utilisation du site, ne contournez pas une authentification, ne surchargez pas le serveur et ne réutilisez pas de contenus protégés par le droit d'auteur ou les bases de données. Si vous collectez des données personnelles, le RGPD s'applique. En cas de doute pour un projet commercial, demandez un avis juridique.

### Quelle bibliothèque Python utiliser pour le web scraping ?

Pour la plupart des sites, le duo Requests et BeautifulSoup suffit : Requests télécharge la page, BeautifulSoup l'analyse. Pour extraire un simple tableau HTML, pandas.read_html est encore plus rapide. Pour les sites dynamiques en JavaScript, utilisez Selenium ou Playwright. Pour des collectes à grande échelle sur des milliers de pages, le framework Scrapy est plus adapté.

### Quelle est la différence entre une Series et un DataFrame dans Pandas ?

Une Series est une colonne unique de valeurs, associée à un index. Un DataFrame est un tableau à deux dimensions composé de plusieurs Series qui partagent le même index, comme une feuille Excel avec des colonnes nommées. Sélectionner une colonne d'un DataFrame, par exemple df["prix"], renvoie une Series.

### Faut-il connaître Python avant d'apprendre le web scraping ?

Des bases suffisent : variables, listes, dictionnaires, boucles for et fonctions. Le scraping est d'ailleurs un excellent projet pour apprendre Python, car le résultat est concret et immédiat. Il faut aussi comprendre la structure d'une page HTML, c'est-à-dire les balises, les classes et les attributs, pour savoir quoi cibler.

### Comment exporter des données scrapées vers Excel ?

Rangez les données dans un DataFrame Pandas, puis appelez df.to_excel("fichier.xlsx", index=False). Cette méthode nécessite la bibliothèque openpyxl, à installer avec pip. Pour un fichier CSV lisible directement dans Excel avec les accents, utilisez df.to_csv("fichier.csv", index=False, encoding="utf-8-sig").

### Pourquoi mon script de scraping ne trouve aucun élément ?

Trois causes dominent. Le contenu est chargé en JavaScript et absent du HTML reçu par Requests. Le sélecteur CSS ne correspond pas exactement à la structure réelle de la page. Ou le site renvoie une page d'erreur ou de blocage. Affichez reponse.status_code et une partie de reponse.text pour vérifier ce que vous avez réellement reçu.
