Localisation des éléments du document HTML
Locator
Pour l’heure, nous avons appris à lancer un navigateur, à aller à une URL donnée et à manipuler le navigateur. Cela ne suffit pas pour faire de réels tests fonctionnels. Entrons à présent un peu plus dans le vif sujet en apprenant comment récupérer un élément d’une page HTML.
Pour des raisons de simplicité et de clarté du code, nous n’utiliserons pas la librairie Pytest : nous utiliserons des locators dans de simples scripts. Nous reprendrons les tests avec Pytest au chapitre Les interactions utilisateur pour tester le comportement des éléments Web d’une page HTML.
Vu que nous ne faisons que sélectionner les éléments Web sans les manipuler, nous ne pouvons donc pas les tester pour le moment.
1. Principe
Les locators de Selenium permettent de cibler un élément HTML précis de la page sur laquelle est positionnée l’instance du navigateur de test lancé.
Nous devons utiliser la fonction du driver Web find_element() pour accéder à un seul élément ou la fonction find_elements() pour accéder à plusieurs éléments.
from selenium.webdriver.common.by import By
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("https://www.editions-eni.fr/...
Par l’identifiant : By.ID
Une balise HTML peut avoir une propriété id pour déclarer son identifiant au sein de la page Web. Cet identifiant a la particularité d’être unique dans la page HTML. De ce fait, lorsque nous utilisons un locator avec une recherche par identifiant, nous ne pouvons sélectionner qu’un élément HTML. Nous ne pouvons donc utiliser que la méthode find_element.
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("http://localhost:8888/chapitre6.html")
# sélection du paragraphe avec l'identifiant intro
browser.find_element(By.ID, "intro")
# sélection d'un élément non existant dans la page
browser.find_element(By.ID, "identifiant-inconnu")
browser.close()
Notre script positionne le navigateur sur la page HTML du chapitre et sélectionne l’élément d’identifiant intro, c’est-à-dire le premier paragraphe de notre page.
Si nous essayons de cibler un élément qui n’existe pas dans notre page, dans notre exemple la balise avec l’identifiant identifiant-inconnu, Selenium soulève une exception « no-such-element-exception »...
Par le nom de la balise : By.TAG_NAME
Selenium nous offre la possibilité de cibler un élément HTML d’une page par le nom de sa balise, grâce à By.TAG_NAME.
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("http://localhost:8888/chapitre6.html")
# sélection du titre h1
browser.find_element(By.TAG_NAME, "h1")
# sélection du premier paragraphe de la page
browser.find_elements(By.TAG_NAME, "p")
# sélection de tous les paragraphes
browser.find_elements(By.TAG_NAME, "p")
browser.close()
Dans notre script, nous sélectionnons en premier le titre h1 de notre page. Non seulement il est unique par convention, mais il est bien unique dans notre page HTML.
Que se passe-t-il lorsque nous sélectionnons l’élément Web avec la balise p, alors que notre page comporte plusieurs paragraphes ? Nous nous devons de nous poser cette question, car notre page comporte plusieurs paragraphes. Nous pouvons supposer à juste titre qu’une exception sera soulevée, mais non.
Selenium analyse la page de la première ligne à la dernière et arrête sa recherche dès qu’il a trouvé ce que nous...
Par la propriété name : By.NAME
HTML donne la possibilité de déclarer une propriété name pour toutes les balises. Contrairement à la propriété id, la valeur de name n’est pas forcément unique dans la page, ce qui peut poser des problèmes de cohérence dans nos tests fonctionnels.
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("http://localhost:8888/chapitre6.html")
# sélection de l'entrée message
browser.find_element(By.NAME, "message")
# sélection du paragraphe user
browser.find_element(By.NAME, "user")
# sélection de tous les éléments avec le name user
browser.find_elements(By.NAME, "user")
browser.close()
En effet, dans notre page HTML, nous avons deux balises avec la propriété name à user : un paragraphe et une entrée du formulaire. Notre paragraphe se trouvant avant l’entrée du formulaire dans notre page, la méthode browser.find_element(By.NAME, "user") sélectionne le paragraphe.
Si nous voulons trouver tous les éléments HTML avec la propriété name à user, nous devons...
Avec le CSS
1. Avec sa classe CSS : By.CLASS_NAME
Les classes CSS permettent d’affecter un style CSS à plusieurs balises d’une page HTML. Elles sont déclarées dans la propriété class des balises. De plus, une balise peut avoir plusieurs classes, comme le premier paragraphe de notre page HTML de test.
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("http://localhost:8888/chapitre6.html")
# sélection de l'élément avec la classe CSS intro-classe
browser.find_element(By.CLASS_NAME, "intro-classe")
# sélection du premier élément avec la classe CSS paragraphe-classe
browser.find_element(By.CLASS_NAME, "paragraphe-classe")
# sélection des éléments avec la classe CSS paragraphe-classe
browser.find_elements(By.CLASS_NAME, "paragraphe-classe")
browser.close()
Lorsque nous recherchons l’élément HTML qui possède la classe intro-classe, Selenium a l’intelligence de comprendre que notre premier paragraphe est attaché à la classe CSS paragraphe-classe et à la classe CSS intro-classe.
Si nous appelons la méthode find_element sur une classe, Selenium pointe sur le premier...
Avec le texte du lien
Pour sélectionner uniquement des balises de type lien hypertexte (balise a), nous pouvons utiliser le texte de ces liens.
1. Avec le texte complet : By.TEXT_LINK
Nous ciblons une balise lien avec son texte grâce à By.TEXT_LINK.
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("http://localhost:8888/chapitre6.html")
# sélection du lien avec le texte Pour aller plus loin
browser.find_element(By.LINK_TEXT, "Pour aller plus loin")
browser.close()
La valeur passée en second paramètre de la méthode find_element doit correspondre au texte de la balise, casse respectée et espace compris.
2. Avec une partie du texte : By.PARTIAL_LINK_TEXT
Si nous souhaitons retrouver une ou plusieurs balises de type lien dont le texte contient certains mots, nous devons utiliser By.PARTIAL_LINK_TEXT.
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("http://localhost:8888/chapitre6.html")
# sélection des liens contenant le texte aller plus
browser.find_elements(By.PARTIAL_LINK_TEXT, "aller plus")
browser.close()
Le script...
Par le chemin XPATH
XPATH permet de cibler différentes parties d’un document XML dans une syntaxe non XML.
Vous vous demandez sûrement pourquoi il est question de XML ici ? HTML et XML sont tous deux des langages à balises sous forme d’arborescence. Nous pouvons donc vulgariser en disant que le HTML est une forme spécifique de XML, où les noms des balises et des propriétés sont prédéfinis.
Nous pouvons donc opérer une sélection par chemin XPATH pour cibler un élément Web dans une page HTML.
1. Introduction à la syntaxe XPATH
XPATH permet de définir un chemin de localisation dans un document structuré en balises. Nous allons illustrer nos propos avec le fichier XML suivant, représentant quelques informations d’une recette de cuisine :
<?xml version="1.0" encoding="ISO-8859-1"?>
<recette>
<titre>Les Bonnes Recettes de Cuisine</titre>
<gateau>Gâteau aux Noix et au Chocolat blanc</gateau>
<ingredients>
<ingredient quantite="250g">chocolat blanc
</ingredient>
<ingredient...
Locators relatifs
Depuis la version 4 de Selenium, nous avons la possibilité de sélectionner un élément Web grâce à sa position par rapport à un autre élément de la page HTML.
Pour utiliser les locators relatifs, nous devons appeler la fonction locate_with que nous importons avec l’instruction suivante :
from selenium.webdriver.support.relative_locator import locate_with
La syntaxe de la fonction locate_with est la suivante :
locate_with(elementASelectionner).position(elementRelatif)
où les deux éléments sont sélectionnés avec la classe By.
1. Locator above
Le locator relatif above permet de sélectionner un élément HTML qui se trouve au-dessus d’un autre. Par exemple, la balise h1 au-dessus de la balise p avec l’identifiant intro dans notre page HTML.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with
browser = webdriver.Chrome()
browser.get("http://localhost:8888/chapitre6.html")
# sélection de la balise h1 au-dessus de la balise avec l'identifiant
intro
locate_with(By.TAG_NAME, "h1 ").above({By.ID, "intro "})
browser.close()
2. Locator below
Le locator relatif below permet de sélectionner...
Exercices
Voici le code de la page HTML exercices-chapitre6.html qui nous servira de référence pour les exercices suivants :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,
initial-scale=1">
<title>Chapitre 6 - Sélectionner les éléments HTML</title>
</head>
<body>
<h1>Chapitre 6 - Exercices</h1>
<img id="drag1" src="logo-eni.jpeg" draggable="true"
ondragstart="drag(event)" width="199" height="200"
classe="image-classe">
<p id="premier" class="paragraphe-classe toto-classe"
name="toto">Lorem … pharetra.</p>
<p class="paragraphe-classe">Vestibulum … nisl.</p>
<h2>Nous contacter</h2>
<form id="contact" class="formulaire-classe">
<input type="text" name="user" id="user"
class="input-classe">...