Selenium
Pilote un vrai navigateur (Chrome, Firefox…) depuis Python pour scraper des pages
qui ne fonctionnent qu'avec JavaScript exécuté. Là où requests ne voit
qu'une coquille HTML vide, Selenium voit la page après rendu.
À quoi ça sert
Quand tu fais requests.get(url), tu récupères le HTML tel qu'il sort
du serveur. Sur les sites modernes (SPA React/Vue, infinite scroll, données
chargées en Ajax…), ce HTML est presque vide : le contenu est généré par du
JavaScript exécuté dans le navigateur.
Selenium contourne le problème en pilotant un vrai navigateur. Il ouvre Chrome (ou Firefox) en arrière-plan, charge la page, attend que le JavaScript fasse son travail, et te donne accès au DOM rendu. Tu peux alors :
- Récupérer le HTML rendu et le passer à BeautifulSoup pour parsing.
- Cliquer sur des boutons, remplir des formulaires, naviguer entre les pages.
- Attendre qu'un élément précis apparaisse avant d'extraire les données.
À l'origine, Selenium est un outil de test end-to-end pour applications web. C'est ce que tu verras dans la doc officielle. Mais l'API est exactement la même pour le scraping : c'est le même besoin (piloter un navigateur), avec une intention différente.
Selenium pilote un navigateur réel pour scraper des pages dont le contenu n'apparaît qu'après exécution du JavaScript.
Selenium est l'historique (2004) que tu croiseras dans la plupart des projets et tutos. Playwright (Microsoft, 2020) est l'alternative moderne : auto-wait intégré, API plus simple, plus rapide. Pour un nouveau projet, regarde Playwright. Pour comprendre l'existant ou suivre un cours, tu auras Selenium en face.
Un exemple d'usage
On veut récupérer les citations de
quotes.toscrape.com/js/
— la version JavaScript du même site (les citations sont injectées par
JS au chargement). Avec requests seul, on récupère une page sans citations.
Avec Selenium, on attend le rendu et on lit ce que le navigateur affiche :
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
from bs4 import BeautifulSoup
driver = webdriver.Chrome()
try:
driver.get("https://quotes.toscrape.com/js/")
# On attend qu'au moins une citation soit dans le DOM
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".quote"))
)
soup = BeautifulSoup(driver.page_source, "html.parser")
for bloc in soup.select(".quote"):
texte = bloc.select_one(".text").get_text(strip=True)
auteur = bloc.select_one(".author").get_text(strip=True)
print(f"{auteur} — {texte}")
finally:
driver.quit()
Le pattern type du scraping moderne : Selenium ouvre la page et exécute le JS, BeautifulSoup parse le résultat. On profite du meilleur des deux outils.
How-to : installer et utiliser Selenium
-
Installer Selenium dans un venv
bashpython3 -m venv .venv source .venv/bin/activate pip install selenium beautifulsoup4 -
Driver : plus rien à faire à la main depuis Selenium 4
Pendant des années, il fallait télécharger
chromedrivermanuellement et le mettre dans le PATH. Depuis Selenium 4.6 (fin 2022), Selenium Manager est intégré : il détecte ton navigateur, télécharge le bon driver et le met en cache. Tu n'as plus rien à installer côté driver.Il faut quand même que Chrome (ou Firefox) soit installé sur ta machine — Selenium pilote un navigateur, il ne l'embarque pas.
-
Premier script : ouvrir une page
pythonfrom selenium import webdriver driver = webdriver.Chrome() driver.get("https://quotes.toscrape.com/js/") print(driver.title) driver.quit()Lance le script : une fenêtre Chrome s'ouvre, charge la page, et se referme. N'oublie jamais
driver.quit(), sinon les processus Chrome s'accumulent en arrière-plan. Le mieux est d'envelopper le tout dans untry / finally. -
Sélectionner des éléments avec
BySelenium fournit plusieurs stratégies de sélection. En 2026, By.CSS_SELECTOR est la plus pratique (même syntaxe que dans BeautifulSoup ou jQuery).
pythonfrom selenium.webdriver.common.by import By # Un seul élément (lève une exception si rien) titre = driver.find_element(By.CSS_SELECTOR, "h1") print(titre.text) # Plusieurs éléments (liste, vide si rien) quotes = driver.find_elements(By.CSS_SELECTOR, ".quote") print(len(quotes))Autres stratégies utiles :
By.ID,By.CLASS_NAME,By.XPATH,By.TAG_NAME. MaisBy.CSS_SELECTORcouvre 95 % des cas. -
Attendre les éléments avec
WebDriverWaitLe piège classique du débutant : utiliser
time.sleep(3)pour laisser la page charger. Ça marche… jusqu'à ce que le réseau soit lent un jour et que ton script casse. La bonne pratique est d'attendre un événement précis.pythonfrom selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # Attend jusqu'à 10 s qu'un .quote apparaisse WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".quote")) )WebDriverWaitrepose en boucle jusqu'à ce que la condition soit vraie (ou que le timeout expire). C'est plus rapide qu'unsleepaveugle, et beaucoup plus fiable.À retenirSi ton script semble fonctionner avec
time.sleep()mais casse aléatoirement, c'est presque toujours un problème de timing. Remplace par unWebDriverWait. -
Mode headless (sans fenêtre)
Pour scraper sans qu'une fenêtre Chrome s'ouvre à chaque exécution (utile sur un serveur, dans un script automatisé, ou juste pour la tranquillité) :
pythonfrom selenium import webdriver opts = webdriver.ChromeOptions() opts.add_argument("--headless=new") opts.add_argument("--window-size=1920,1080") driver = webdriver.Chrome(options=opts)Pendant le développement, garde le mode visible pour voir ce qui se passe. Une fois que ton script tourne, passe en headless.
-
Combiner avec BeautifulSoup
Selenium est très bien pour piloter le navigateur, mais BeautifulSoup est plus pratique pour parser méthodiquement de gros volumes de HTML. Le combo gagnant :
pythonfrom bs4 import BeautifulSoup # Selenium charge et exécute le JS driver.get(url) WebDriverWait(driver, 10).until(...) # BeautifulSoup parse le HTML rendu soup = BeautifulSoup(driver.page_source, "html.parser") for bloc in soup.select(".quote"): ... -
Bonnes pratiques de scraping
- Espace tes requêtes avec
time.sleep()entre les pages — ne martèle pas un site. - Lis le
robots.txtet respecte les conditions d'utilisation. - User-Agent honnête via
opts.add_argument("user-agent=…"). - Toujours
driver.quit()dans unfinallypour ne pas laisser de processus Chrome zombies. - Préfère l'API officielle du site si elle existe — c'est plus fiable et c'est gratuit pour le serveur en face.
- Espace tes requêtes avec
Aide-mémoire
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
# Démarrer / arrêter
driver = webdriver.Chrome()
driver.quit()
# Naviguer
driver.get(url)
driver.back()
driver.refresh()
# Sélectionner
driver.find_element(By.CSS_SELECTOR, ".x")
driver.find_elements(By.CSS_SELECTOR, ".x")
# Interagir
el.click()
el.send_keys("texte")
el.clear()
el.text # texte affiché
el.get_attribute("href")
# Attendre
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".x"))
)
EC.visibility_of_element_located(...)
EC.element_to_be_clickable(...)
# HTML rendu (à passer à BS4)
driver.page_source
# Options Chrome
opts = webdriver.ChromeOptions()
opts.add_argument("--headless=new")
opts.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(options=opts)
Pour aller plus loin
- Documentation officielle : selenium.dev/documentation
- Site d'entraînement (version JS) : quotes.toscrape.com/js/
- Pour parser le HTML récupéré : fiche BeautifulSoup.
- Alternative moderne, plus simple et plus rapide : fiche Playwright.