Localisation d'un élément par id
Quelle est la différence entre les techniques de localisation suivantes?
-
element(by.id("id"));
element(by.css("#id"));
element(by.xpath("//*[@id='id']"));
browser.executeScript("return document.querySelector('#id');");
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 id?
5 réponses
Votre question est très difficile à répondre, certainement pour donner une seule réponse concluante. En fait, je suis tenté de signaler cette question comme "trop large", ce qui est soutenu par les autres réponses et commentaires.
Prenez, par exemple, juste votre element(by.id("id"));
. En regardant à travers la source de sélénium, 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 fil dans un binaire séparé. N'hésitez pas à aller plus loin dans le code, creuser un trou plus profond de votre auto.
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 + "']");
}
Et puis ils analysent le DOM disponible.
En ce qui concerne votre question de performance, tout ce que quelqu'un vous donne sera 1) juste un sentiment , ou 2) pur BS! Ce que vous pouvez déjà voir à partir des autres réponses et commentaires que vous obtenez.
Pour obtenir un réel réponse (soutenue par les données réelles), il y a juste trop de variables à considérer:
- protocole Wire tel qu'implémenté par différents fournisseurs de navigateurs, ainsi que diverses optimisations dans différentes versions.
- moteurs DOM implémentés par différents fournisseurs de navigateurs, ainsi que diverses optimisations dans différentes versions.
- moteurs JavaScript implémentés par différents fournisseurs de navigateurs, ainsi que diverses optimisations dans différentes versions.
Aussi, quels que soient les résultats vous obtenez pour votre application web / page web sera plus comme ne pas s'appliquer à une autre application web / page web, en raison des différences dans la structure utilisée pour construire ce site.
L'essentiel est: si vous êtes préoccupé par les tests de performance, alors le sélénium est la mauvaise 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 lointaine après coup.
Si votre objectif est de faire fonctionner vos tests plus rapidement, votre temps sera mieux dépensé en regardant votre structure de test:
- à quelle fréquence ouvrez-vous/fermez-vous le navigateur. C'est souvent l'activité qui prend le plus de temps dans un test.
- à quelle fréquence actualisez-vous votre cache d'éléments, à quelle fréquence avez-vous besoin de? Envisagez de déplacer vos éléments vers la pageFactory model, 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 c'est sortir du sujet (certains pourraient suggérer "ranty") de votre question initiale.
Je pense juste à la perspective de performance et écris le script suivant pour vérifier le logo google. Bien que le résultat soit source de confusion, nous pouvons faire une estimation statistique du résultat.
QuerySelector et getElementById ont toujours un meilleur résultat, sauf si le nombre d'essais est supérieur à 10K. si l'on compare ces deux méthodes: getElementById est meilleur (29 sur 21).
Si l'on compare ces il y, ID, CSS et XPATH, CSS est mieux (29 sur 18 et 4), le second 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))
TL; DR; performance dans l'ordre 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 vais donner à ceci un essai. 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, l' réponse, il ne sera pas précis à 100% mais surtout.
Je vais séparer 5 méthodes en 2 groupes:
1. Communications communes
Pour les 3 premières méthodes:
Élément(by.id ("id"));
Élément (par.css ("#id"));
Élément (par.xpath("//*[@id='id']"));
Ce sont tous des résultats avec une seule requête HTTP au serveur Selenium. 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, {[7] } répondra à la demande en conséquence à ce qui est demandé par l'un ou l'autre des Chromedriver
, Firefoxdriver
... etc...
Sous Webdriver trouver des éléments de stratégie.js . Comme il semble que les méthodes sont mappées avec quel navigateur fournit par JavaScript document
propriétés. Nous avons eu tag
, id
, css selector
, xpath
... etc.. qui sont jumelés avec document.elementByTagName
, document.elementByID
, document.querySelecotr
, document.evaluate
...
Logiquement, du point de vue d'un codeur, je dirai que la ressource devrait être réutilisée indépendamment de la façon dont ces pilotes ont été écrits. Par exemple, la demande de quête pour id
sera probablement quelque chose comme getElementById
qui doit être déclenchée du côté du navigateur via le pilote de communication.
=> résumé donc, à la fin, nous avons:
-
css selector
équivalent dequerySelector
-
id
équivalent degetElementById
-
xpath
équivalent deevaluate
2. Injection de communications
Pour 2 dernières méthodes:
Navigateur.executeScript ("retourner le document.querySelector('#id');");
Navigateur.executeScript ("retourner le document.getElementById ('id');");
Ce sont tous des résultats avec une seule requête HTTP au serveur Selenium. Qui est:
'/session/:sessionId/execute'
Avec 2 paramètres:
-
script
: texte javascript ('string'
) ou unfunction
-
args
: arguments est unarray
Jusqu'à ce point, il est sur la façon dont JS a été injecté dans le navigateur, car aucun d'entre nous ne peut être sûr du comportement (soit en utilisant devtools
ou injecter <script>
dans HTML). Supposons simplement que ce sera le même pour tous les navigateurs.
=> résumé donc, à la fin, nous allons analyser:
-
querySelector
getElementById
Comparaison principale
1. element()
vs browser.executeScript()
:
- element () {[127] } original fait pour localiser les éléments. Il utilise tout le profil de méthode par navigateur et pilote de communication informatique. Cela se traduira par des performances plus rapides
- navigateur.executeScript () {[127] } était original pas 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 une manière plus compliquée pour atteindre le même objectif. Par conséquent, cela se traduira par un calcul plus compliqué que d'utiliser element finder. Et a fini par résultat une performance plus lente.
=> résumé rapide à lent
element()
browser.executeScript()
2. document.querySelector()
vs document.getElementById()
vs document.querySelector()
:
Nouveau chaque navigateur entraînera une légère différence. Mais il y a déjà quelques recherches à ce sujet. Je vais juste utiliser ce que la communauté a été trouver.
CSS selector
être que plus rapide que xpath
(source)
document.querySelector()
> plus RAPIDE > document.evaluate()
(NOTE: xpath n'est pas supporté par IE, donc selenium utilise son propre moteur xpath chaque fois que vous utilisez xpath sur IE avec protractor)
Sur jsperf.com
nous avons eu cette test en disant:
document.getElementById()
> plus RAPIDE > document.querySelector()
=> RÉSUMÉ de 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');");
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 ce soit rapide, la lisibilité du code est faible.
element()
fonction, à son tour, décide de findElement()
fonction qui planifie une commande pour trouver l'élément du DOM. Amélioration de la lisibilité.
Du point de vue de la performance selon moi, voici les classements dans l'ordre croissant en commençant par le plus rapide 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 le javascript executeScript()
est si rapide est que la commande est exécutée directement sur DOM sans conversions. ce lien justifie leur classement entre eux .
Les localisateurs element()
spécifiques à protractor restants sont lents car protractor doit convertir les commandes pour obtenir les éléments web utilisation 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 des scripts de test.
J'espère que ça aide.
Ce serait une réponse large si quelqu'un essaie d'y répondre donc je vais essayer de le rendre aussi simple que possible.
Ce ne sont que différentes façons de trouver des éléments en utilisant du sélénium. La raison pour laquelle nous avons tant d'alternatives pour sélectionner des éléments n'est pas toujours que nous aurons un identifiant ou une classe étiqueté à un élément. Pour les éléments qui n'ont pas d'id ou de classe ou de 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 depuis HTML (HTML 5 pour être précis, si écrit selon les normes) est une instance de XML, nous pouvons utiliser XPATH pour identifier de manière unique chaque élément dans le fichier.
OK alors pourquoi ne pas utiliser XPATH tout le temps? Pourquoi tant d'alternatives? Simple, XPATH est difficile à écrire. Par exemple, si nous avons besoin d'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 avant, il suffit d'installer firepath ou firebug et faites un clic droit sur l'élément et sélectionnez Copier XPATH.
Instructions détaillées sur les indicateurs en sélénium: ici (présenté en java mais aidera en général)