Web Scraping avec Python : Guide complet avec Requests, BeautifulSoup et Selenium
Updated on
Vous avez besoin de données non disponibles via des APIs -- prix de produits sur des sites concurrents, articles de recherche sur des portails académiques, offres d'emploi sur des plateformes de recrutement ou articles de presse de plusieurs sources. Copier manuellement des données est lent, sujet aux erreurs et impossible à grande échelle. Le web scraping automatise ce processus, mais choisir le mauvais outil ou la mauvaise approche entraîne des requêtes bloquées, des parseurs cassés et des problèmes juridiques.
Ce guide couvre la pile complète du web scraping Python : requests + BeautifulSoup pour les pages statiques, Selenium pour le contenu rendu en JavaScript, et Scrapy pour le crawling à grande échelle. Vous apprendrez des techniques pratiques pour gérer les défis du monde réel.
Démarrage rapide : requests + BeautifulSoup
La combinaison la plus courante pour scraper des pages HTML statiques :
import requests
from bs4 import BeautifulSoup
# Récupérer la page
url = 'https://books.toscrape.com/'
response = requests.get(url)
response.raise_for_status() # Lever une erreur pour les mauvais codes de statut
# Analyser le HTML
soup = BeautifulSoup(response.text, 'html.parser')
# Extraire les titres des livres
books = soup.select('article.product_pod h3 a')
for book in books[:5]:
print(book['title'])Installation
# Installer les packages nécessaires
# pip install requests beautifulsoup4 lxmlAnalyse HTML avec BeautifulSoup
Trouver des éléments
from bs4 import BeautifulSoup
html = """
<div class="products">
<div class="product" id="p1">
<h2 class="name">Widget A</h2>
<span class="price">$9.99</span>
<p class="desc">A useful widget</p>
</div>
<div class="product" id="p2">
<h2 class="name">Widget B</h2>
<span class="price">$14.99</span>
<p class="desc">A better widget</p>
</div>
</div>
"""
soup = BeautifulSoup(html, 'html.parser')
# Par balise
print(soup.find('h2').text) # "Widget A"
# Par classe
prices = soup.find_all('span', class_='price')
for p in prices:
print(p.text) # "$9.99", "$14.99"
# Par ID
product = soup.find(id='p2')
print(product.find('h2').text) # "Widget B"
# Sélecteur CSS
names = soup.select('.product .name')
for n in names:
print(n.text)Sélecteurs courants
| Méthode | Exemple | Trouve |
|---|---|---|
find('tag') | soup.find('h2') | Premier élément h2 |
find_all('tag') | soup.find_all('a') | Tous les éléments ancre |
find(class_='x') | soup.find(class_='price') | Premier élément avec la classe |
find(id='x') | soup.find(id='main') | Élément avec l'ID |
select('css') | soup.select('div.product > h2') | Correspondances du sélecteur CSS |
select_one('css') | soup.select_one('#header') | Première correspondance CSS |
Extraction de données
from bs4 import BeautifulSoup
html = '<a href="/page/2" class="next" data-page="2">Next Page</a>'
soup = BeautifulSoup(html, 'html.parser')
link = soup.find('a')
# Contenu textuel
print(link.text) # "Next Page"
print(link.get_text(strip=True)) # "Next Page" (nettoyé)
# Attributs
print(link['href']) # "/page/2"
print(link.get('class')) # ['next']
print(link['data-page']) # "2"Gestion des en-têtes et sessions
De nombreux sites web bloquent les requêtes sans en-têtes appropriés :
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'en-US,en;q=0.9',
}
# Utiliser une session pour les cookies et en-têtes persistants
session = requests.Session()
session.headers.update(headers)
response = session.get('https://books.toscrape.com/')
soup = BeautifulSoup(response.text, 'html.parser')
print(f"{len(soup.select('article.product_pod'))} livres trouvés")Pagination
Suivre les liens de page suivante
import requests
from bs4 import BeautifulSoup
base_url = 'https://books.toscrape.com/catalogue/'
all_books = []
url = 'https://books.toscrape.com/catalogue/page-1.html'
while url:
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# Extraire les livres de la page actuelle
for book in soup.select('article.product_pod'):
title = book.select_one('h3 a')['title']
price = book.select_one('.price_color').text
all_books.append({'title': title, 'price': price})
# Trouver la page suivante
next_btn = soup.select_one('li.next a')
if next_btn:
url = base_url + next_btn['href']
else:
url = None
print(f"{len(all_books)} livres scrapés jusqu'à présent...")
print(f"Total : {len(all_books)} livres")Scraping de pages JavaScript avec Selenium
Quand une page rend le contenu avec JavaScript, requests ne récupère que le HTML brut avant le rendu. Utilisez Selenium pour contrôler un vrai navigateur :
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Configurer Chrome sans interface
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
try:
driver.get('https://quotes.toscrape.com/js/')
# Attendre le chargement du contenu
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'quote'))
)
quotes = driver.find_elements(By.CLASS_NAME, 'quote')
for quote in quotes:
text = quote.find_element(By.CLASS_NAME, 'text').text
author = quote.find_element(By.CLASS_NAME, 'author').text
print(f'"{text}" -- {author}')
finally:
driver.quit()Comparaison des outils
| Outil | Idéal pour | Vitesse | JavaScript | Courbe d'apprentissage |
|---|---|---|---|---|
requests + BeautifulSoup | Pages HTML statiques | Rapide | Non | Facile |
Selenium | Pages rendues en JS | Lent | Oui | Moyen |
Scrapy | Crawling à grande échelle | Rapide | Avec plugins | Raide |
Playwright | Apps JS modernes | Moyen | Oui | Moyen |
httpx + selectolax | Analyse haute performance | Très rapide | Non | Facile |
Scrapy pour le scraping à grande échelle
Pour crawler des milliers de pages, Scrapy fournit la concurrence intégrée, la logique de réessai et les pipelines de données :
# spider.py
import scrapy
class BookSpider(scrapy.Spider):
name = 'books'
start_urls = ['https://books.toscrape.com/']
def parse(self, response):
for book in response.css('article.product_pod'):
yield {
'title': book.css('h3 a::attr(title)').get(),
'price': book.css('.price_color::text').get(),
}
# Suivre la pagination
next_page = response.css('li.next a::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
# Exécuter avec : scrapy runspider spider.py -o books.jsonNettoyage et stockage des données
import requests
from bs4 import BeautifulSoup
import pandas as pd
# Scraper les données
url = 'https://books.toscrape.com/'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
books = []
for item in soup.select('article.product_pod'):
title = item.select_one('h3 a')['title']
price_text = item.select_one('.price_color').text
price = float(price_text.replace('£', ''))
rating_class = item.select_one('p.star-rating')['class'][1]
books.append({
'title': title,
'price': price,
'rating': rating_class,
})
# Convertir en DataFrame
df = pd.DataFrame(books)
print(df.head())
# Sauvegarder en CSV
df.to_csv('books.csv', index=False)Pratiques éthiques de scraping
| Pratique | Description |
|---|---|
| Vérifier robots.txt | Respecter les règles de crawling du site |
| Ajouter des délais | Utiliser time.sleep() entre les requêtes (1-3 secondes) |
| S'identifier | Définir un User-Agent descriptif |
| Cacher les réponses | Ne pas re-scraper les pages déjà obtenues |
| Vérifier les APIs | Beaucoup de sites ont des APIs publiques plus rapides et autorisées |
| Lire les CGU | Certains sites interdisent explicitement le scraping |
| Limiter le débit | Ne pas surcharger les serveurs avec des requêtes concurrentes |
import time
import requests
def polite_scrape(urls, delay=2):
"""Scraper avec des délais entre les requêtes."""
results = []
for url in urls:
response = requests.get(url)
results.append(response.text)
time.sleep(delay) # Rester poli
return resultsAnalyse des données scrapées
Après avoir collecté des données par web scraping, PyGWalker (opens in a new tab) vous aide à explorer et visualiser le jeu de données interactivement dans Jupyter :
import pandas as pd
import pygwalker as pyg
df = pd.read_csv('scraped_data.csv')
walker = pyg.walk(df)Pour exécuter des scripts de scraping itérativement dans Jupyter avec l'assistance de l'IA, RunCell (opens in a new tab) fournit un environnement alimenté par l'IA où vous pouvez déboguer les sélecteurs et tester la logique d'analyse interactivement.
FAQ
Quelle est la meilleure bibliothèque Python pour le web scraping ?
Pour les pages statiques, requests + BeautifulSoup est le choix le plus simple et populaire. Pour les pages rendues en JavaScript, utilisez Selenium ou Playwright. Pour le crawling à grande échelle avec des milliers de pages, Scrapy fournit la concurrence intégrée et la gestion des pipelines.
Comment scraper un site web qui utilise JavaScript ?
Utilisez Selenium ou Playwright pour contrôler un navigateur sans interface qui exécute JavaScript. Alternativement, vérifiez l'onglet Réseau du navigateur pour des endpoints d'API retournant des données JSON -- scraper l'API directement est plus rapide et fiable que l'automatisation du navigateur.
Le web scraping est-il légal ?
La légalité du web scraping dépend de la juridiction, des conditions d'utilisation du site et de l'utilisation des données. Scraper des données publiquement disponibles est généralement légal dans de nombreuses juridictions, mais vérifiez toujours le robots.txt et les CGU du site. Évitez de scraper des données personnelles ou du contenu protégé par le droit d'auteur.
Comment éviter d'être bloqué en scrapant ?
Utilisez des délais entre les requêtes (1-3 secondes), alternez les User-Agents, respectez robots.txt, utilisez des sessions pour les cookies et évitez de faire trop de requêtes concurrentes. Si vous êtes systématiquement bloqué, vérifiez si le site a une API publique.
Comment gérer la pagination dans le web scraping ?
Trouvez le lien ou bouton "page suivante" dans le HTML, extrayez son URL et suivez-le en boucle jusqu'à ce qu'il n'y ait plus de pages. Alternativement, si les pages utilisent des paramètres de requête (ex. ?page=2), itérez directement à travers les numéros de page.
Conclusion
L'écosystème de web scraping Python couvre chaque scénario : requests + BeautifulSoup pour le scraping rapide de pages statiques, Selenium pour les sites lourds en JavaScript, et Scrapy pour le crawling à l'échelle de la production. Commencez avec l'outil le plus simple qui fonctionne, ajoutez de la complexité seulement quand c'est nécessaire, et scrapez toujours de manière éthique -- respectez robots.txt, ajoutez des délais et vérifiez d'abord les APIs. Stockez vos données scrapées dans des formats structurés comme CSV ou DataFrames pour une analyse immédiate.