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 son id?
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:
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:
Mais je pense que cela sort du sujet (certains pourraient suggérer "délire") de votre question initiale.
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))
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.
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.
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
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
element()
vs browser.executeScript()
:=> RÉSUMÉ rapide à lent
element()
browser.executeScript()
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()
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');");
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)