Automatisation Web et Scraping avec Selenium

Selenium est un outil initialement conçu pour les tests automatisés, mais il est également très utile pour le scraping web, particulièrement lorsque les données nécessitent l'exécution de JavaScript. Son fonctionnement repose sur le contrôle d'un navigateur web réel, simulant ainsi les actions d'un utilisateur (navigation, saisie, clics) pour obtenir le contenu rendu de la page. Il prend en charge une variété de navigateurs.

from selenium import webdriver

# Initialisation de différents navigateurs
# webdriver.Chrome() # Navigation Chrome
# webdriver.Firefox() # Navigation Firefox
# webdriver.PhantomJS() # Navigation sans interface graphique (obsolète)
# webdriver.Safari() # Navigation Safari
# webdriver.Edge() # Navigation Edge

Installation

Navigateur avec interface graphique Pour utiliser Selenium avec un navigateur comme Chrome, vous devez installer la librairie selenium et télécharger le pilote correspondant (chromedriver).

pip3 install selenium

Téléchargez chromedriver.exe et placez-le dans le répertoire scripts de votre installation Python, ou spécifiez son chemin lors de l'initialisation du WebDriver. Assurez-vous que la version du pilote correspond à celle de votre navigateur.

Vous pouvez trouver les pilotes pour différents navigateurs sur leurs sites officiels ou des miroirs :

Exemple d'utilisation :

from selenium import webdriver

# Spécifiez le chemin vers votre chromedriver si nécessaire
driver = webdriver.Chrome(executable_path='./chromedriver')
driver.get('https://www.baidu.com')
print(driver.page_source) # Affiche le code source HTML de la page
driver.close() # Ferme le navigateur

Navigateur sans interface graphique (Headless) Le mode headless permet d'exécuter le navigateur sans afficher d'interface visuelle, idéal pour les serveurs ou l'automatisation en arrière-plan.

from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument('--headless') # Active le mode headless
chrome_options.add_argument('--disable-gpu') # Nécessaire sur certains systèmes pour éviter des bugs
chrome_options.add_argument('--window-size=1920,1080') # Définit la taille de la fenêtre
chrome_options.add_argument('--no-sandbox') # Contourne les problèmes de sandboxing sur Linux
chrome_options.add_argument('--disable-dev-shm-usage') # Contourne les problèmes liés à /dev/shm

driver = webdriver.Chrome(executable_path='./chromedriver', options=chrome_options)
driver.get("https://www.baidu.com")
print(driver.get_cookies())
driver.close()

Mode développeur Pour contourner certaines détections d'automatisation, vous pouvez activer des options spécifiques dans le ChromeOptions.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
# Désactive les messages d'automatisation dans la console du navigateur
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False) # Désactive l'extension d'automatisation

driver_path = './chromedriver' # Remplacez par le chemin de votre driver
driver = webdriver.Chrome(executable_path=driver_path, options=options)

# Exemple d'utilisation pour une connexion (à adapter)
def perform_login(username, password):
    try:
        driver.implicitly_wait(10) # Attente implicite
        driver.get('https://www.taobao.com/')
        # Cliquer sur le bouton de connexion (exemple CSS selector)
        login_button = driver.find_element_by_css_selector('#J_SiteNavLogin > div.site-nav-menu-hd > div.site-nav-sign > a.h')
        login_button.click()

        # Saisir les identifiants
        username_input = driver.find_element_by_id('fm-login-id')
        username_input.send_keys(username)
        password_input = driver.find_element_by_id('fm-login-password')
        password_input.send_keys(password)

        # Pause pour une connexion manuelle ou confirmation (à adapter)
        input("Veuillez compléter la connexion manuellement si nécessaire, puis appuyez sur Entrée...")
        return driver # Retourne le driver pour une utilisation ultérieure
    except Exception as e:
        print(f"Erreur lors de la connexion: {e}")
        driver.close()
        return None

# Exemple d'appel
# logged_driver = perform_login("votre_user", "votre_mdp")
# if logged_driver:
#     print("Connexion réussie.")

Masquer l'indicateur navigator.webdriverCertains sites détectent l'automatisation via la propriété window.navigator.webdriver. Vous pouvez la masquer en injectant du JavaScript au chargement de la page.

from selenium import webdriver
import time

def setup_driver_with_hidden_webdriver():
    options = webdriver.ChromeOptions()
    # Désactive les options liées à l'automatisation
    options.add_experimental_option('useAutomationExtension', False)
    options.add_experimental_option('excludeSwitches', ['enable-automation'])

    driver = webdriver.Chrome(executable_path='./chromedriver', options=options)

    # Injecte du JavaScript pour modifier la propriété navigator.webdriver
    driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        "source": """
            Object.defineProperty(navigator, 'webdriver', {
              get: () => undefined
            })
          """
    })
    return driver

# Exemple d'utilisation
driver = setup_driver_with_hidden_webdriver()
driver.implicitly_wait(10)
driver.get('https://www.some-detection-site.com/') # Remplacez par le site cible
time.sleep(5) # Laisser le temps au JS de s'exécuter
print(driver.page_source)
driver.close()

Utilisation avancée de Selenium

Sélectionneurs d'éléments Selenium offre plusieurs méthodes pour localiser des éléments sur une page :

  • find_element_by_css_selector()
  • find_element_by_xpath()
  • find_element_by_id()
  • find_element_by_name()
  • find_element_by_tag_name()
  • find_element_by_class_name()
  • find_element_by_link_text()
  • find_element_by_partial_link_text()

Actions courantes

  • .send_keys('texte') : Saisir du texte dans un champ.
  • .click() : Cliquer sur un élément.
  • .clear() : Effacer le contenu d'un champ de saisie.

Exemple de recherche sur Baidu :

from selenium import webdriver
import time

driver = webdriver.Chrome(executable_path='./chromedriver')
driver.get("https://www.baidu.com")
driver.implicitly_wait(10) # Attente implicite maximale de 10 secondes

# Trouver le champ de recherche par son sélecteur CSS
search_input = driver.find_element_by_css_selector('#kw')
search_input.send_keys("Automatisation Web")

# Trouver le bouton de recherche
search_button = driver.find_element_by_id('su')
search_button.click()

time.sleep(5) # Pause pour observer le résultat
driver.close()

Obtenir des informations sur les éléments Vous pouvez extraire des attributs, du texte, l'ID, la position et la taille des éléments.

# Supposons que 'element' est un WebElement trouvé précédemment
# Par exemple : element = driver.find_element_by_id('monId')

# Obtenir un attribut spécifique (ex: 'src' pour une image, 'href' pour un lien)
attribute_value = element.get_attribute('href')
print(f"Valeur de l'attribut href: {attribute_value}")

# Obtenir le texte visible de l'élément
element_text = element.text
print(f"Texte de l'élément: {element_text}")

# Obtenir l'ID de l'élément
element_id = element.id
print(f"ID de l'élément: {element_id}")

# Obtenir la position (coordonnées x, y) de l'élément
element_location = element.location
print(f"Position de l'élément: {element_location}")

# Obtenir la taille (largeur, hauteur) de l'élément
element_size = element.size
print(f"Taille de l'élément: {element_size}")

# Obtenir le nom de la balise de l'élément
tag_name = element.tag_name
print(f"Nom de la balise: {tag_name}")

Attentes explicites et implicites

  • Attente implicite (implicitly_wait) : Le driver attendra un certain temps (ex: 10 secondes) pour qu'un élément soit disponible avant de lancer une expection NoSuchElementException. Cette attente s'applique à toutes les opérations de localisation d'éléments.
  • Attente explicite (WebDriverWait) : Permet de définir des conditions spécifiques (ex: un élément est cliquable) et un temps d'attente maximum. C'est la méthode recommandée pour une gestion plus fine des attentes.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# Attente implicite (déjà vue plus haut)
# driver.implicitly_wait(10)

# Attente explicite
wait = WebDriverWait(driver, 10) # Attendre au maximum 10 secondes
try:
    # Attendre que l'élément avec l'ID 'monElement' soit présent
    element = wait.until(EC.presence_of_element_located((By.ID, "monElement")))
    print("L'élément est présent.")

    # Attendre que l'élément soit cliquable
    clickable_element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".mon-bouton")))
    clickable_element.click()
except Exception as e:
    print(f"L'attente a échoué: {e}")

Exécution de code JavaScript

Utilisation basique Vous pouvez exécuter du code JavaScript directement dans le contexte de la page chargée.

from selenium import webdriver
import time

driver = webdriver.Chrome(executable_path='./chromedriver')
driver.get("https://www.baidu.com")

# Exécuter un simple alert JavaScript
driver.execute_script('alert("JavaScript exécuté !");')
time.sleep(5) # Pause pour voir l'alerte
driver.switch_to.alert.accept() # Accepte l'alerte
driver.close()

Défilement de la page Le défilement peut être contrôlé via JavaScript.

// Faire défiler vers le bas de 100 pixels
window.scrollTo(0, 100);
// Faire défiler vers le bas de 500 pixels
window.scrollTo(0, 500);
// Faire défiler jusqu'en bas de la page
window.scrollTo(0, document.body.scrollHeight);
// Faire défiler jusqu'à 500 pixels avant la fin
window.scrollTo(0, document.body.scrollHeight - 500);

Exemple d'exécution :

from selenium import webdriver
import time

driver = webdriver.Chrome(executable_path='./chromedriver')
driver.get("https://www.cnblogs.com")

# Défilement jusqu'en bas de la page
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
time.sleep(3)
driver.close()

Navigation (Avant/Arrière) Selenium permet de simuler les boutons "Précédent" et "Suivant" du navigateur.

driver.back()   # Simule le bouton précédent
driver.forward()  # Simule le bouton suivant

Exemple complet :

from selenium import webdriver
import time

driver = webdriver.Chrome(executable_path='./chromedriver')

driver.get("https://www.cnblogs.com")  # Page 1
time.sleep(1)
driver.get("https://www.baidu.com")  # Page 2
time.sleep(1)
driver.get("https://www.jd.com")  # Page 3
time.sleep(1)

driver.back()  # Retour à la Page 2
time.sleep(1)
driver.forward()  # Retour à la Page 3
time.sleep(1)
driver.close()

Gestion des onglets et fenêtres L'ouverture de nouveaux onglets ou fenêtres peut être gérée en utilisant execute_script et en changeant le contexte du driver.

driver.execute_script('window.open()') # Ouvre un nouvel onglet

# Récupère les identifiants de tous les onglets/fenêtres ouverts
window_handles = driver.window_handles
print(f"Tous les handles: {window_handles}")

# Se déplace vers le nouvel onglet (le deuxième handle, index 1)
driver.switch_to.window(window_handles[1])
driver.get('https://www.taobao.com') # Charge une URL dans le nouvel onglet
time.sleep(2)

# Retourne au premier onglet (handle index 0)
driver.switch_to.window(window_handles[0])
driver.get('https://www.sina.com.cn') # Charge une URL dans le premier onglet
time.sleep(2)
driver.close() # Ferme l'onglet courant

Gestion des exceptions Il est crucial de gérer les exceptions potentielles (ex: élément non trouvé) pour rendre votre script plus robuste.

from selenium import webdriver

driver = None # Initialiser driver à None
try:
    driver = webdriver.Chrome(executable_path='./chromedriver')
    driver.get('http://www.baidu.com')
    # Tentative de trouver un élément inexistant pour déclencher une exception
    driver.find_element_by_id("id_inexistant")

except Exception as e:
    print(f"Une erreur est survenue: {e}")
finally:
    if driver: # Vérifier si driver a été initialisé
        driver.close() # Ferme le navigateur quoi qu'il arrive

Simulation des actions clavier Selenium permet de simuler des touches du clavier, comme la touche "Entrée".

from selenium.webdriver.common.keys import Keys

# Exemple: simuler la pression de la touche Entrée après une saisie
# search_input.send_keys(Keys.ENTER)

Exemple complet (recherche sur Baidu avec touche Entrée) :

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

driver = webdriver.Chrome(executable_path='./chromedriver')
driver.get("https://www.baidu.com")
driver.implicitly_wait(10)

search_input = driver.find_element_by_css_selector('#kw')
search_input.send_keys("Simulation Clavier")

# Simule la pression de la touche Entrée
search_input.send_keys(Keys.ENTER)

time.sleep(5)
driver.close()

Étiquettes: Selenium web scraping Python Web Automation headless browser

Publié le 22 septembre à 09h22