All guides
IntermediateSelf-pacedFree GuideSection 33/95

Web Scraping — BeautifulSoup

Practise development foundations: programming, web, APIs, data and AI tools. Work through sections and exercises to build your first projects.

The full lessons for this course are currently available in French. Use the section menu to navigate the French course.

💡

Free content, available without an account. Tools and models change: use the current model guide to check their versions. Models and 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
Quick Check

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

Quick Check

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

Your progress

Progress is self-reported and stored in your browser. The final completion record is not a qualification or an independent assessment.

View progress and completion record

Learn AI, from prompts to agents

15 free guidesQuizzes, diagrams and workshopsNo account needed

One practical AI workflow in your inbox

Methods, resources and new exercises. Free, unsubscribe at any time.