selenium - Ubicar un elemento por id
xpath selenium-webdriver (5)
TL; DR; rendimiento en orden de rápido a lento.
-
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'');");
Voy a intentar esto. Trataré de explicarlo hasta el punto de Protractor
y WebdriverJS
. Como no estoy escribiendo Selenium
o los controladores del navegador (por ejemplo, Firefoxdriver
, Firefoxdriver
... etc ...) que es la comunicación entre los navegadores y el Selenium
. Para esto, utilizaré el conocimiento estándar del motor del navegador para este punto. Por lo tanto, la respuesta, no será 100% precisa, sino principalmente.
Separé 5 métodos en 2 grupos:
1. Comunicaciones comunes
Para los primeros 3 métodos:
elemento (by.id ("id"));
elemento (by.css ("# id"));
elemento (by.xpath ("// * [@ id = ''id'']"));
Todos estos son resultados con una única solicitud HTTP al servidor Selenium. Que es: ''/session/:sessionId/element/:id/element''
Con 2 parámetros:
-
using
: tipo de:id
. Ejemplo:''css select''
,''id''
, ''xpath''
,''link text''
... etc. -
value
: valor de:id
. Ejemplo''element-id''
,''.element-css > .child''
,//*[@id=''id'']
En este punto, Selenium
responderá a la solicitud de acuerdo con lo que se solicita a través de Chromedriver
, Firefoxdriver
... etc ...
En Webdriver find-element-strategy.js . Como parece, los métodos se asignan con qué navegador proporciona las propiedades del document
JavaScript. Obtuvimos tag
, id
, css selector
, xpath
... etc. que se corresponden con document.elementByTagName
, document.elementByID
, document.querySelecotr
, document.evaluate
...
Lógicamente, en el punto de vista de un codificador, diré que el recurso debe reutilizarse sin importar cómo se escribieron estos controladores. Por ejemplo, solicitud de búsqueda de id
. Probablemente se active algo como getElementById
en el lado del navegador a través del controlador de comunicación.
=> RESUMEN Así que al final tenemos:
-
css selector
equivalente dequerySelector
-
id
equivalente agetElementById
-
xpath
equivalente deevaluate
2. Inyección de comunicaciones
Para 2 últimos métodos:
browser.executeScript ("return document.querySelector (''# id'');");
browser.executeScript ("return document.getElementById (''id'');");
Todos estos son resultados con una única solicitud HTTP al servidor Selenium. Que es: ''/session/:sessionId/execute''
Con 2 parámetros:
-
script
: javascript text (''string''
) o unafunction
-
args
: arguments es unaarray
Hasta este punto, se trata de cómo se inyectó JS en el navegador, ya que ninguno de nosotros puede estar seguro del comportamiento (ya sea usando devtools
o inyectando <script>
en HTML). Supongamos que será el mismo para todos los navegadores.
=> RESUMEN Así que al final analizaremos:
-
querySelector
-
getElementById
Comparación principal
1. element()
vs browser.executeScript()
:
- elemento () Original creado para ubicar elementos. Está utilizando todo el perfil del método por el navegador y su controlador de comunicación. Esto dará como resultado un rendimiento más rápido
- browser.executeScript () no fue original para usar para localizar un elemento. Pero para ejecutar un guión, al usarlo, por supuesto, estamos obteniendo el mismo resultado pero estamos pasando por una forma más complicada de lograr el mismo objetivo. Por lo tanto, esto dará como resultado un cálculo más complicado que usar el buscador de elementos. Y terminó resultado un rendimiento más lento.
=> RESUMEN rápido a lento
-
element()
-
browser.executeScript()
2. document.querySelector()
vs document.getElementById()
vs document.querySelector()
:
De nuevo, cada navegador tendrá una ligera diferencia. Pero ya hay algo de investigación sobre esto. Usaré qué comunidad se ha encontrado.
CSS selector
es más rápido que xpath
( source )
document.querySelector()
> FASTER> document.evaluate()
(NOTA: xpath no es compatible con IE, por lo que el selenio usa su propio motor xpath cuando se usa xpath en IE con transportador)
En jsperf.com
obtuvimos jsperf.com prueba que decía
document.getElementById()
> FASTER> document.querySelector()
=> RESUMEN rápido a lento
-
document.getElementById()
-
document.querySelector()
-
document.evaluate()
3. Suma el rendimiento del método de rápido a lento
-
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'');");
¿Cuál es la diferencia entre las siguientes técnicas de ubicación?
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'');");
Y, desde la perspectiva del rendimiento , ¿cuál sería la forma más rápida de localizar un elemento por identificación?
Identificar las diferencias sería bastante difícil. Aquí hay algunas cosas que encontré
executeScript()
programa un comando para ejecutar JavaScript como una cadena en el contexto del marco o ventana actualmente seleccionado. Aunque esto es rápido, la legibilidad del código es baja.
element()
a su vez resuelve la función findElement()
que programa un comando para encontrar el elemento en el DOM. Legibilidad mejorada
Desde la perspectiva del rendimiento según yo, aquí están las clasificaciones en orden ascendente comenzando por las más rápidas y todas ellas estaban cerca una de la otra con diferencias en pocos milisegundos.
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'']"));
El motivo por el cual javascript executeScript()
es tan rápido es porque el comando se ejecuta en DOM directamente sin conversiones. Este enlace justifica su clasificación entre ellos .
Los localizadores restantes del element()
específico del transportador element()
son lentos, ya que el transportador necesita convertir los comandos para obtener los elementos web utilizando la función findElement()
. Obtener elemento por id
es más rápido que utilizar css
y xpath
(esto también depende de cómo se usan los localizadores y, a menudo, puede cambiar en función del uso).
NOTA: El análisis de rendimiento anterior fue el promedio de muchas pruebas que ejecuté localmente en mi máquina, pero puede diferir en función de las tareas del sistema que afectan internamente la ejecución de las secuencias de comandos de prueba.
Espero eso ayude.
Sería una respuesta amplia si alguien intenta responder, así que trataré de hacerlo lo más simple posible.
Estas son solo formas diferentes de encontrar elementos usando selenio. La razón por la que tenemos tantas alternativas para seleccionar elementos es que no siempre tendremos identificación o clase etiquetada en un elemento. Para los elementos que no tienen identificación o clase o nombre, la única opción que nos queda es XPATH.
XPATH se puede utilizar para identificar de manera única cualquier elemento en un XML y dado que HTML (HTML 5 para ser precisos, si se escribe de acuerdo con los estándares) es una instancia de XML, podemos usar XPATH para identificar de forma única cada elemento en el archivo.
Bien, entonces ¿por qué no usar XPATH todo el tiempo? ¿Por qué tantas alternativas? Simple, XPATH es difícil de escribir. Por ejemplo, si necesitamos obtener el XPATH de un ''td'' que pertenece a una tabla anidada dentro de otras 2 tablas. XPATH será bastante largo y la mayoría de las veces tendemos a cometer un error.
Encontrar XPATH en Firefox es bastante directo, simplemente instale firepath o firebug y haga clic derecho en el elemento y seleccione COPY XPATH.
Instrucciones detalladas sobre indicadores en selenio: here (presentado en Java pero ayudará en general)
Solo pienso en la perspectiva del rendimiento y escribo el siguiente script para verificar el logotipo de google. Aunque el resultado es confuso, podemos hacer una estimación del resultado estadísticamente.
querySelector y getElementById siempre tienen un mejor resultado, a menos que el número de intentos sea superior a 10K. Si comparamos estos dos métodos: getElementById es mejor (29 sobre 21).
Si comparamos estos, ID , CSS y XPATH , CSS es mejor (29 sobre 18 y 4), el segundo es ID y el último XPATH.
El resultado de mi prueba: getElementById, querySelector, CSS, ID, XPATH
Ver la tabla, resultado y script:
La tabla muestra el resultado en resumen para 50 intentos:
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
Resultado con diferencia de tiempo:
>>> 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)]
Código:
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))
Su pregunta es muy difícil de responder, sin duda para dar una única respuesta concluyente. De hecho, estoy tentado de señalar esta pregunta como "demasiado amplia", que es respaldada por otras respuestas y comentarios.
Tome, por ejemplo, solo su element(by.id("id"));
. Mirando a través de la fuente de Selenium, la mayoría de los controladores simplemente toman cualquier identificación que usted dé y la pasan al protocolo de conexión:
public WebElement findElementById(String using) {
if (getW3CStandardComplianceLevel() == 0) {
return findElement("id", using);
} else {
return findElementByCssSelector("#" + cssEscape(using));
}
}
Como usted sabe, cada proveedor de navegador implementa su propio protocolo de cable en un binario separado. Siéntete libre de profundizar en el código, para cavar un agujero más profundo para ti.
Para otros navegadores que no son compatibles con el protocolo de conexión, por ejemplo HtmlUnit, solo tiene algo como:
public List<WebElement> findElementsById(String id) {
return findElementsByXPath("//*[@id=''" + id + "'']");
}
y luego analizan el DOM disponible.
En cuanto a su pregunta de rendimiento, cualquier cosa que alguien le dé será 1) solo un sentimiento , o 2) BS puro! Que ya puede ver a partir de las otras respuestas y comentarios que está recibiendo.
Para obtener una respuesta real (respaldada por datos reales), hay demasiadas variables a considerar:
- Protocolo Wire implementado por diferentes proveedores de navegadores, más varias optimizaciones en diferentes versiones.
- Motores DOM implementados por diferentes proveedores de navegadores, más varias optimizaciones en diferentes versiones.
- Motores JavaScript implementados por diferentes proveedores de navegadores, más varias optimizaciones en diferentes versiones.
Además, cualquiera que sea el resultado que obtenga para su aplicación web / página web, lo más probable es que no se aplique a una aplicación web / página web diferente, debido a las diferencias en el marco utilizado para construir ese sitio.
La conclusión es: si le preocupan las pruebas de rendimiento, el selenio es la respuesta incorrecta. Selenium es una biblioteca de pruebas funcional, optimizada para ofrecerle la mejor representación del usuario final. El rendimiento es una idea de último momento.
Si su objetivo es que sus pruebas se ejecuten más rápido, le conviene dedicar más tiempo a observar su estructura de prueba:
- ¿Con qué frecuencia abres / cierras el navegador? Esta suele ser la actividad que consume más tiempo en una prueba.
- ¿Con qué frecuencia actualiza su caché de elementos, con qué frecuencia lo necesita ? Considere mover sus elementos al modelo de Página de Fábrica , que carga todos los elementos por su cuenta.
- Y, por supuesto, el mayor factor de aceleración: ejecutar sus pruebas en paralelo en varias máquinas.
Pero creo que esto se está desviando del tema (algunos podrían sugerir "ranty") de su pregunta inicial.