Tous les guides
IntermédiaireÀ votre rythmeGuide gratuitSection 33/95

Web Scraping — BeautifulSoup

Pratiquez les fondations du développement : programmation, web, API, données et usages de l’IA. Des sections et exercices pour construire vos premiers projets.

💡

Contenu gratuit, accessible sans compte. Les outils et modèles évoluent : consultez le dossier actuel pour vérifier leurs versions. Modèles et sources

Section 11.2.13 : Web Scraping — BeautifulSoup

🎯 Objectif pédagogique

Extraire des données de pages web avec BeautifulSoup. Vous serez capable de parser du HTML, extraire des informations structurées, et construire vos propres datasets à partir du web — une compétence inestimable quand les données n'existent pas sous forme d'API.


Quand le web est votre base de données

Certaines données n'existent pas en API ou en CSV. Les offres d'emploi sur un site, les prix d'un e-commerce, les avis clients — ces données sont dans le HTML de pages web. Le web scraping consiste à les extraire automatiquement.

Marc voulait comparer les salaires entre différents sites d'emploi. Pas d'API disponible. Solution : scraper les pages et construire son propre dataset.

Éthique et légalité du scraping

Avant de scraper un site, vérifiez :

  1. →robots.txt — le fichier qui indique ce qui est autorisé (site.com/robots.txt)
  2. →Conditions d'utilisation — certains sites interdisent le scraping
  3. →Fréquence — ne bombardez jamais un serveur (ajoutez des pauses)
  4. →Données personnelles — ne scrapez pas de données RGPD Le scraping pour usage personnel et éducatif est généralement toléré. Le scraping commercial peut poser problème.

BeautifulSoup — Parser le HTML

pip install beautifulsoup4 requests
from bs4 import BeautifulSoup
import requests

# Récupérer une page
url = "https://quotes.toscrape.com/"   # Site de test pour le scraping
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

# Extraire le titre
print(soup.title.text)  # "Quotes to Scrape"

# Trouver des éléments
quotes = soup.find_all('span', class_='text')
authors = soup.find_all('small', class_='author')

for quote, author in zip(quotes, authors):
    print(f'"\{quote.text\}" — \{author.text\}')

Sélecteurs CSS

# Par tag
soup.find('h1')                     # Premier h1
soup.find_all('p')                  # Tous les p

# Par classe
soup.find_all('div', class_='quote')
soup.select('.quote')               # CSS selector

# Par ID
soup.find(id='main-content')
soup.select('#main-content')

# Imbriqués
soup.select('div.quote span.text')  # span.text dans div.quote

# Attributs
soup.find_all('a', href=True)       # Tous les liens
soup.find_all('img', src=True)      # Toutes les images

# Texte
soup.find_all(string='Python')      # Éléments contenant "Python"

Exemple complet : scraper des citations

from bs4 import BeautifulSoup
import requests
import pandas as pd
import time

all_quotes = []
base_url = "https://quotes.toscrape.com/page/\{\}/"

for page in range(1, 6):  # Pages 1 à 5
    url = base_url.format(page)
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    for quote_div in soup.find_all('div', class_='quote'):
        text = quote_div.find('span', class_='text').text
        author = quote_div.find('small', class_='author').text
        tags = [tag.text for tag in quote_div.find_all('a', class_='tag')]
        
        all_quotes.append(\{
            'text': text,
            'author': author,
            'tags': ', '.join(tags),
            'page': page
        \})
    
    time.sleep(1)  # Politesse : 1 seconde entre chaque requête

# Créer un DataFrame
df = pd.DataFrame(all_quotes)
print(f"\n\{len(df)\} citations récupérées")
print(df.head())

# Analyse
print(f"\nAuteurs les plus cités :")
print(df['author'].value_counts().head(5))

# Sauvegarder
df.to_csv('quotes.csv', index=False)

Gérer les cas complexes

# Headers (se faire passer pour un navigateur)
headers = \{
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
\}
response = requests.get(url, headers=headers)

# Gestion d'erreurs
try:
    response = requests.get(url, timeout=10)
    response.raise_for_status()  # Lève une exception si status != 200
except requests.RequestException as e:
    print(f"Erreur : \{e\}")

# Encoding
response.encoding = 'utf-8'  # Forcer l'encodage si nécessaire

🏋️ Exercice pratique (25 minutes)

# Scraper https://quotes.toscrape.com
# 1. Récupérez les 10 premières pages
# 2. Créez un DataFrame avec : texte, auteur, tags, numéro de page
# 3. Quel auteur a le plus de citations ?
# 4. Quel tag est le plus fréquent ?
# 5. Sauvegardez en CSV
Vérification rapide

Pourquoi est-il important d'ajouter time.sleep() entre les requêtes de scraping ?

Vérification rapide

Que fait soup.find_all('div', class_='quote') ?

Votre progression

Cette progression est déclarative et conservée dans votre navigateur. L’attestation finale ne constitue pas un diplôme ni une évaluation indépendante.

Voir ma progression et mon attestation

Apprendre l’IA, du premier prompt aux agents

15 guides gratuitsQuiz, schémas et ateliersSans compte

Un cas pratique IA dans votre boîte mail

Méthodes, ressources et nouveaux exercices. Gratuit, avec désinscription à tout moment.