Comprobando si existe un elemento con Python Selenium

8 minutos de lectura

avatar de usuario de nonshatter
inquebrantable

Tengo un problema; Estoy usando el controlador web Selenium (Firefox) para abrir una página web, hacer clic en algunos enlaces, etc. y luego capturar una captura de pantalla.

Mi secuencia de comandos funciona bien desde la CLI, pero cuando se ejecuta a través de un trabajo cron no pasa la primera prueba find_element(). Necesito agregar algo de depuración, o algo que me ayude a descubrir por qué está fallando.

Básicamente, tengo que hacer clic en un ancla de ‘iniciar sesión’ antes de ir a la página de inicio de sesión. La construcción del elemento es:

<a class="lnk" rel="nofollow" href="/login.jsp?destination=/secure/Dash.jspa">log in</a>

estoy usando el encontrar_elemento Por el método LINK_TEXT:

login = driver.find_element(By.LINK_TEXT, "log in").click()

A) ¿Cómo compruebo que el enlace realmente está siendo recogido por Python? ¿Debo usar el bloque try/catch?

B) ¿Existe una forma mejor/más fiable de localizar el DOM elemento que por LINK_TEXT? por ejemplo, en jQuerypuede usar un selector más específico, $(‘a.lnk:contains(log in)’).do_something();


Resolví el problema principal y solo era un problema con los dedos. Estaba llamando al script con parámetros incorrectos, un simple error.

Todavía me gustaría algunos consejos sobre cómo verificar si existe un elemento. Además, un ejemplo/explicación de esperas implícitas/explícitas en lugar de usar una llamada de mierda time.sleep().

  • También puede encontrar elementos por localizador CSS o xpath. Tiende a ser menos frágil que por el contenido del texto.

    –Silas Ray

    5 de marzo de 2012 a las 15:15

  • Creo que ambos, usando texto de contenido y XPATH/CSS, son frágiles a cambios menores en el diseño en lugar de la lógica de la aplicación. Una mejor manera sería encontrar el elemento ya sea id, class_name o name.

    – Kshitij Saraogi

    3 mayo 2017 a las 13:30

Avatar de usuario de Alex Okrushko
Alex Okrushko

Para):

from selenium.common.exceptions import NoSuchElementException
def check_exists_by_xpath(xpath):
    try:
        webdriver.find_element_by_xpath(xpath)
    except NoSuchElementException:
        return False
    return True

Para b): Además, puede tomar la expresión XPath como estándar en todos sus scripts y crear funciones como las mencionadas anteriormente para uso universal.

recomiendo usar Selectores de CSS. Recomiendo no mezclar/usar “por id”, “por nombre”, etc. y usar un solo enfoque en su lugar.

  • También debe pasar object: browser = webdriver.Firefox() a su función personalizada

    usuario2558887

    27 de junio de 2014 a las 14:08

  • En general, rara vez me he encontrado con páginas html que se ajusten a la idea de coincidencia uniforme. ¿Hay alguna manera de evitar las coincidencias mixtas de los métodos de localización en dichas páginas?

    – Kshitij Saraogi

    3 mayo 2017 a las 13:34

  • @KshitijSaraogi No estoy seguro de entender completamente su pregunta. Si se queda con que es imposible tener solo ‘selectores css’ en sus pruebas de controlador web, en realidad es bastante posible. He estado haciendo precisamente eso durante los últimos 6 años.

    – Alex Okrushko

    5 mayo 2017 a las 20:05

  • @AlexOkrushko ¿Cuáles son sus razones para recomendar selectores css sobre xpath?

    – BoZenKhaa

    13 de marzo de 2018 a las 14:19

  • @BoZenKhaa, al menos 2 razones: familiaridad con los selectores css para los desarrolladores, lo que contribuye a la legibilidad del código; xpath tuvo un rendimiento terrible en IE.

    – Alex Okrushko

    16 de marzo de 2018 a las 10:20

Avatar de usuario de Brian Leishman
Brian Leishmann

Puede tomar una lista de elementos en lugar de un solo elemento. Una lista vacía en python es falsa. Ejemplo:

if driver.find_elements(By.CSS_SELECTOR, '#element'):
    print "Element exists!"

También puedes usar By.ID y By.NAMEpero eso solo convierte su identificación o nombre en un selector css de todos modos. Fuente

  • ¿Es esto más rápido que el método anterior de manejo de excepciones?

    – Gal Braja

    17 de febrero de 2017 a las 10:41

  • @GalBracha Buena pregunta, supongo que probablemente dependerá de la versión y la plataforma, por lo que si la diferencia de velocidad es tan importante para usted aquí, le recomendaría probarlo en su plataforma de destino para obtener los mejores resultados. Sin embargo, hay un punto que debe señalarse aquí sobre las optimizaciones previas y la legibilidad del código podría ser más importante que la insignificante mejora del rendimiento en este caso.

    – Brian Leishmann

    17/02/2017 a las 14:00

  • La forma de búsqueda de elemento (singular) arroja una excepción cuando no se encuentra el elemento. Los elementos de búsqueda (plural con ‘s’) devolverán una lista vacía. En mi humilde opinión, todos los demás ejemplos que usan try-catch para ver si existe un elemento tienen un mal estilo de programación. Try-catch solo debe usarse para detectar situaciones inesperadas. Si cree que el elemento puede no existir, su código debe escribirse para manejar esa situación.

    – Bill Worthington

    8 de marzo de 2021 a las 14:37

  • @BillWorthington está de acuerdo al 100 %. No soy un desarrollador de Python, así que no sé qué es normal aquí, pero no escribiría cosas de esa manera en ningún otro idioma.

    – Brian Leishmann

    8 de marzo de 2021 a las 14:52

  • @BrianLeishman Estaba tratando de señalar que su ejemplo es la forma CORRECTA de hacerlo y que los OTROS ejemplos no tenían un buen estilo de programación.

    – Bill Worthington

    9 de marzo de 2021 a las 15:38

Avatar de usuario de Sam Woods
sam maderas

R) Sí. La forma más fácil de verificar si existe un elemento es simplemente llamar find_element dentro de una try/catch.

B) Sí, siempre trato de identificar elementos sin usar su texto por dos razones:

  1. es más probable que el texto cambie y;
  2. si es importante para usted, no podrá ejecutar sus pruebas en compilaciones localizadas.

La solución es:

  1. Puede usar XPath para encontrar un elemento padre o antepasado que tenga una ID o algún otro identificador único y luego encontrar su hijo/descendiente que coincida con o;
  2. puede solicitar una identificación o nombre o algún otro identificador único para el enlace en sí.

Para las preguntas de seguimiento, usando try/catch es cómo puede saber si un elemento existe o no y aquí se pueden encontrar buenos ejemplos de esperas: http://seleniumhq.org/docs/04_webdriver_advanced.html

  • Uno de los usos que tengo para buscar texto es ver si se muestra un mensaje flash exitoso o fallido. ¿No estás seguro de si hay una mejor manera de hacerlo?

    – Rob subvención

    06/10/2015 a las 14:34

  • Esas son razones absolutamente excelentes para evitar seleccionar por texto.

    – Kevlarr

    11/01/2018 a las 16:30

  • Esto fue útil, tenga en cuenta que ahora puede usar is_displayed(): selenium.dev/documentation/webdriver/elements/información

    – Raúl

    27 abr a las 9:10

  • El enlace está (efectivamente) roto. Redirige a una página genérica.

    -Peter Mortensen

    hace 13 horas

  • @Raoul: ¿No se encontraría eso con el problema de una excepción lanzada?

    -Peter Mortensen

    hace 12 horas

Avatar de usuario de Super Mario
Super Mario

Una solución sin try&catch y sin nuevas importaciones:

if len(driver.find_elements_by_id('blah')) > 0: # Pay attention: find_element*s*
    driver.find_element_by_id('blah').click # Pay attention: find_element

avatar de usuario de vmk
vmk

Lo mismo que Brian, pero agrega a esto respuesta de tstempko:

Probé y funciona rápidamente:

driver.implicitly_wait(0)

if driver.find_element_by_id("show_reflist"):
    driver.find_element_by_id("show_reflist").find_element_by_tag_name("img").click()

Después de esto, restauro mi valor predeterminado:

driver.implicitly_wait(30)

  • ¡sí! si sabe que la página ya está cargada, no querrá esperar 30 segundos para obtener su “retorno no existe”. esto vuelve inmediatamente, justo lo que necesitaba.

    – Welch

    11 de mayo de 2018 a las 6:32


  • ¿No arrojaría eso una excepción si algo no existe (el punto central de esta pregunta)? ¿Y por lo tanto no funciona realmente?

    -Peter Mortensen

    el dia de ayer


  • OK, el OP ha dejado el edificio: “Visto por última vez hace más de 1 año”. ¿Quizás alguien más pueda intervenir?

    -Peter Mortensen

    hace 13 horas

  • Del comentario de Bill Worthington: “La forma de búsqueda de elemento (singular) arroja una excepción cuando no se encuentra el elemento”.. Voluntad driver.implicitly_wait(0) evitar que se lance la excepción?

    -Peter Mortensen

    hace 12 horas


También podría hacerlo de manera más concisa usando

driver.find_element_by_id("some_id").size != 0

  • ¡sí! si sabe que la página ya está cargada, no querrá esperar 30 segundos para obtener su “retorno no existe”. esto vuelve inmediatamente, justo lo que necesitaba.

    – Welch

    11 de mayo de 2018 a las 6:32


  • ¿No arrojaría eso una excepción si algo no existe (el punto central de esta pregunta)? ¿Y por lo tanto no funciona realmente?

    -Peter Mortensen

    el dia de ayer


  • OK, el OP ha dejado el edificio: “Visto por última vez hace más de 1 año”. ¿Quizás alguien más pueda intervenir?

    -Peter Mortensen

    hace 13 horas

  • Del comentario de Bill Worthington: “La forma de búsqueda de elemento (singular) arroja una excepción cuando no se encuentra el elemento”.. Voluntad driver.implicitly_wait(0) evitar que se lance la excepción?

    -Peter Mortensen

    hace 12 horas


Avatar de usuario de Peter Mortensen
Pedro Mortensen

driver.find_element_by_id("some_id").size() es un método de clase.

Nosotros necesitamos:

driver.find_element_by_id("some_id").size que es un diccionario, entonces:

if driver.find_element_by_id("some_id").size['width'] != 0:
   print 'button exist'

  • esto no siempre es correcto, el ancho puede ser cero si el elemento también existe. el = driver.find_element_by_class_name(‘gNO89b’) el.size este es un elemento válido en la página de búsqueda de Google pero el ancho es 0

    – señor de los códigos

    6 oct 2020 a las 16:23

  • No creo que esto funcione. find_element_by_id() probablemente arroja una excepción si el elemento no existe (el punto central de esta pregunta).

    -Peter Mortensen

    hace 13 horas

  • Del comentario de Bill Worthington: “La forma de búsqueda de elemento (singular) arroja una excepción cuando no se encuentra el elemento”.

    -Peter Mortensen

    hace 12 horas

¿Ha sido útil esta solución?