Mostrando las entradas con la etiqueta selenium. Mostrar todas las entradas
Mostrando las entradas con la etiqueta selenium. Mostrar todas las entradas

Alternativas a XPath en Selenium: Cómo localizar elementos de manera eficiente

En Selenium, puedes localizar elementos usando diferentes estrategias además de By.XPATH. Aquí te dejo las alternativas y cómo obtenerlas en cada caso.


🔹 Alternativas a By.XPATH y cómo obtenerlas

Método Descripción Ejemplo
By.ID Busca por el atributo id del elemento. By.ID, "miElemento"
By.NAME Busca por el atributo name del elemento. By.NAME, "usuario"
By.CLASS_NAME Busca por el atributo class del elemento. By.CLASS_NAME, "boton-login"
By.TAG_NAME Busca por el tipo de etiqueta HTML. By.TAG_NAME, "button"
By.LINK_TEXT Busca enlaces (<a>) por su texto exacto. By.LINK_TEXT, "Iniciar sesión"
By.PARTIAL_LINK_TEXT Busca enlaces por una parte del texto. By.PARTIAL_LINK_TEXT, "Iniciar"
By.CSS_SELECTOR Busca usando selectores CSS. By.CSS_SELECTOR, ".clase .subclase"

Ejemplo con cada alternativa:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Espera hasta que el elemento esté presente usando diferentes métodos
elemento_id = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.ID, "miElemento")))
elemento_name = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.NAME, "usuario")))
elemento_class = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, "boton-login")))
elemento_tag = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, "button")))
elemento_link = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.LINK_TEXT, "Iniciar sesión")))
elemento_partial_link = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "Iniciar")))
elemento_css = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".clase .subclase")))

🔹 ¿Cómo obtener estos valores en la web?

Puedes inspeccionar los elementos en el navegador (F12 → "Inspeccionar elemento") y obtenerlos de la siguiente manera:

  1. ID → Busca id="miElemento" en el HTML.
  2. NAME → Busca name="usuario".
  3. CLASS_NAME → Usa .clase si tiene class="boton-login".
  4. TAG_NAME → Usa button, input, div, etc.
  5. LINK_TEXT → Usa el texto visible de un enlace (<a>).
  6. PARTIAL_LINK_TEXT → Usa parte del texto del enlace.
  7. CSS_SELECTOR → Usa selectores CSS como .clase, #id, [atributo="valor"], etc.

🔥 ¿Cuándo usar cada uno?

  • ID → La mejor opción si el elemento tiene un id único.
  • NAME → Útil si hay varios elementos con el mismo nombre (ejemplo: formularios).
  • CLASS_NAME → Bueno si la clase es específica y única.
  • TAG_NAME → Si buscas todos los elementos de un tipo (button, input).
  • LINK_TEXT → Si es un enlace (<a>) con texto fijo.
  • PARTIAL_LINK_TEXT → Si el enlace tiene texto variable.
  • CSS_SELECTOR → Más rápido que XPath en muchos casos, útil para estructuras complejas.
  • XPATH → Más flexible para navegar por estructuras complejas.

Si el id o name están disponibles, úsalos en lugar de XPATH para un mejor rendimiento. 🚀

find_element en Selenium no funciona: causas y soluciones

Si el botón existe pero el código no funciona, aquí hay varias razones posibles y soluciones:

1. El botón aún no está disponible en el DOM

Aunque el botón exista, puede que Selenium intente encontrarlo antes de que esté completamente cargado. Prueba usar WebDriverWait:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

elemento = WebDriverWait(self.driver, 10).until(
    EC.presence_of_element_located((By.XPATH, xpath_boton_login))
)

🔹 Esto espera hasta 10 segundos a que el botón aparezca en el DOM antes de continuar.


2. El botón no es interactuable

Puede que el botón esté en el DOM, pero todavía no sea clickeable. Usa element_to_be_clickable:

elemento = WebDriverWait(self.driver, 10).until(
    EC.element_to_be_clickable((By.XPATH, xpath_boton_login))
)

🔹 Esto espera a que el botón sea interactuable antes de seleccionarlo.


3. Hay un iframe que lo bloquea

Si el botón está dentro de un iframe, necesitas cambiar el foco:

self.driver.switch_to.frame("id_del_iframe")
elemento = self.driver.find_element(By.XPATH, xpath_boton_login)
self.driver.switch_to.default_content()  # Volver al contexto principal si es necesario

4. El botón está oculto por otro elemento

Si el botón está en el DOM pero no visible, prueba hacer scroll hasta él:

from selenium.webdriver.common.action_chains import ActionChains

elemento = self.driver.find_element(By.XPATH, xpath_boton_login)
self.driver.execute_script("arguments[0].scrollIntoView();", elemento)

🔹 Esto lo lleva a la vista antes de intentar interactuar con él.


5. Hay múltiples elementos con el mismo XPath

Si xpath_boton_login selecciona varios elementos, find_element podría estar encontrando el incorrecto. Prueba find_elements:

elementos = self.driver.find_elements(By.XPATH, xpath_boton_login)
if elementos:
    elemento = elementos[0]  # Seleccionar el primero

presence_of_element_located

Para hacer que el programa espere hasta que el elemento esté presente en el DOM antes de continuar, usa WebDriverWait con presence_of_element_located.

Código para esperar hasta que el elemento esté presente:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Esperar hasta que el elemento esté presente en el DOM (máximo 10 segundos)
elemento = WebDriverWait(self.driver, 10).until(
    EC.presence_of_element_located((By.XPATH, xpath_boton_login))
)

🔹 Explicación:

  1. WebDriverWait(self.driver, 10): Espera hasta 10 segundos antes de lanzar una excepción.
  2. until(EC.presence_of_element_located((By.XPATH, xpath_boton_login))):
    • Verifica que el elemento esté en el DOM, pero no necesariamente visible o interactuable.

Si también necesitas que el botón sea clickeable antes de continuar, usa element_to_be_clickable en lugar de presence_of_element_located.


Código para esperar hasta que sea clickeable:

elemento = WebDriverWait(self.driver, 10).until(
    EC.element_to_be_clickable((By.XPATH, xpath_boton_login))
)

Este código espera que el botón esté en el DOM y listo para ser presionado.

Si el tiempo de espera se agota sin encontrar el elemento, lanzará un TimeoutException.

como obtengo el innerText de un elemento en selenium con python

Para obtener el texto interno (innerText) de un elemento utilizando Selenium con Python, puedes utilizar el método text del objeto WebElement. Aquí tienes un ejemplo de cómo hacerlo:

from selenium import webdriver from selenium.webdriver.common.by import By # Inicializar el navegador driver = webdriver.Chrome() # Puedes cambiarlo al navegador que estés utilizando # Abrir una página web driver.get('https://www.example.com') # Encontrar el elemento del que deseas obtener el texto (puedes usar cualquier selector que desees) elemento = driver.find_element(By.ID, 'elemento_id') # Obtener el texto interno del elemento texto = elemento.text # Imprimir el texto obtenido print("Texto interno del elemento:", texto) # Cerrar el navegador driver.quit()

ir a un elemento determinado en selenium con python

Para ir a un elemento específico en una página web utilizando Selenium con Python, puedes usar el método scrollIntoView() de JavaScript para desplazarte hacia ese elemento. A continuación, te muestro cómo hacerlo:

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys # Inicializar el navegador driver = webdriver.Chrome() # Puedes cambiarlo al navegador que estés utilizando # Abrir una página web driver.get('https://www.example.com') # Encontrar el elemento al que deseas desplazarte (puedes usar cualquier selector que desees) elemento = driver.find_element(By.ID, 'elemento_id') # Usar JavaScript para desplazarte al elemento driver.execute_script('arguments[0].scrollIntoView();', elemento) # Puedes interactuar con el elemento después de desplazarte a él, por ejemplo, hacer clic en él elemento.click() # Cerrar el navegador driver.quit()

instancia de webdriver.Chrome() en selenium

Al crear una instancia de webdriver.Chrome() en Selenium, puedes pasar varias opciones de configuración para personalizar el comportamiento del navegador. Estas opciones te permiten controlar aspectos como la ventana del navegador, el comportamiento de navegación, la privacidad y más. A continuación, te muestro algunas de las opciones comunes que puedes utilizar al crear un objeto webdriver.Chrome():


from selenium import webdriver

# Crear opciones de Chrome
chrome_options = webdriver.ChromeOptions()

# Ejemplos de opciones comunes:

# 1. Modo incógnito
chrome_options.add_argument('--incognito')

# 2. Deshabilitar las notificaciones
chrome_options.add_argument('--disable-notifications')

# 3. Deshabilitar las imágenes
chrome_options.add_argument('--blink-settings=imagesEnabled=false')

# 4. Iniciar maximizado
chrome_options.add_argument('--start-maximized')

# 5. Cambiar la ubicación de descargas
chrome_options.add_argument('--download.default_directory=/ruta/a/carpeta')

# 6. Ejecutar en segundo plano (headless)
chrome_options.add_argument('--headless')

# 7. Cambiar el User-Agent
chrome_options.add_argument('--user-agent=MiUserAgentPersonalizado')

# 8. Cambiar el idioma
chrome_options.add_argument('--lang=es')

# Crear instancia de Chrome WebDriver con las opciones
driver = webdriver.Chrome(chrome_options=chrome_options)

# Realizar acciones con el driver

# Cerrar el navegador
driver.quit()

chromedriver

https://googlechromelabs.github.io/chrome-for-testing/#stable

http://chromedriver.storage.googleapis.com/index.html

ModuleNotFoundError: No module named 'webdriver'

ImportError: cannot import name 'webdriver' from partially initialized module ''


muchos de estos error vienen dados por realizar los siguientes tipos de importacion

import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.page_load_strategy = 'normal'
driver = webdriver.Chrome(options=options)
driver.get("http://www.google.com")
driver.quit()


 Solucion

from selenium.webdriver.chrome.service import Service

from selenium.webdriver.common.by import By

from webdriver_manager.chrome import ChromeDriverManager

from selenium import webdriver

driver = webdriver.Chrome()

driver.get("https://www.google.com")

driver.quit()


tener presente que la version de Chrome (por ejemplo) sea compatible con con WebDriver utilizado 

Selenium - espera explícita

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
if __name__ == '__main__':

driver = webdriver.Chrome()
driver.get("https://www.google.com.ar/maps")

try:
# $x("//*[@id='searchboxinput']")
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "searchboxinput")))
elem=driver.find_element(By.ID, "searchboxinput")
elem.send_keys("ddddd")

# elemento = driver.find_element(By.ID, "searchboxinput")
elemento = driver.find_element(By.XPATH, "//input[@id='searchboxinput']")
time.sleep(4)




except Exception:
print("nada")
finally:
print("fin")
driver.quit()from selenium.webdriver.support.wait import WebDriverWait


Las siguientes son las condiciones esperadas que se pueden utilizar en la espera explícita.

  1. alertIsPresent()
  2. elementSelectionStateToBe()
  3. elementToBeClickable()
  4. elementToBeSelected()
  5. frameToBeAvaliableAndSwitchToIt()
  6. invisibilityOfTheElementLocated()
  7. invisibilityOfElementWithText()
  8. presenceOfAllElementsLocatedBy()
  9. presenceOfElementLocated()
  10. textToBePresentInElement()
  11. textToBePresentInElementLocated()
  12. textToBePresentInElementValue()
  13. titleIs()
  14. titleContains()
  15. visibilityOf()
  16. visibilityOfAllElements()
  17. visibilityOfAllElementsLocatedBy()
  18. visibilityOfElementLocated()

sobre Web Scraping

---------------------------------------------------------------------------------------------------------------

pip install requests ; para hacer requerimientos a un servidor

pip install beautifulsoup4 : para parcer los HTML

pip install lxml : para parcer los HTML

pip install selenium : para hacer extracciones dinámicas

pip install Pillow : para hacer extracciones de imágenes

pip install pymongo : para hacer guardado de información en base de datos

si hay problemas usar --user al final, da permisos de administrador, sudo para linux

pip install scrapy

---------------------------------------------------------------------------------------------------------------

tipos de web-scraping

nivel 1: tipo estático, donde toda la información permanece en una página web y no hay cargas del tipo dinámico.

librerías a usar:

  1. requests: para hacer requerimientos (pip install requests)
  2. xml y BeautifulSoup para parcear los requerimientos y extraer informacion
  3. scrapy para realizar requerimientos, parcearlos y extraer información
nivel 2: tipo estático con varias paginas con el mismo dominio, puede ser horizontal(llamado crollin horizontal) que es cuando tiene varias páginas en la parte inferior y se dirige a una página del mismo dominio y crollin vertical que es cuando de va accediendo al detalle de los elementos de la misma página.

librerías a usar:

  1. scrapy para realizar requerimientos, parcearlos y extraer información

nivel 3:tipo dinámico, donde se automatiza las acciones de un navegador (mediante python por ej) 

librerías a usar:

  1. Selenium python
nivel 4: usos de apis

nivel 5: donde se expande este mundo con
  • Autenticación
  • captchas
  • iFrames 

pasos a seguir para hacer web scraping 

  1. Se define una URL semilla, la pagina principal de donde se extraen los datos
  2. Realizar los requerimientos (requests)
  3. Obtener respuesta del servidor (en formato HTML)
  4. Se extrae la información deseada del HTML
  5. Se repite el paso 2 con otras URL del mismo dominio (dentro del crollin vertical/horizontal)

para el paso 4, como se extrae la información del HTML mediante XPATH
    XPATH: es un lenguaje que nos permite construir expresiones que recorren y procesan un documento XML. un HTML es un documento del tipo XML

al momento de armar un xpath se tienen en cuenta
  • los ejes (axis) da pie donde se realizará la búsqueda (ej: mediante // se busca en TODO el documento, con  / solo en la raíz y con ./ es una búsqueda relativa al lugar en el que se está)
  • el nodo de búsqueda (step) que es el nombre del tag del elemento en el que hacemos foco.
  • se definen los predicador, para pulir mas la búsqueda, por medio del usos de los atributos del tag, los atributos tienen un nombre y un valor  

ejemplo



para seleccionar page con el titulo matemáticas , puede hacerse mediante

//page[@title='Clase']/page[@title='2005']/page[@title='Matemáticas']
apretando shift y posando el mouse sobre la palabra sugiere...
//page[2]/page[2]/page[2]/@title 

el eje(axis) es el //, el nodo(step) el page y los predicados van dentro de [ ]  habiendo claro, muchas formas de construirlos. Se pueden indexar las búsquedas.

si van a la pagina de práctica y usan el siguiente código...
-------------------------------------- inicio codigo --------------------------------------
<app>
    <welcome-message>Hi! This is xpather beta...</welcome-message>
    <abstract>
        This web app enables you to query XML/HTML documents with your
browser in real time. It can generate queries for you too! 
    </abstract>
    <description>
        <subject>
You can enter your xpath query in the top-left panel 
and it will be instantly executed against this document.
Once some results are displayed on the right, you can 
scroll to them by clicking on them. 
</subject>
<subject>
To generate an xpath query for a specific element,
please hold CTRL and hover over it.
An xpath is generated heuristically with the aim
to be unambiguous and the shortest possible.
</subject>
    </description>
<extra-notes>
<note>
None of entered documents leave your computer because all
the processing is done by your powerful browser!
(of course as long as you do not save your input)
</note>
        <note>
This application is in an early beta version so please
be forgiving. XPath 2.0 is supported but namespaces are
still being added and they may not fully work yet. 
Please send your comments to: xpather.com@gmail.com
</note>
<note>
By default XML mode is used but if a document cannot
be parsed as XML then HTML mode kicks in.
</note>
<note>
Pasting documents bigger than 500kb may cause your
browser become sluggish or unresponsive.
</note>
</extra-notes>
</app>
-------------------------------------- fin codigo --------------------------------------
y quieren extraer el texto del último note pueden hacerlo mediante //note[last()]/text() acá se observa el uso de función como last() y text()
hay otros como...
position()=<numero>
contains(<tag(ej. @id)>,<cadena string(ej. "Matem")>) #si dentro de un tag contiene un tipo de cadena de string.
not # para negar un predicado
text() # extrae el texto

mas info en https://developer.mozilla.org/es/docs/Web/XPath/Functions (algunas entradas fallan)

webs de interés sobre xml y xpath

Probar expresiones en caliente
al apretar F12 podemos inspeccionar la pagina en la que estemos, en console podemos usar... 
$x("<expresion XPATH>")


mecanismos
teniendo...
import requests
from lxml import html

encabezados = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
}

url = "https://www.wikipedia.org/"

respuesta = requests.get(url, headers=encabezados)
requests = respuesta.text #solo lo convierte a texto plano
parser = html.fromstring(requests) #convierte el requests en un parceador, para extraer datos.
dato = parser.get_element_by_id("Matemática") # obtener elemento con id = "Matemática", entrega objeto de tipo elemento porque es una clase
dato_texto = dato.text_content() #para extrar el dato "Matemática" y poder imprimirlo, por ej.


# extraccion de datos usando beautifulSoup
import requests
from bs4 import BeautifulSoup

encabezados = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
}
# primer paso, definimos URL semilla
url = 'https://stackoverflow.com/questions'
respuesta = requests.get(url, headers=encabezados)
soup = BeautifulSoup(respuesta.text)
contenedor_de_preguntas = soup.find(id='questions')
lista_de_preguntas = contenedor_de_preguntas.find_all('div', class_='question-summary')
for pregunta in lista_de_preguntas:
titulo_pregunta = pregunta.find('h3').text
descripcion_pregunta = pregunta.find(class_='excerpt').text
descripcion_pregunta = descripcion_pregunta.replace('\n', '').replace('\r', '').strip()
soup.find() #busca según determinado parámetro
contenedor_de_preguntas.find_all() #busca todos los elementos que cumplan la función, entrega una lista.
se usa class_ porque class es una palabra reservada de python.
descripcion_pregunta.replace('\n', '').replace('\r', '').strip() #mediante estos códigos se limpia el resultado

INDICE