La clase By en Python
flowchart LR
By[from selenium.webdriver.common.by import By] --> ID[By.ID]
By --> N[By.NAME]
By --> CN[By.CLASS_NAME]
By --> Tg[By.TAG_NAME]
By --> CSS[By.CSS_SELECTOR]
By --> XP[By.XPATH]
By --> LT[By.LINK_TEXT]
By --> PLT[By.PARTIAL_LINK_TEXT]
Driver["driver / element"] --> FE["find_element By, valor"]
Driver --> FES[find_elements lista]
FE --> Excep[NoSuchElementException si falla]
FES --> Lst[Lista vacía si no hay match]
Driver --> Rel[Relative locators]
Rel --> Near["locate_with By.TAG_NAME, body .above above"]
En Selenium con Python, todos los localizadores se expresan usando la clase By del módulo selenium.webdriver.common.by. Esta clase define las constantes de estrategia de localización disponibles.
from selenium.webdriver.common.by import By
# Estrategias disponibles
By.ID # Busca por atributo id
By.NAME # Busca por atributo name
By.CLASS_NAME # Busca por clase CSS (una sola clase)
By.TAG_NAME # Busca por etiqueta HTML
By.CSS_SELECTOR # Busca por selector CSS completo
By.XPATH # Busca por expresión XPath
By.LINK_TEXT # Busca por texto exacto de enlace
By.PARTIAL_LINK_TEXT # Busca por texto parcial de enlace
find_element vs find_elements
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com")
# find_element: devuelve UN WebElement
# Lanza NoSuchElementException si no existe
elemento = driver.find_element(By.ID, "mi-elemento")
# find_elements: devuelve una LISTA de WebElements
# Devuelve lista vacía si no hay coincidencias (no lanza excepción)
elementos = driver.find_elements(By.CLASS_NAME, "producto")
print(f"Productos encontrados: {len(elementos)}")
# Comprobar si un elemento existe
existe = len(driver.find_elements(By.ID, "banner-opcional")) > 0
print(f"¿Existe el banner? {existe}")
Localización por ID, Name y Class
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com/registro")
# Por ID (el más rápido y preciso)
campo_email = driver.find_element(By.ID, "email")
campo_email.send_keys("usuario@ejemplo.com")
# Por NAME
campo_nombre = driver.find_element(By.NAME, "fullname")
campo_nombre.send_keys("Ana García")
# Por CLASS_NAME (solo una clase, sin espacios)
boton_enviar = driver.find_element(By.CLASS_NAME, "btn-submit")
boton_enviar.click()
# Por TAG_NAME
todos_los_parrafos = driver.find_elements(By.TAG_NAME, "p")
for p in todos_los_parrafos:
print(p.text)
Selectores CSS
Los selectores CSS son potentes y versátiles. Permiten combinar múltiples atributos y relaciones jerárquicas.
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com")
# Por ID (equivalente a By.ID)
driver.find_element(By.CSS_SELECTOR, "#email")
# Por clase
driver.find_element(By.CSS_SELECTOR, ".btn-primary")
# Por etiqueta
driver.find_element(By.CSS_SELECTOR, "button")
# Combinación etiqueta + clase
driver.find_element(By.CSS_SELECTOR, "button.btn-primary")
# Por atributo
driver.find_element(By.CSS_SELECTOR, "input[type='email']")
driver.find_element(By.CSS_SELECTOR, "[data-testid='login-button']")
# Atributo que contiene un valor
driver.find_element(By.CSS_SELECTOR, "a[href*='login']")
# Atributo que empieza por un valor
driver.find_element(By.CSS_SELECTOR, "input[name^='user']")
# Elemento hijo directo
driver.find_element(By.CSS_SELECTOR, "form > input[type='submit']")
# Elemento descendiente (cualquier nivel)
driver.find_element(By.CSS_SELECTOR, "nav a.active")
# Pseudo-clase
driver.find_element(By.CSS_SELECTOR, "li:first-child")
driver.find_element(By.CSS_SELECTOR, "li:nth-child(2)")
driver.find_element(By.CSS_SELECTOR, "li:last-child")
# data-testid (práctica recomendada para pruebas)
driver.find_element(By.CSS_SELECTOR, "[data-testid='submit-form']")
XPath
XPath permite localizar elementos usando expresiones de ruta. Es más potente que CSS pero también más verboso.
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com")
# Ruta absoluta (frágil, no recomendada)
driver.find_element(By.XPATH, "/html/body/form/input")
# Ruta relativa con búsqueda en todo el documento
driver.find_element(By.XPATH, "//input[@id='email']")
# Por atributo
driver.find_element(By.XPATH, "//input[@type='password']")
# Por texto exacto
driver.find_element(By.XPATH, "//button[text()='Enviar']")
# Por texto parcial con contains()
driver.find_element(By.XPATH, "//button[contains(text(), 'Enviar')]")
# Combinando atributos
driver.find_element(By.XPATH, "//input[@type='email' and @required]")
# Elemento padre
driver.find_element(By.XPATH, "//input[@id='email']/..")
# Siguiente hermano (following-sibling)
driver.find_element(By.XPATH, "//label[@for='email']/following-sibling::input")
# Por posición
driver.find_element(By.XPATH, "//ul/li[1]") # Primer elemento
driver.find_element(By.XPATH, "//ul/li[last()]") # Último elemento
# normalize-space para textos con espacios
driver.find_element(By.XPATH, "//span[normalize-space(text())='Precio total']")
Localizadores por texto de enlace
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com")
# Texto exacto del enlace
driver.find_element(By.LINK_TEXT, "Iniciar sesión").click()
# Texto parcial del enlace
driver.find_element(By.PARTIAL_LINK_TEXT, "sesión").click()
Localizadores relativos
Desde Selenium 4, los localizadores relativos permiten encontrar elementos basándose en su posición visual relativa a otros elementos conocidos.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com/formulario")
# El campo de contraseña está DEBAJO del campo de email
campo_password = driver.find_element(
locate_with(By.TAG_NAME, "input").below(
driver.find_element(By.ID, "email")
)
)
# El botón está CERCA del formulario
boton = driver.find_element(
locate_with(By.TAG_NAME, "button").near(
driver.find_element(By.ID, "formulario-login")
)
)
# El label está A LA IZQUIERDA del campo
label_email = driver.find_element(
locate_with(By.TAG_NAME, "label").to_left_of(
driver.find_element(By.ID, "email")
)
)
# Encima de (above)
elemento_superior = driver.find_element(
locate_with(By.CLASS_NAME, "header").above(
driver.find_element(By.ID, "main-content")
)
)
Buenas prácticas para localizadores robustos
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com")
# PREFERIDO: data-testid (no cambia con refactorizaciones de UI)
driver.find_element(By.CSS_SELECTOR, "[data-testid='submit-button']")
# BUENO: ID único y estable
driver.find_element(By.ID, "user-email-input")
# ACEPTABLE: combinación de atributos específica
driver.find_element(By.CSS_SELECTOR, "input[name='email'][type='email']")
# EVITAR: clases de estilos (cambian con rediseños)
# driver.find_element(By.CLASS_NAME, "mt-4 text-blue-500") # Clase Tailwind frágil
# EVITAR: XPath absoluto (rompe con cualquier cambio estructural)
# driver.find_element(By.XPATH, "/html/body/div[3]/form/button")
Ejemplo práctico: extraer datos de una tabla
from selenium import webdriver
from selenium.webdriver.common.by import By
def extraer_tabla(driver, selector_tabla):
"""Extrae los datos de una tabla HTML como lista de diccionarios."""
tabla = driver.find_element(By.CSS_SELECTOR, selector_tabla)
# Obtener cabeceras
cabeceras = [
th.text for th in tabla.find_elements(By.TAG_NAME, "th")
]
# Obtener filas
filas = tabla.find_elements(By.CSS_SELECTOR, "tbody tr")
datos = []
for fila in filas:
celdas = fila.find_elements(By.TAG_NAME, "td")
fila_datos = {
cabeceras[i]: celdas[i].text
for i in range(len(celdas))
}
datos.append(fila_datos)
return datos
with webdriver.Chrome() as driver:
driver.get("https://www.ejemplo.com/productos")
productos = extraer_tabla(driver, "table#lista-productos")
for producto in productos:
print(producto)
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Selenium
Documentación oficial de Selenium
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Selenium es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Selenium
Explora más contenido relacionado con Selenium y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Usar By.ID, By.NAME, By.CLASS_NAME y By.TAG_NAME para localizar elementos básicos. Construir selectores CSS avanzados con By.CSS_SELECTOR para localización precisa. Crear expresiones XPath con By.XPATH para localizar elementos complejos. Usar By.LINK_TEXT y By.PARTIAL_LINK_TEXT para localizar enlaces. Aplicar localizadores relativos (near, above, below, to_left_of, to_right_of). Localizar múltiples elementos con find_elements y manejar listas de WebElements.