Passer au contenu

Comment attendre que la page se charge dans Selenium ? Un guide d'expert

Laissez-moi deviner : vous avez commencé à gratter un site avec Selenium et tout à coup, vous êtes confronté à de redoutables erreurs de délai d'attente, à des exceptions d'éléments obsolètes et à des localisateurs instables. Semble familier?

Nous sommes nombreux à y être allés ! Dans le Web dynamique d'aujourd'hui, attendre correctement que les pages soient complètement chargées avant d'interagir est essentiel pour une automatisation fiable.

Dans ce guide complet de plus de 3200 5 mots, je mettrai à profit mes XNUMX+ années d'expérience en tant qu'expert professionnel en web scraping pour explorer les différentes méthodes et meilleures pratiques pour une attente gracieuse dans Selenium.

Que vous soyez débutant ou professionnel chevronné, une logique d'attente robuste est un outil indispensable pour la stabilité. Allons-y !

Pourquoi vous ne pouvez pas vous précipiter

Au début du Web, les pages étaient pour la plupart du HTML simple rendu séquentiellement. Les scrapers pourraient commencer l’extraction immédiatement lors du chargement de la page.

Mais le Web d’aujourd’hui est très dynamique. Selon Recherche Google, le temps médian pour peindre pour la première fois est de 1.7 s, mais le temps médian pour être pleinement interactif est énorme en 15 secondes. Cela prend beaucoup de temps pour que le contenu se charge.

En tant que grattoir, si vous vous précipitez trop vite, voici quelques problèmes courants auxquels vous serez confronté :

  • Erreurs de clic sur le bouton car l'élément n'a pas encore été rendu
  • Essayer de lire les données d'une table qui n'a pas chargé le contenu du serveur
  • Envoi de texte à une entrée qui n'est pas visible à l'écran
  • Grattage des éléments vides qui seront remplis après le chargement de la page

Ces types d'exceptions sont des symptômes indiquant que vous devez attendre plus longtemps que la page soit prête avant d'interagir.

En chiffres : temps de chargement des pages

Pour comprendre combien de temps nous devrons peut-être attendre, examinons quelques mesures concrètes sur les performances de chargement des pages à partir du Rapport sur l'état du Web 2020 par Akamai :

  • Temps médian d'interactivité : 15s
  • Poids moyen des pages : 2744KB
  • Nombre moyen de demandes : 105
  • Images moyennes par page : 53
  • Octets JavaScript par page : 453KB

Les pages sont aujourd’hui plus volumineuses et complexes, et beaucoup plus de travail est nécessaire après la réponse initiale. Il est essentiel que les grattoirs attendent l'interactivité, pas seulement la première peinture.

Exceptions courantes causées par l'absence d'attente

Voici quelques exceptions spécifiques qui peuvent se produire lorsque les éléments ne sont pas encore prêts :

  • StaleElementReferenceExceptionStaleElementReferenceException – Élément supprimé du DOM après la récupération
  • ElementNotInteractableException – Essayer de cliquer sur un élément invisible
  • NoSuchElementException – La recherche a expiré car l'élément n'existe pas encore

Chacun de ces éléments indique que le grattoir nécessite davantage d’attente.

Les attentes explicites sont votre amie

Pour éviter ces erreurs, nous devons attendre que la page soit entièrement rendue avant d'interagir. Il existe deux approches principales dans Selenium :

Attentes implicites – Définir un temps d’attente global sur le chauffeur

Attentes explicites – Attendre que des conditions spécifiques se produisent

Dans la plupart des cas, une attente explicite est de loin préférable à une attente implicite. Comprenons pourquoi.

Attentes implicites : l'approche Sledgehammer

Les attentes implicites définissent un délai d'attente sur le pilote pour interroger le DOM lors de la recherche d'éléments. Cela signifie qu'à chaque fois que vous appelez :

driver.find_element_by_id(‘some-id‘)

Le pilote réessayera jusqu'à la durée d'attente implicite pour localiser cet élément avant de lancer une NoSuchElementException.

Vous pourriez l'utiliser comme :

driver = webdriver.Chrome()
driver.implicitly_wait(10) 

Désormais, toutes les recherches réessayeront pendant 10 secondes maximum pour trouver des éléments s'ils ne sont pas immédiatement présents.

L'inconvénient est qu'il attend chaque localisateur, même ceux qui ne sont pas nécessaires pour déterminer l'état de préparation de la page. Cela peut vraiment ralentir votre grattoir.

Pensez aux attentes implicites, comme l'ajout d'un sommeil de 5 secondes à chaque récupération d'élément. Ça s'additionne !

La précision des attentes explicites

Les attentes explicites nous permettent d'attendre précisément des conditions spécifiques indiquant l'état de préparation avant de continuer.

Les idées clés sont :

  • N'attendez qu'en cas de besoin – Évitez les attentes inutiles sans rapport avec la préparation de la page
  • Conditions précises – Attendez des éléments ou des états exacts, pas seulement du temps total
  • Flexibilité – Personnalisez la logique d’attente par page avec différentes conditions
  • Lisible – Intention facile à comprendre lors de la révision de l’ancien code

Voici un exemple typique attendant qu'un élément apparaisse :

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait 

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "myDynamicElement"))
)

Cela suspend l'exécution jusqu'à ce que l'élément portant l'ID "myDynamicElement" se charge ou que 10 secondes se soient écoulées.

Autres conditions attendues utiles fourni par Sélénium consistent à

  • title_contains() – Attendez que le titre de la page soit mis à jour
  • staleness_of() – Attendez que l’élément ne soit plus attaché au DOM
  • element_to_be_clickable() – Attendez que l’élément soit visible et activé

Explicit Beats Implicit : un exemple concret

Comparons les deux attentes avec un exemple réel.

Supposons que je supprime un site doté d'une barre de navigation, d'un panneau latéral gauche et d'un contenu principal.

L'élément clé que je dois attendre est un identifiant "#main-content" où mes données sont restituées.

Avec attente implicite :

  • 10 secondes ajoutées à chaque recherche d'élément, même si elles ne sont pas nécessaires
  • Toujours sujet aux erreurs d'éléments obsolètes s'il est trop rapide

Avec attente explicite :

  • N'attendez qu'en cas de besoin pour le sélecteur #main-content
  • Évitez les attentes inutiles pour la navigation et le panneau latéral
  • Attendez spécifiquement le chargement des données avant de continuer

En attendant sélectivement une seule condition de préparation comme un élément, j'évite les retards inutiles.

Modèles pour des attentes explicites efficaces

Maintenant que vous êtes convaincu que les attentes explicites sont la voie à suivre, explorons quelques bonnes pratiques pour les utiliser efficacement.

Attentes de chargement de page

Attendre l'état prêt du document est une technique courante pour déterminer quand le chargement est terminé :

WebDriverWait(driver, 10).until(
   lambda d: d.execute_script(‘return document.readyState‘) == ‘complete‘
)

Cela interroge le navigateur jusqu'à ce que l'état prêt soit « terminé », indiquant que tous les actifs sont chargés.

Un modèle plus léger surveille des éléments spécifiques de haut niveau :

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "main-content"))
) 

Cela réussit lorsque la section de contenu principale se charge, sans attendre tout le reste.

Attentes par action

Vous pouvez également attendre juste avant d'effectuer une action, comme cliquer sur un élément :

menu = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "top-menu"))
)

submenu = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, "submenu"))
)

submenu.click()

Cela garantit que le menu supérieur et le sous-menu sont prêts avant de cliquer.

Attentes parallèles

L'attente de plusieurs conditions peut confirmer que la page est prête :

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "header")),
    EC.presence_of_element_located((By.ID, "footer")), 
    EC.presence_of_element_located((By.ID, "main"))
)

Exiger le chargement de l’en-tête, du pied de page et du contenu principal réduit les faux positifs.

Attentes chaînées et imbriquées

Pour les scénarios avancés, vous pouvez également imbriquer les attentes :

element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "dropdown"))
)

menu = WebDriverWait(element, 10).until(
    EC.presence_of_element_located((By.ID, "menu"))  
)

Cela attend d'abord un élément parent, puis un élément enfant à l'intérieur de celui-ci.

L'interrogation AJAX attend

Certains sites se chargent via des requêtes AJAX continues. Vous pouvez boucler en attendant les modifications :

while True:

    current_count = driver.find_element_by_id(‘result-count‘).text

    # If count changed since last check, page is still loading
    if current_count != previous_count:
        previous_count = current_count
        continue 

    break # Page loaded!

Cela interroge un élément à la recherche de modifications pour détecter le chargement.

Attentes asynchrones

Dans les frameworks asynchrones comme asyncio, vous pouvez attendre des promesses :

await page.waitForSelector(‘#content‘)

La syntaxe est un peu différente mais propose une attente asynchrone.

Combinaison implicite + explicite

Vous pouvez même combiner des attentes implicites et explicites :

driver.implicitly_wait(10) 

my_element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "my-element"))
)

Vous avez ainsi une attente globale ainsi qu'une attente spécifique. Assurez-vous simplement qu’ils utilisent des durées raisonnables.

Choisir des localisateurs qui signalent l'état de préparation

Lors de la sélection des localisateurs à attendre, vous souhaitez que les éléments correspondent à ces critères :

  • Apparaître tard dans le processus de chargement
  • Avoir des identifiants ou des classes uniques qui ne changeront pas
  • Situé au-dessus du pli pour des contrôles rapides
  • Il est peu probable qu'ils soient déplacés en raison de changements de site
  • Ne soyez pas supprimé du DOM et devenez obsolète

Quelques exemples courants sont:

  • En-tête principal ou navigation chargé après les ressources
  • Conteneurs de contenu principaux ou widgets
  • Pied de page
  • Petits éléments d'interface utilisateur dynamiques comme des boutons

Les indicateurs de charge comme les fileuses sont également d’excellents déclencheurs d’attente lorsqu’ils disparaissent.

Réglage des délais d'attente pour une attente optimale

Définir des délais d'attente trop longs peut vraiment ralentir votre scraper, mais un délai trop court peut provoquer des pannes irrégulières.

Voici quelques bonnes pratiques concernant le réglage des durées :

  • Définissez des délais d'expiration de chargement de page plus longs, environ 10 à 20 secondes.
  • Utilisez des délais d'attente plus courts, comme 3 à 5 secondes pour des éléments individuels.
  • Tenez compte des performances du navigateur, mobile par rapport au bureau.
  • Tenez compte de la latence du réseau, du haut débit par rapport à la 3G.
  • Surveillez les erreurs de délai d’attente et ajustez plus haut si nécessaire.
  • Analysez la cascade de chargement des pages pour connaître les temps de chargement typiques.
  • Prévoyez 1 à 2 secondes supplémentaires comme tampon.
  • Standardisez les attentes similaires dans votre base de code.

Au fur et à mesure que vous grattez plus de pages, vous obtiendrez une meilleure intuition sur les attentes optimales en matière de fiabilité.

Gestion des échecs d'attente et de délai d'attente

Même avec des attentes élevées, vous pouvez toujours rencontrer des délais d'attente occasionnels. Voici quelques façons de les gérer :

  • Détails du débogage du journal – L'ajout d'impressions permet de diagnostiquer les échecs d'attente.
  • Réessayer après expiration du délai – Réessayez de courtes attentes explicites jusqu'à 3 fois en cas d'échec.
  • Augmenter le délai d'attente – Si de nombreux délais d'attente se produisent, augmentez progressivement les attentes.
  • Utilisez essayer/sauf – Détectez des exceptions spécifiques comme StaleElementReference.
  • Désactiver en cas d'échec – Vous pouvez ignorer les attentes après des échecs répétés pour permettre aux tests de se poursuivre.

Avec une certaine résilience intégrée, ces problèmes sporadiques ne briseront pas votre grattoir.

En attente dans d'autres langues

Jusqu'à présent, les exemples étaient en Python, mais des attentes explicites sont disponibles dans tous les langages :

  • Java - WebDriverWait ainsi que ExpectedConditions
  • C# - WebDriverWait ainsi que ExpectedConditions
  • Rubi - WebDriver::Wait ainsi que ExpectedConditions
  • JavaScript - browser.wait() et méthodes utilitaires

Les concepts sont très similaires – seule la syntaxe diffère légèrement.

Au-delà de Selenium : plus d'outils d'attente

Il existe également d'autres bibliothèques d'attente utiles au-delà de Selenium :

  • Temps - time.sleep() est simple mais met en pause toute exécution.
  • Refaire - L' Réessayer le package facilite les tentatives et les attentes.
  • Aiohttp - await response.text() attend la fin des appels réseau.
  • Belle soupe - BeautifulSoup(page.content, features="lxml") attendra l'analyse complète.
  • Scrapy - yield scrapy.Request(url, callback=self.parse) est asynchrone.

Les mélanger avec Selenium offre des attentes robustes dans votre code.

En résumé : attendez bien et mettez au rebut de manière fiable

En conclusion, voici cinq points clés à retenir :

  1. Utiliser des attentes explicites – Ils évitent les délais d’attente inutiles et ciblent des conditions spécifiques.

  2. Attendez plusieurs signaux – Combinez les attentes pour l’en-tête, le corps, le pied de page, etc. pour confirmer que la page est prête.

  3. Ajustez judicieusement les délais d'attente – Définissez des valeurs basées sur des données de chargement de page réelles pour optimiser les délais.

  4. Standardiser les attentes – Réutilisez des modèles cohérents dans votre base de code.

  5. Ajouter de la résilience – Implémentez les tentatives et la gestion des échecs pour tenir compte des pages dynamiques.

Attendre peut paraître fastidieux au début. Mais investir dans une logique d’attente robuste vous récompensera avec des scrapers fiables et résilients préparés pour le Web moderne.

J'espère que ces modèles et conseils tirés de mes années en tant que spécialiste professionnel du web scraping vous aideront à attendre avec succès. Mettez-vous au rebut !

Mots clés:

Prendre part à la conversation

Votre adresse email n'apparaitra pas. Les champs obligatoires sont marqués *