Je vais tenir l'opinion impopulaire sur la balise SO sélénium selon laquelle XPath est préférable à CSS à long terme.
Ce long article comporte deux sections - d'abord, je vais mettre une preuve à l'arrière de la serviette, la différence de performance entre les deux est de 0,1 à 0,3 millisecondes (oui; c'est 100 microsecondes ) , puis je partagerai mon opinion pourquoi XPath est plus puissant.
Différence de performance
Commençons par aborder "l'éléphant dans la pièce" - ce xpath est plus lent que le CSS.
Avec la puissance actuelle du processeur (lire: tout ce qui a été produit par x86 depuis 2013) , même sur les VM Browserstack / saucelabs / aws, et le développement des navigateurs (lire: tous les plus populaires au cours des 5 dernières années), ce n'est guère le cas. Les moteurs du navigateur se sont développés, le support de xpath est uniforme, IE est hors de propos (espérons-le pour la plupart d'entre nous) . Cette comparaison dans l'autre réponse est citée partout, mais elle est très contextuelle - combien exécutent - ou se soucient - de l'automatisation par rapport à IE8?
S'il y a une différence, c'est en une fraction de milliseconde .
Pourtant, la plupart des frameworks de niveau supérieur ajoutent au moins 1 ms de surcharge par rapport à l'appel de sélénium brut de toute façon (wrappers, gestionnaires, stockage d'état, etc.); mon arme personnelle de choix - RobotFramework - ajoute au moins 2 ms, que je suis plus qu'heureux de sacrifier pour ce qu'elle fournit. Un aller-retour réseau entre un AWS us-east-1 et le hub de BrowserStack dure généralement 11 millisecondes .
Donc, avec les navigateurs distants, s'il y a une différence entre xpath et css, elle est éclipsée par tout le reste, par ordre de grandeur.
Les mesures
Il n'y a pas beaucoup de comparaisons publiques (je n'ai vraiment vu que celle citée) , donc - voici un cas unique, factice et simple.
Il localisera un élément par les deux stratégies X fois et comparera le temps moyen pour cela.
La cible - la page de destination de BrowserStack, et son bouton «Inscription»; une capture d'écran du html en écrivant ce post:
Voici le code de test (python):
from selenium import webdriver
import timeit
if __name__ == '__main__':
xpath_locator = '//div[@class="button-section col-xs-12 row"]'
css_locator = 'div.button-section.col-xs-12.row'
repetitions = 1000
driver = webdriver.Chrome()
driver.get('https://www.browserstack.com/')
css_time = timeit.timeit("driver.find_element_by_css_selector(css_locator)",
number=repetitions, globals=globals())
xpath_time = timeit.timeit('driver.find_element_by_xpath(xpath_locator)',
number=repetitions, globals=globals())
driver.quit()
print("css total time {} repeats: {:.2f}s, per find: {:.2f}ms".
format(repetitions, css_time, (css_time/repetitions)*1000))
print("xpath total time for {} repeats: {:.2f}s, per find: {:.2f}ms".
format(repetitions, xpath_time, (xpath_time/repetitions)*1000))
Pour ceux qui ne sont pas familiers avec Python - il ouvre la page et trouve l'élément - d'abord avec le localisateur css, puis avec le xpath; l'opération de recherche est répétée 1 000 fois. La sortie est le temps total en secondes pour les 1 000 répétitions et le temps moyen pour une découverte en millisecondes.
Les localisateurs sont:
- pour xpath - "un élément div ayant cette valeur de classe exacte, quelque part dans le DOM";
- le css est similaire - "un élément div avec cette classe, quelque part dans le DOM".
Choisi délibérément pour ne pas être sur-accordé; aussi, le sélecteur de classe est cité pour le css comme "le deuxième plus rapide après un identifiant".
L'environnement - Chrome v66.0.3359.139, chromedriver v2.38, processeur: ULV Core M-5Y10 fonctionnant généralement à 1,5 GHz (oui, un "traitement de texte", pas même une bête i7 ordinaire) .
Voici le résultat:
css total time 1000 repeats: 8.84s, per find: 8.84ms
xpath total time for 1000 repeats: 8.52s, per find: 8.52ms
De toute évidence, les délais de recherche sont assez proches; la différence est de 0,32 millisecondes . Ne sautez pas "le xpath est plus rapide" - parfois c'est le cas, parfois c'est css.
Essayons avec un autre ensemble de localisateurs, un tout petit peu plus compliqué - un attribut ayant une sous-chaîne (approche commune au moins pour moi, aller après la classe d'un élément quand une partie de celui-ci a une signification fonctionnelle) :
xpath_locator = '//div[contains(@class, "button-section")]'
css_locator = 'div[class~=button-section]'
Les deux localisateurs sont à nouveau sémantiquement les mêmes - "trouver un élément div ayant dans son attribut de classe cette sous-chaîne".
Voici les résultats:
css total time 1000 repeats: 8.60s, per find: 8.60ms
xpath total time for 1000 repeats: 8.75s, per find: 8.75ms
Diff de 0,15 ms .
En tant qu'exercice - le même test que celui effectué dans le blog lié dans les commentaires / autre réponse - la page de test est publique, tout comme le code de test .
Ils font quelques choses dans le code - en cliquant sur une colonne pour trier par elle, puis en obtenant les valeurs et en vérifiant que le tri de l'interface utilisateur est correct.
Je vais le couper - il suffit de récupérer les localisateurs, après tout - c'est le test racine, non?
Le même code que ci-dessus, avec ces modifications dans:
css_locator = '#table2 tbody .dues'
xpath_locator = "//table[@id='table2']//tr/td[contains(@class,'dues')]"
Et voici le résultat:
css total time 1000 repeats: 8.24s, per find: 8.24ms
xpath total time for 1000 repeats: 8.45s, per find: 8.45ms
Diff de 0,2 millisecondes.
"Recherche d'éléments en parcourant":
css_locator = '#table1 tbody tr td:nth-of-type(4)'
xpath_locator = "//table[@id='table1']//tr/td[4]"
Le résultat:
css total time 1000 repeats: 9.29s, per find: 9.29ms
xpath total time for 1000 repeats: 8.79s, per find: 8.79ms
Cette fois, il est de 0,5 ms (en sens inverse, xpath s'est avéré "plus rapide" ici).
Donc 5 ans plus tard (meilleurs moteurs de navigateurs) et en se concentrant uniquement sur les performances des localisateurs (pas d'actions comme le tri dans l'interface utilisateur, etc.), le même banc d'essai - il n'y a pratiquement aucune différence entre CSS et XPath.
Alors, hors xpath et css, lequel des deux choisir pour les performances? La réponse est simple: choisissez la localisation par identifiant .
Pour faire court, si l'id d'un élément est unique (comme il est supposé l'être selon les spécifications), sa valeur joue un rôle important dans la représentation interne du navigateur du DOM, et est donc généralement la plus rapide.
Pourtant, les identifiants uniques et constants (par exemple non générés automatiquement) ne sont pas toujours disponibles, ce qui nous amène à "pourquoi XPath s'il y a du CSS?"
L'avantage XPath
Avec les performances hors de l'image, pourquoi est-ce que je pense que XPath est meilleur? Simple - polyvalence et puissance.
Xpath est un langage développé pour travailler avec des documents XML; en tant que tel, il permet des constructions beaucoup plus puissantes que css.
Par exemple, la navigation dans toutes les directions de l'arborescence - trouvez un élément, puis allez chez ses grands-parents et recherchez un enfant de celui-ci ayant certaines propriétés.
Il permet des conditions booléennes intégrées - cond1 and not(cond2 or not(cond3 and cond4))
; sélecteurs intégrés - "trouver un div ayant ces enfants avec ces attributs, puis naviguer en fonction de celui-ci".
XPath permet une recherche basée sur la valeur d'un nœud (son texte) - aussi désapprouvée que cette pratique soit, elle est utile en particulier dans les documents mal structurés (pas d'attributs définis sur lesquels marcher, comme les identifiants et les classes dynamiques - localisez l'élément par son texte contenu) .
Le pas dans le CSS est certainement plus facile - on peut commencer à écrire des sélecteurs en quelques minutes; mais après quelques jours d'utilisation, la puissance et les possibilités de xpath ont rapidement dépassé le css.
Et purement subjectif - un CSS complexe est beaucoup plus difficile à lire qu'une expression xpath complexe.
Outro;)
Enfin, encore une fois très subjectif - lequel choisir?
OMI, il n'y a pas de bon ou de mauvais choix - ce sont des solutions différentes au même problème, et ce qui convient le mieux au travail doit être choisi.
Étant "fan" de XPath, je ne suis pas gêné d'utiliser dans mes projets un mélange des deux - diable, parfois il est beaucoup plus rapide d'en lancer un CSS, si je sais que cela fera très bien le travail.