web-dev-qa-db-fra.com

Localisation d'un élément par id

Quelle est la différence entre les techniques de localisation suivantes?

  1. element(by.id("id"));
  2. element(by.css("#id"));
  3. element(by.xpath("//*[@id='id']"));
  4. browser.executeScript("return document.querySelector('#id');");
  5. browser.executeScript("return document.getElementById('id');");

Et, du point de vue des performances , quel serait le moyen le plus rapide de localiser un élément par son id?

24
alecxe

Il est très difficile de répondre à votre question, certainement pour donner une seule réponse concluante. En fait, je suis tenté de signaler cette question comme "trop ​​large", ce qui est corroboré par les autres réponses et commentaires.

Prenez, par exemple, juste votre element(by.id("id"));. En parcourant la source Selenium, la plupart des pilotes prennent simplement l'identifiant que vous donnez et le transmettent au protocole Wire:

public WebElement findElementById(String using) {
  if (getW3CStandardComplianceLevel() == 0) {
    return findElement("id", using);
  } else {
    return findElementByCssSelector("#" + cssEscape(using));
  }
}

Comme vous le savez, chaque fournisseur de navigateur implémente son propre protocole de connexion dans un binaire distinct. N'hésitez pas à aller plus loin dans le code, à creuser un trou plus profond pour vous-même.

Pour les autres navigateurs qui ne prennent pas en charge le protocole Wire, par exemple HtmlUnit, vous avez juste quelque chose comme:

public List<WebElement> findElementsById(String id) {
  return findElementsByXPath("//*[@id='" + id + "']");
}

puis ils analysent le DOM disponible.

En ce qui concerne votre question de performance, tout ce que quelqu'un vous donnera sera 1) juste un sentiment , ou 2) un pur BS! Ce que vous pouvez déjà voir dans les autres réponses et commentaires que vous obtenez.

Pour obtenir une réponse réelle (prise en charge par les données réelles), il y a juste trop de variables à considérer:

  • Protocole de câblage tel qu'implémenté par différents fournisseurs de navigateurs, plus diverses optimisations dans différentes versions.
  • Moteurs DOM mis en œuvre par différents fournisseurs de navigateurs, ainsi que diverses optimisations dans différentes versions.
  • Moteurs JavaScript mis en œuvre par différents fournisseurs de navigateurs, ainsi que diverses optimisations dans différentes versions.

De plus, quels que soient les résultats que vous obtiendrez pour votre application Web/page Web, ils ne s'appliqueront pas à une autre application Web/page Web, en raison des différences dans le cadre utilisé pour créer ce site.

En bout de ligne: si vous êtes préoccupé par les tests de performances, le sélénium n'est pas la bonne réponse. Selenium est une bibliothèque de tests fonctionnels, optimisée pour vous donner la meilleure représentation de l'utilisateur final. La performance est une réflexion après coup.

Si votre objectif est de faire exécuter vos tests plus rapidement, votre temps sera mieux dépensé en regardant votre structure de test:

  • À quelle fréquence ouvrez-vous/fermez le navigateur? Il s'agit souvent de l'activité la plus longue dans un test.
  • À quelle fréquence actualisez-vous votre cache d'éléments, à quelle fréquence avez-vous besoin de? Pensez à déplacer vos éléments vers le modèle Page Factory, qui charge paresseusement tous les éléments pour vous.
  • Et bien sûr, le plus grand facteur d'accélération: exécuter vos tests en parallèle sur plusieurs machines.

Mais je pense que cela sort du sujet (certains pourraient suggérer "délire") de votre question initiale.

9
SiKing

Je pense juste à la perspective des performances et j'écris le script suivant pour vérifier le logo Google. Bien que le résultat soit déroutant, nous pouvons faire une estimation statistique du résultat.

querySelector et getElementById ont toujours de meilleurs résultats, sauf si le nombre d'essais est supérieur à 10K. Si nous comparons ces deux méthodes: getElementById est meilleur (29 sur 21).

Si nous les comparons là-bas, ID , CSS et XPATH , CSS est meilleur (29 sur 18 et 4), le deuxième est ID et le dernier XPATH.

Le résultat de mon test: getElementById, querySelector, CSS, ID, XPATH

Voir le tableau, le résultat et le script:

Le tableau montre le résultat en résumé pour 50 essais:

 1 2 3 4 5 
 ID 0 0 18 24 8 
 CSS 0 0 29 18 3 
 XPATH 0 0 4 12 34 
 QuerySelector 21 29 0 0 0 
 GetElementById 29 21 0 0 0 

Résultat avec diff de temps:

>>> for i in range(50):
...  test_time(1)
...
[('getElementById', 0.004777193069458008), ('querySelector', 0.006440162658691406), ('id', 0.015267133712768555), ('css', 0.015399932861328125), ('xpath', 0.015429019927978516)]
[('querySelector', 0.006442070007324219), ('getElementById', 0.00728607177734375), ('id', 0.013181924819946289), ('css', 0.014509916305541992), ('xpath', 0.015583992004394531)]
[('getElementById', 0.0063440799713134766), ('querySelector', 0.006493091583251953), ('css', 0.014523029327392578), ('id', 0.014902830123901367), ('xpath', 0.015790224075317383)]
[('getElementById', 0.007112026214599609), ('querySelector', 0.007357120513916016), ('id', 0.014781951904296875), ('css', 0.015780925750732422), ('xpath', 0.016005992889404297)]
[('getElementById', 0.006434917449951172), ('querySelector', 0.007117033004760742), ('id', 0.01497507095336914), ('css', 0.015005111694335938), ('xpath', 0.015393972396850586)]
[('querySelector', 0.00563812255859375), ('getElementById', 0.006503105163574219), ('css', 0.014302968978881836), ('id', 0.014812946319580078), ('xpath', 0.017061948776245117)]
[('querySelector', 0.0048770904541015625), ('getElementById', 0.006540060043334961), ('css', 0.014795064926147461), ('id', 0.015192985534667969), ('xpath', 0.016000986099243164)]
[('getElementById', 0.006265878677368164), ('querySelector', 0.006501913070678711), ('id', 0.014132022857666016), ('css', 0.01437997817993164), ('xpath', 0.014840841293334961)]
[('getElementById', 0.006368160247802734), ('querySelector', 0.006601095199584961), ('css', 0.01462101936340332), ('id', 0.014872074127197266), ('xpath', 0.016145944595336914)]
[('querySelector', 0.00642704963684082), ('getElementById', 0.006908893585205078), ('css', 0.014439105987548828), ('id', 0.014970064163208008), ('xpath', 0.015510082244873047)]
[('getElementById', 0.006404876708984375), ('querySelector', 0.006679058074951172), ('css', 0.014878988265991211), ('id', 0.01546788215637207), ('xpath', 0.015535116195678711)]
[('querySelector', 0.005848884582519531), ('getElementById', 0.008013010025024414), ('css', 0.014436006546020508), ('xpath', 0.01566910743713379), ('id', 0.015830039978027344)]
[('querySelector', 0.006299018859863281), ('getElementById', 0.006538867950439453), ('css', 0.014534950256347656), ('id', 0.014979124069213867), ('xpath', 0.01618194580078125)]
[('getElementById', 0.006415128707885742), ('querySelector', 0.006479978561401367), ('id', 0.014901876449584961), ('css', 0.014998912811279297), ('xpath', 0.01544499397277832)]
[('getElementById', 0.006515979766845703), ('querySelector', 0.006515979766845703), ('xpath', 0.014292001724243164), ('css', 0.014482975006103516), ('id', 0.015102863311767578)]
[('getElementById', 0.00574803352355957), ('querySelector', 0.006389141082763672), ('css', 0.014650821685791016), ('id', 0.014751911163330078), ('xpath', 0.01532888412475586)]
[('getElementById', 0.0063037872314453125), ('querySelector', 0.006974935531616211), ('id', 0.014775991439819336), ('css', 0.014935970306396484), ('xpath', 0.015460968017578125)]
[('getElementById', 0.0064661502838134766), ('querySelector', 0.0065021514892578125), ('id', 0.014723062515258789), ('css', 0.014946937561035156), ('xpath', 0.015508890151977539)]
[('getElementById', 0.006738901138305664), ('querySelector', 0.008143901824951172), ('css', 0.014575004577636719), ('xpath', 0.015228986740112305), ('id', 0.015702009201049805)]
[('getElementById', 0.006436824798583984), ('querySelector', 0.0064470767974853516), ('css', 0.014545917510986328), ('id', 0.014694929122924805), ('xpath', 0.015357017517089844)]
[('querySelector', 0.006292104721069336), ('getElementById', 0.006451845169067383), ('css', 0.014657020568847656), ('xpath', 0.01574397087097168), ('id', 0.016795873641967773)]
[('getElementById', 0.006443977355957031), ('querySelector', 0.006485939025878906), ('css', 0.013139009475708008), ('id', 0.014308929443359375), ('xpath', 0.015516042709350586)]
[('querySelector', 0.006464958190917969), ('getElementById', 0.006821870803833008), ('id', 0.016110897064208984), ('css', 0.01633286476135254), ('xpath', 0.017225980758666992)]
[('getElementById', 0.005715131759643555), ('querySelector', 0.008069992065429688), ('css', 0.014779090881347656), ('id', 0.01491093635559082), ('xpath', 0.015527963638305664)]
[('getElementById', 0.006309986114501953), ('querySelector', 0.006836891174316406), ('css', 0.01497507095336914), ('id', 0.015040159225463867), ('xpath', 0.02096104621887207)]
[('querySelector', 0.00616908073425293), ('getElementById', 0.007357120513916016), ('css', 0.014974832534790039), ('id', 0.015640974044799805), ('xpath', 0.016278982162475586)]
[('querySelector', 0.005301952362060547), ('getElementById', 0.0063440799713134766), ('id', 0.014526844024658203), ('css', 0.014657974243164062), ('xpath', 0.0162200927734375)]
[('querySelector', 0.005811929702758789), ('getElementById', 0.007221221923828125), ('css', 0.01259613037109375), ('xpath', 0.014851093292236328), ('id', 0.015043020248413086)]
[('getElementById', 0.006195068359375), ('querySelector', 0.007548093795776367), ('css', 0.01441502571105957), ('id', 0.01441812515258789), ('xpath', 0.016713857650756836)]
[('querySelector', 0.0050449371337890625), ('getElementById', 0.006323099136352539), ('id', 0.01497793197631836), ('css', 0.014984130859375), ('xpath', 0.015444040298461914)]
[('getElementById', 0.007039070129394531), ('querySelector', 0.008107900619506836), ('xpath', 0.015566825866699219), ('id', 0.015954017639160156), ('css', 0.01815509796142578)]
[('getElementById', 0.005831003189086914), ('querySelector', 0.007988214492797852), ('id', 0.014652013778686523), ('css', 0.014683008193969727), ('xpath', 0.01581597328186035)]
[('querySelector', 0.006363868713378906), ('getElementById', 0.006494998931884766), ('xpath', 0.01517796516418457), ('id', 0.016071796417236328), ('css', 0.017260074615478516)]
[('getElementById', 0.00633692741394043), ('querySelector', 0.007826089859008789), ('css', 0.014354944229125977), ('id', 0.015484809875488281), ('xpath', 0.017076969146728516)]
[('querySelector', 0.006349802017211914), ('getElementById', 0.006428956985473633), ('css', 0.01385188102722168), ('id', 0.014858007431030273), ('xpath', 0.016836166381835938)]
[('querySelector', 0.006417989730834961), ('getElementById', 0.007012844085693359), ('css', 0.01460719108581543), ('id', 0.014763832092285156), ('xpath', 0.015476226806640625)]
[('getElementById', 0.006266117095947266), ('querySelector', 0.0074520111083984375), ('id', 0.014987945556640625), ('css', 0.01515817642211914), ('xpath', 0.015646934509277344)]
[('getElementById', 0.006376981735229492), ('querySelector', 0.0064089298248291016), ('id', 0.01494598388671875), ('css', 0.015275001525878906), ('xpath', 0.01553201675415039)]
[('getElementById', 0.006357908248901367), ('querySelector', 0.006699085235595703), ('css', 0.014505147933959961), ('xpath', 0.015446186065673828), ('id', 0.019747018814086914)]
[('getElementById', 0.0063610076904296875), ('querySelector', 0.0064640045166015625), ('css', 0.014472007751464844), ('id', 0.014828205108642578), ('xpath', 0.01532888412475586)]
[('getElementById', 0.0063610076904296875), ('querySelector', 0.006580829620361328), ('css', 0.012439966201782227), ('id', 0.014935016632080078), ('xpath', 0.015373945236206055)]
[('querySelector', 0.006309032440185547), ('getElementById', 0.006561994552612305), ('id', 0.014923095703125), ('css', 0.015380859375), ('xpath', 0.01574110984802246)]
[('querySelector', 0.006357908248901367), ('getElementById', 0.006387948989868164), ('css', 0.01481485366821289), ('id', 0.015089988708496094), ('xpath', 0.015390872955322266)]
[('querySelector', 0.004536867141723633), ('getElementById', 0.00640416145324707), ('css', 0.014551877975463867), ('xpath', 0.014974117279052734), ('id', 0.014991998672485352)]
[('getElementById', 0.006387233734130859), ('querySelector', 0.00643610954284668), ('css', 0.014494895935058594), ('id', 0.014873981475830078), ('xpath', 0.015212059020996094)]
[('getElementById', 0.0063588619232177734), ('querySelector', 0.006443977355957031), ('css', 0.013200998306274414), ('id', 0.014631986618041992), ('xpath', 0.015624046325683594)]
[('getElementById', 0.0048558712005615234), ('querySelector', 0.005300045013427734), ('id', 0.014750003814697266), ('css', 0.014846086502075195), ('xpath', 0.015408992767333984)]
[('querySelector', 0.008347034454345703), ('getElementById', 0.008370161056518555), ('id', 0.014650106430053711), ('css', 0.014775991439819336), ('xpath', 0.015323877334594727)]
[('querySelector', 0.006309032440185547), ('getElementById', 0.007323026657104492), ('css', 0.014546871185302734), ('xpath', 0.015864133834838867), ('id', 0.02078390121459961)]
[('querySelector', 0.007790088653564453), ('getElementById', 0.010209083557128906), ('id', 0.015320062637329102), ('xpath', 0.01600193977355957), ('css', 0.01807403564453125)]

Code:

from timeit import default_timer as timer
import time, operator
from Selenium import webdriver

def open_browser():
    dr = webdriver.Chrome()
    dr.get('http://www.google.com')
    time.sleep(5)
    return dr,timer()

def quit_browser(el, start, dr, result):
    diff = timer() - float(start)
    result[el] = diff
    dr.quit()

def test_time(tm):
    result = {}

    dr, start = open_browser()
    for i in range(tm):
        dr.find_element_by_id('hplogo')
    quit_browser("id", start, dr, result)

    dr, start = open_browser()
    for i in range(tm):
        dr.find_element_by_css_selector('#hplogo')
    quit_browser("css", start, dr, result)

    dr, start = open_browser()
    for i in range(tm):
        dr.find_element_by_xpath("//*[@id='hplogo']")
    quit_browser("xpath", start, dr, result)

    dr, start = open_browser()
    for i in range(tm):
        dr.execute_script("return document.querySelector('#hplogo');")
    quit_browser("querySelector", start, dr, result)

    dr, start = open_browser()
    for i in range(tm):
        dr.execute_script("return document.getElementById('hplogo');")
    quit_browser("getElementById", start, dr, result)

    print sorted(result.items(), key=operator.itemgetter(1))
6
Mesut GÜNEŞ

Identifier les différences serait assez difficile. Voici quelques choses que j'ai trouvées -

executeScript() planifie une commande pour exécuter JavaScript sous forme de chaîne dans le contexte du cadre ou de la fenêtre actuellement sélectionné. Bien que cela soit rapide, la lisibilité du code est faible.

element() fonction à son tour se résout en findElement() fonction qui planifie une commande pour trouver l'élément sur le DOM. Meilleure lisibilité.

Du point de vue des performances selon moi, voici les classements en ordre croissant en commençant par les plus rapides et tous étaient proches les uns des autres avec des différences en quelques millisecondes -

1 - browser.executeScript("return document.getElementById('id');");
2 - browser.executeScript("return document.querySelector('#id');");
3 - element(by.id("id"));
4 - element(by.css("#id"));
5 - element(by.xpath("//*[@id='id']"));

La raison pour laquelle javascript executeScript() est si rapide est que la commande est exécutée directement sur DOM sans conversion. Ce lien justifie leur classement entre eux .

Les localisateurs element() spécifiques au rapporteur restants sont lents car le rapporteur doit convertir les commandes pour obtenir les éléments Web à l'aide de la fonction findElement(). Obtenir l'élément par id est plus rapide que d'utiliser css et xpath (Cela dépend également de la façon dont les localisateurs sont utilisés et peut souvent changer en fonction de l'utilisation).

REMARQUE: L'analyse des performances ci-dessus était la moyenne de nombreux tests que j'ai exécutés localement sur ma machine, mais elle peut différer en fonction des tâches système qui affectent en interne l'exécution les scripts de test.

J'espère que cela aide.

4
Girish Sortur

TL; DR; performances afin de rapide à lent.

  • element(by.id("id"));
  • element(by.css("#id"));
  • element(by.xpath("//*[@id='id']"));
  • browser.executeScript("return document.getElementById('id');");
  • browser.executeScript("return document.querySelector('#id');");

Je veux bien essayer. Je vais essayer de l'expliquer jusqu'au point de Protractor et WebdriverJS. Comme je n'écris pas Selenium ou les pilotes du navigateur (par exemple Chromedriver, Firefoxdriver... etc ...) qui est la communication entre les navigateurs et Selenium . Pour cela, je vais utiliser la connaissance standard du moteur du navigateur pour ce point. Par conséquent, la réponse ne sera pas exacte à 100% mais surtout.

Je séparerai 5 méthodes en 2 groupes:

1. Communications communes

Pour les 3 premières méthodes:

élément (by.id ("id"));

élément (by.css ("# id"));

element (by.xpath ("// * [@ id = 'id']"));

Ce sont tous des résultats avec une seule requête HTTP au serveur Selenium. Ce qui est: '/session/:sessionId/element/:id/element'

Avec 2 paramètres:

  • using: type de :id. Exemple: 'css select', 'id', 'xpath', 'link text' ... etc.
  • value: valeur de :id. Exemple 'element-id', '.element-css > .child', //*[@id='id']

À ce stade, Selenium répondra à la demande en fonction de ce qui est demandé par le biais de Chromedriver, Firefoxdriver... etc ...

Sous Webdriver find-element-strategy.js . Il semble que les méthodes soient mappées avec ce que le navigateur fournit par les propriétés javascript document. Nous avons tag, id, css selector, xpath... etc. qui correspondent à document.elementByTagName, document.elementByID, document.querySelecotr, document.evaluate ...

Logiquement, du point de vue d'un codeur, je dirai que la ressource doit être réutilisée quelle que soit la façon dont ces pilotes ont été écrits. Par exemple, une demande de quête pour id, il est probable que quelque chose comme getElementById soit déclenché côté navigateur via le pilote de communication.

=> [~ # ~] résumé [~ # ~] Donc au final nous avons:

  • css selector Équivalent de querySelector
  • id équivalent de getElementById
  • xpath équivalent de evaluate

2. Injection de communications

Pour les 2 dernières méthodes:

browser.executeScript ("return document.querySelector ('# id');");

browser.executeScript ("return document.getElementById ('id');");

Ce sont tous des résultats avec une seule requête HTTP au serveur Selenium. Ce qui est: '/session/:sessionId/execute'

Avec 2 paramètres:

  • script: texte javascript ('string') ou function
  • args: arguments est un array

Jusqu'à ce stade, il s'agit de savoir comment JS a été injecté dans le navigateur, car aucun de nous ne peut être sûr du comportement (en utilisant devtools ou en injectant <script> Dans HTML). Supposons simplement que ce sera le même pour tous les navigateurs.

=> [~ # ~] résumé [~ # ~] Donc à la fin nous analyserons:

  • querySelector
  • getElementById

Comparaison principale

1. element() vs browser.executeScript():

  • element () Original fait pour localiser les éléments. Il utilise tout le profil de méthode par navigateur et pilote de communication. Cela se traduira par des performances plus rapides
  • browser.executeScript () était original pas fait pour être utilisé pour localiser un élément. Mais pour exécuter un script, en l'utilisant, nous obtenons bien sûr le même résultat mais en passant par des moyens plus compliqués pour atteindre le même objectif. Par conséquent, cela entraînera un calcul plus compliqué que l'utilisation de l'élément Finder. Et a fini par entraîner une performance plus lente.

=> RÉSUMÉ rapide à lent

  • element()
  • browser.executeScript()

2. document.querySelector() vs document.getElementById() vs document.querySelector():

Encore une fois, chaque navigateur entraînera une légère différence. Mais il y a déjà des recherches à ce sujet. Je vais simplement utiliser quelle communauté a été trouvée.

CSS selector Sachant que plus vite que xpath ( source )

document.querySelector()> PLUS RAPIDE> document.evaluate()

(REMARQUE: xpath n'est pas pris en charge par IE, donc Selenium utilise son propre moteur xpath chaque fois que vous utilisez xpath sur IE avec rapporteur)

Le jsperf.com nous avons obtenu ce test ce dicton

document.getElementById()> PLUS RAPIDE> document.querySelector()

=> SOMMAIRE rapide à lent

  • document.getElementById()
  • document.querySelector()
  • document.evaluate()

3. Résumer les performances de la méthode de rapide à lent

  • element(by.id("id"));
  • element(by.css("#id"));
  • element(by.xpath("//*[@id='id']"));
  • browser.executeScript("return document.getElementById('id');");
  • browser.executeScript("return document.querySelector('#id');");
4
Linh Pham

Ce serait une réponse large si quelqu'un essaie d'y répondre, je vais donc essayer de le rendre aussi simple que possible.

Ce ne sont que différentes façons de trouver des éléments à l'aide de sélénium. La raison pour laquelle nous avons tant d'alternatives pour sélectionner des éléments est que nous n'aurons pas toujours un identifiant ou une classe étiqueté sur un élément. Pour les éléments qui n'ont ni id, ni classe, ni nom, la seule option qui nous reste est XPATH.

XPATH peut être utilisé pour identifier de manière unique n'importe quel élément dans un XML et puisque HTML (HTML 5 pour être précis, s'il est écrit conformément aux normes) est une instance de XML, nous pouvons utiliser XPATH pour identifier de manière unique chaque élément du fichier.

OK alors pourquoi ne pas utiliser XPATH tout le temps? Pourquoi tant d'alternatives? Simple, XPATH est difficile à écrire. Par exemple, si nous devons obtenir le XPATH d'un 'td' qui appartient à une table imbriquée dans 2 autres tables. XPATH sera assez long et la plupart du temps, nous avons tendance à faire une erreur.

Trouver XPATH dans firefox est assez simple, installez simplement firepath ou firebug et faites un clic droit sur l'élément et sélectionnez COPY XPATH.

Instructions détaillées sur les indicateurs en sélénium: ici (présenté en Java mais aidera en général)

0
Revanth Kumar