Localizadores de elementos con Python

Intermedio
Selenium
Selenium
Actualizado: 05/05/2026

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 - Autor del tutorial

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.