Utiliser Python et Selenium pour créer un bot ou automatiser des tâches sur le Web

Dans un monde où l’efficacité numérique est cruciale, l’automatisation des tâches web répétitives devient un atout majeur. Python, avec sa bibliothèque Selenium, offre une solution puissante pour créer des bots intelligents capables d’interagir avec n’importe quel site web comme le ferait un utilisateur humain.

Que vous souhaitiez automatiser la collecte de données, tester des applications web, ou simplifier des processus administratifs, ce guide vous accompagnera pas à pas dans la création de votre premier bot web

Qu’est-ce que Selenium ?

Selenium est une suite d’outils open-source permettant d’automatiser les navigateurs web. Initialement conçu pour les tests automatisés, Selenium est devenu l’outil de référence pour l’automatisation web grâce à ses capacités :

  • Multi-navigateurs : Compatible avec Chrome, Firefox, Safari, Edge
  • Multi-plateformes : Fonctionne sur Windows, macOS, Linux
  • Multi-langages : Support de Python, Java, C#, JavaScript, Ruby
  • Interaction complète : Simulation de clics, saisie de texte, navigation

Installation et configuration

Prérequis

Avant de commencer, assurez-vous d’avoir :

  • Python 3.7 ou version supérieure
  • Un navigateur web (Chrome recommandé)
  • Une connexion internet stable

Installation de Selenium

Installation du WebDriver

Le WebDriver est le pont entre votre code Python et le navigateur. Pour Chrome :

Cette approche moderne télécharge automatiquement la version compatible du driver Chrome.

Votre premier bot Selenium

Commençons par créer un script simple qui ouvre un navigateur et navigue vers un site web :

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
import time

class WebBot:
    def __init__(self):
        # Configuration du driver Chrome
        options = webdriver.ChromeOptions()
        options.add_argument('--disable-blink-features=AutomationControlled')
        options.add_experimental_option("excludeSwitches", ["enable-automation"])
        
        # Initialisation du driver
        service = Service(ChromeDriverManager().install())
        self.driver = webdriver.Chrome(service=service, options=options)
        self.wait = WebDriverWait(self.driver, 10)
    
    def open_website(self, url):
        """Ouvre un site web"""
        self.driver.get(url)
        print(f"Page ouverte : {url}")
    
    def close(self):
        """Ferme le navigateur"""
        self.driver.quit()

# Utilisation
bot = WebBot()
bot.open_website("https://www.google.com")
time.sleep(3)
bot.close()

Recherche et interaction avec les éléments

Pour interagir avec une page web, vous devez localiser les éléments HTML. Selenium offre plusieurs méthodes :

def find_elements_demo(self):
    # Par ID
    element = self.driver.find_element(By.ID, "search-box")
    
    # Par nom de classe
    elements = self.driver.find_elements(By.CLASS_NAME, "button")
    
    # Par nom d'attribut
    element = self.driver.find_element(By.NAME, "username")
    
    # Par sélecteur CSS
    element = self.driver.find_element(By.CSS_SELECTOR, ".login-form input[type='password']")
    
    # Par XPath
    element = self.driver.find_element(By.XPATH, "//button[@class='submit-btn']")
    
    # Par texte de lien
    element = self.driver.find_element(By.LINK_TEXT, "Connexion")

Cas d’usage pratiques

1. Bot de recherche automatisée

Créons un bot qui effectue des recherches automatiques sur Google :

python

class GoogleSearchBot(WebBot):
    def search(self, query):
        """Effectue une recherche sur Google"""
        try:
            # Ouvrir Google
            self.open_website("https://www.google.com")
            
            # Accepter les cookies si nécessaire
            try:
                accept_btn = self.wait.until(
                    EC.element_to_be_clickable((By.ID, "L2AGLb"))
                )
                accept_btn.click()
            except:
                pass  # Pas de popup de cookies
            
            # Localiser la barre de recherche
            search_box = self.wait.until(
                EC.presence_of_element_located((By.NAME, "q"))
            )
            
            # Saisir la requête
            search_box.clear()
            search_box.send_keys(query)
            search_box.submit()
            
            # Attendre les résultats
            self.wait.until(
                EC.presence_of_element_located((By.ID, "search"))
            )
            
            # Extraire les titres des résultats
            results = self.driver.find_elements(By.CSS_SELECTOR, "h3")
            
            print(f"Résultats pour '{query}':")
            for i, result in enumerate(results[:5], 1):
                print(f"{i}. {result.text}")
                
        except Exception as e:
            print(f"Erreur lors de la recherche : {e}")

# Utilisation
search_bot = GoogleSearchBot()
search_bot.search("Python Selenium automation")
time.sleep(5)
search_bot.close()

2. Bot de connexion automatique

Automatisons la connexion à un site web :

python

class LoginBot(WebBot):
    def login(self, url, username, password, username_selector, password_selector, login_btn_selector):
        """Connexion automatique à un site"""
        try:
            # Ouvrir la page de connexion
            self.open_website(url)
            
            # Attendre que la page se charge
            username_field = self.wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, username_selector))
            )
            
            # Saisir les identifiants
            username_field.clear()
            username_field.send_keys(username)
            
            password_field = self.driver.find_element(By.CSS_SELECTOR, password_selector)
            password_field.clear()
            password_field.send_keys(password)
            
            # Cliquer sur le bouton de connexion
            login_btn = self.driver.find_element(By.CSS_SELECTOR, login_btn_selector)
            login_btn.click()
            
            # Attendre la redirection
            time.sleep(3)
            print(f"Connexion réussie sur {url}")
            
        except Exception as e:
            print(f"Erreur de connexion : {e}")

3. Bot de surveillance de prix

Créons un bot qui surveille les prix sur un site e-commerce :

python

class PriceMonitorBot(WebBot):
    def __init__(self):
        super().__init__()
        self.prices_history = []
    
    def monitor_price(self, product_url, price_selector, target_price=None):
        """Surveille le prix d'un produit"""
        try:
            self.open_website(product_url)
            
            # Attendre que le prix se charge
            price_element = self.wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, price_selector))
            )
            
            # Extraire le prix
            price_text = price_element.text
            # Nettoyer le texte pour extraire le nombre
            import re
            price_match = re.search(r'[\d,]+\.?\d*', price_text.replace(',', ''))
            
            if price_match:
                current_price = float(price_match.group().replace(',', ''))
                self.prices_history.append({
                    'price': current_price,
                    'timestamp': time.time()
                })
                
                print(f"Prix actuel : {current_price}€")
                
                if target_price and current_price <= target_price:
                    self.send_alert(f"🎉 Prix cible atteint ! {current_price}€ <= {target_price}€")
                    
                return current_price
            
        except Exception as e:
            print(f"Erreur de surveillance : {e}")
            return None
    
    def send_alert(self, message):
        """Envoie une alerte (à personnaliser)"""
        print(f"ALERTE : {message}")
        # Ici vous pourriez ajouter l'envoi d'email, notification, etc.

Techniques avancées

Gestion des attentes intelligentes

Utilisez les attentes explicites pour rendre vos bots plus fiables :

python

from selenium.webdriver.support import expected_conditions as EC

class AdvancedBot(WebBot):
    def wait_for_element(self, locator, timeout=10):
        """Attendre qu'un élément soit présent"""
        return WebDriverWait(self.driver, timeout).until(
            EC.presence_of_element_located(locator)
        )
    
    def wait_for_clickable(self, locator, timeout=10):
        """Attendre qu'un élément soit cliquable"""
        return WebDriverWait(self.driver, timeout).until(
            EC.element_to_be_clickable(locator)
        )
    
    def wait_for_text(self, locator, text, timeout=10):
        """Attendre qu'un élément contienne un texte spécifique"""
        return WebDriverWait(self.driver, timeout).until(
            EC.text_to_be_present_in_element(locator, text)
        )

Mode headless (sans interface)

Pour des bots en production, le mode headless améliore les performances :

python

def setup_headless_driver(self):
    """Configuration pour mode headless"""
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    options.add_argument('--disable-gpu')
    
    service = Service(ChromeDriverManager().install())
    return webdriver.Chrome(service=service, options=options)

Gestion des cookies et sessions

python

def manage_cookies(self):
    """Gestion des cookies"""
    # Sauvegarder les cookies
    cookies = self.driver.get_cookies()
    
    # Ajouter un cookie personnalisé
    self.driver.add_cookie({
        'name': 'session_id',
        'value': 'abc123',
        'domain': 'example.com'
    })
    
    # Supprimer tous les cookies
    self.driver.delete_all_cookies()

Bonnes pratiques et optimisation

1. Respect des sites web

python

class EthicalBot(WebBot):
    def __init__(self, delay_between_requests=2):
        super().__init__()
        self.delay = delay_between_requests
    
    def polite_request(self, action):
        """Exécute une action avec délai respectueux"""
        result = action()
        time.sleep(self.delay)  # Respecter le serveur
        return result
    
    def check_robots_txt(self, domain):
        """Vérifier robots.txt (implémentation basique)"""
        import requests
        try:
            response = requests.get(f"https://{domain}/robots.txt")
            return "User-agent: *" in response.text
        except:
            return True  # Autoriser par défaut

2. Gestion des erreurs robuste

python

def robust_element_interaction(self, locator, action="click", max_retries=3):
    """Interaction robuste avec gestion d'erreurs"""
    for attempt in range(max_retries):
        try:
            element = self.wait.until(EC.element_to_be_clickable(locator))
            
            if action == "click":
                element.click()
            elif action == "text":
                return element.text
            elif action == "send_keys":
                return element  # Retourner pour saisie ultérieure
                
            return True
            
        except Exception as e:
            print(f"Tentative {attempt + 1} échouée : {e}")
            if attempt == max_retries - 1:
                raise e
            time.sleep(2)  # Attendre avant de réessayer

3. Logging et monitoring

python

import logging
from datetime import datetime

class MonitoredBot(WebBot):
    def __init__(self):
        super().__init__()
        self.setup_logging()
    
    def setup_logging(self):
        """Configuration du logging"""
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('bot.log'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)
    
    def log_action(self, action, success=True, details=""):
        """Logger les actions du bot"""
        status = "SUCCESS" if success else "FAILED"
        self.logger.info(f"{action} - {status} - {details}")

Déploiement et automatisation

Planification avec cron (Linux/Mac)

bash

# Exécuter le bot chaque jour à 9h
0 9 * * * /usr/bin/python3 /path/to/your/bot.py

# Exécuter toutes les heures
0 * * * * /usr/bin/python3 /path/to/your/bot.py

Planification avec Task Scheduler (Windows)

python

# Script pour Windows Task Scheduler
import subprocess
import sys

def run_bot():
    try:
        # Votre code de bot ici
        bot = YourBot()
        bot.run()
        bot.close()
        
        print("Bot exécuté avec succès")
        return 0
    except Exception as e:
        print(f"Erreur : {e}")
        return 1

if __name__ == "__main__":
    sys.exit(run_bot())

Exemple complet : Bot de veille concurrentielle

Voici un exemple complet qui combine plusieurs techniques :

python

import json
from datetime import datetime
import smtplib
from email.mime.text import MIMEText

class CompetitorMonitorBot(WebBot):
    def __init__(self, config_file="config.json"):
        super().__init__()
        self.load_config(config_file)
        self.results = []
    
    def load_config(self, config_file):
        """Charger la configuration depuis un fichier JSON"""
        with open(config_file, 'r') as f:
            self.config = json.load(f)
    
    def monitor_competitors(self):
        """Surveiller les concurrents"""
        for competitor in self.config['competitors']:
            try:
                print(f"Surveillance de {competitor['name']}...")
                
                # Naviguer vers le site
                self.open_website(competitor['url'])
                
                # Extraire les informations
                data = self.extract_competitor_data(competitor)
                
                # Sauvegarder les résultats
                self.results.append({
                    'competitor': competitor['name'],
                    'data': data,
                    'timestamp': datetime.now().isoformat()
                })
                
                time.sleep(self.config.get('delay_between_sites', 5))
                
            except Exception as e:
                print(f"Erreur pour {competitor['name']}: {e}")
    
    def extract_competitor_data(self, competitor):
        """Extraire les données spécifiques du concurrent"""
        data = {}
        
        for selector_info in competitor['selectors']:
            try:
                element = self.driver.find_element(
                    By.CSS_SELECTOR, 
                    selector_info['selector']
                )
                data[selector_info['name']] = element.text
            except:
                data[selector_info['name']] = "Non trouvé"
        
        return data
    
    def generate_report(self):
        """Générer un rapport"""
        report = "=== RAPPORT DE VEILLE CONCURRENTIELLE ===\n\n"
        
        for result in self.results:
            report += f"Concurrent: {result['competitor']}\n"
            report += f"Date: {result['timestamp']}\n"
            
            for key, value in result['data'].items():
                report += f"  {key}: {value}\n"
            
            report += "\n" + "-"*50 + "\n\n"
        
        return report
    
    def send_email_report(self, report):
        """Envoyer le rapport par email"""
        if not self.config.get('email'):
            return
        
        email_config = self.config['email']
        
        msg = MIMEText(report)
        msg['Subject'] = f"Rapport de veille - {datetime.now().strftime('%Y-%m-%d')}"
        msg['From'] = email_config['from']
        msg['To'] = email_config['to']
        
        try:
            with smtplib.SMTP(email_config['smtp_server'], email_config['smtp_port']) as server:
                server.starttls()
                server.login(email_config['username'], email_config['password'])
                server.send_message(msg)
            print("Rapport envoyé par email")
        except Exception as e:
            print(f"Erreur envoi email : {e}")

# Fichier config.json exemple
config_example = {
    "competitors": [
        {
            "name": "Concurrent A",
            "url": "https://competitor-a.com",
            "selectors": [
                {"name": "prix_produit", "selector": ".price"},
                {"name": "stock", "selector": ".stock-status"}
            ]
        }
    ],
    "delay_between_sites": 5,
    "email": {
        "smtp_server": "smtp.gmail.com",
        "smtp_port": 587,
        "from": "votre@email.com",
        "to": "destinataire@email.com",
        "username": "votre@email.com",
        "password": "votre_mot_de_passe"
    }
}

# Utilisation
if __name__ == "__main__":
    bot = CompetitorMonitorBot()
    bot.monitor_competitors()
    report = bot.generate_report()
    bot.send_email_report(report)
    bot.close()

Troubleshooting et solutions aux problèmes courants

Problème : Détection anti-bot

python

def avoid_detection(self):
    """Techniques pour éviter la détection"""
    options = webdriver.ChromeOptions()
    
    # Masquer l'automatisation
    options.add_argument('--disable-blink-features=AutomationControlled')
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option('useAutomationExtension', False)
    
    # User-Agent personnalisé
    options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
    
    # Désactiver les images pour plus de rapidité
    prefs = {"profile.managed_default_content_settings.images": 2}
    options.add_experimental_option("prefs", prefs)
    
    return options

Problème : Éléments qui changent dynamiquement

python

def handle_dynamic_content(self):
    """Gérer le contenu dynamique"""
    # Attendre le chargement AJAX
    self.wait.until(
        lambda driver: driver.execute_script("return jQuery.active == 0")
    )
    
    # Ou attendre un élément spécifique
    self.wait.until(
        EC.presence_of_element_located((By.CLASS_NAME, "loaded"))
    )

Python et Selenium forment une combinaison puissante pour l’automatisation web. En suivant les bonnes pratiques présentées dans ce guide, vous pouvez créer des bots robustes, éthiques et efficaces.

Points clés à retenir :

  1. Planifiez votre approche : Analysez le site cible avant de coder
  2. Respectez les limites : Vérifiez robots.txt et conditions d’utilisation
  3. Gérez les erreurs : Implémentez une gestion d’erreurs robuste
  4. Testez régulièrement : Les sites web évoluent, vos bots aussi
  5. Documentez votre code : Facilitez la maintenance future

L’automatisation web ouvre de nombreuses possibilités : monitoring, tests, collecte de données, et bien plus. Avec les bases solides de ce guide, vous êtes maintenant équipé pour créer vos propres solutions d’automatisation.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *