Selenium WebDriver es una biblioteca que controla navegadores reales desde código, implementando la especificación WebDriver del W3C. Se instala con el gestor de paquetes de tu lenguaje —pip install selenium en Python, una dependencia Maven en Java, dotnet add package Selenium.WebDriver en C#— y desde la versión 4.6 ya no hace falta descargar drivers a mano: lo resuelve Selenium Manager. Un script se compone siempre de ocho bloques, de abrir la sesión a cerrarla. Selenium automatiza el navegador y nada más: el ejecutor de pruebas y las aserciones los aporta el framework de tu lenguaje.
Ver índice de contenidos
- 01Qué es Selenium, en concreto
- 02Qué necesitás antes de instalar
- 03Cómo se instala en cada lenguaje
- 04Tu primer script, bloque por bloque
- 05Cómo encontrar elementos sin que se rompa
- 06Esperas: el error que rompe más suites
- 07Sin ventana y en integración continua
- 08Cómo organizarlo cuando crece
- 09Errores frecuentes al empezar
- 10Preguntas frecuentes
- 11Fuentes
Qué es Selenium, en concreto
Cuando alguien dice «Selenium» puede estar hablando de tres cosas distintas, y conviene separarlas antes de instalar nada:
- Selenium WebDriver: la biblioteca que controla el navegador desde tu código. Es lo que se usa en el 99 % de los casos y de lo que trata esta guía.
- Selenium IDE: una extensión de navegador que graba y reproduce interacciones, sin escribir código. Sirve para explorar, no para sostener una suite.
- Selenium Grid: la pieza que distribuye la ejecución en varias máquinas para correr en paralelo.
La definición oficial de WebDriver es «una API y un protocolo que definen una interfaz neutral respecto del lenguaje para controlar el comportamiento de los navegadores». La parte importante de esa frase es protocolo: WebDriver es una especificación del W3C, el mismo organismo que estandariza HTML y CSS. Los navegadores traen soporte porque el estándar existe, no porque Selenium se los pida, y eso es lo que permite que el mismo conjunto de órdenes funcione desde cinco lenguajes distintos.
Selenium automatiza el navegador y se detiene ahí. No trae ejecutor de pruebas, aserciones, informes ni ejecución en paralelo: eso lo aporta el framework de tu lenguaje. Si esperabas que todo viniera en la misma caja, la comparación entre las tres herramientas está en Selenium, Cypress o Playwright.
Qué necesitás antes de instalar
Menos de lo que suele creerse. La lista completa son tres cosas:
- Un navegador instaladoChrome, Firefox o Edge alcanzan. Safari solo se puede automatizar en macOS, con
safaridriver. - Un lenguaje y su gestor de paquetesPython con pip, Java con Maven o Gradle, C# con NuGet, Ruby con gem, o Node.js con npm.
- Nada másEn particular, ningún driver descargado a mano: de eso se encarga Selenium Manager desde la versión 4.6.
Sobre versiones mínimas del lenguaje, los propios repositorios de paquetes son la fuente a mirar porque cambian con cada release. Al 27 de julio de 2026, el paquete selenium de PyPI declara Python 3.10 o superior y selenium-webdriver en npm declara Node.js 20 o superior.
Cómo se instala en cada lenguaje
Estos son los comandos que figuran en la documentación oficial. La versión estable al momento de escribir esta guía es la 4.46.0.
# Python
pip install selenium
# JavaScript / Node.js
npm install selenium-webdriver
# C# / .NET
dotnet add package Selenium.WebDriver
# Ruby
gem install selenium-webdriver
En Java se declara como dependencia del proyecto. Con Maven, dentro de pom.xml:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.46.0</version>
</dependency>
Y con Gradle, en build.gradle: testImplementation "org.seleniumhq.selenium:selenium-java:4.46.0". Si trabajás en Kotlin, se usan las bindings de Java sin nada extra.
En equipos, conviene declarar la versión exacta (selenium==4.46.0 en requirements.txt, por ejemplo) en lugar de instalar siempre la última. Así una actualización silenciosa no rompe la suite de otra persona un lunes a la mañana.
Tu primer script, bloque por bloque
La documentación oficial describe cualquier script de Selenium como una combinación de ocho operaciones. Aprenderlas de entrada ahorra mucho tiempo, porque después toda prueba que leas —por larga que sea— se descompone en estas mismas piezas.
Veámoslos funcionando sobre una página real: el índice de guías de este portal, que filtra resultados en el cliente mientras escribís. El script abre la página, busca wardriving y comprueba que quede una sola guía.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 1. Iniciar la sesión — Selenium Manager resuelve el driver solo
driver = webdriver.Chrome()
try:
# 2. Actuar sobre el navegador
driver.get("https://underc0de.org/guias/")
# 3. Pedir información al navegador
print("Título:", driver.title)
# 5. Encontrar un elemento
buscador = driver.find_element(By.CSS_SELECTOR, "[data-guide-search]")
# 6. Actuar sobre el elemento
buscador.send_keys("wardriving")
# 4. Estrategia de espera + 7. información del elemento
contador = WebDriverWait(driver, 10).until(
EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, "[data-result-count]"), "1 guía encontrada"
)
)
assert contador, "El buscador no filtró a una sola guía"
finally:
# 8. Cerrar la sesión, pase lo que pase
driver.quit()
Dos detalles que no son decorativos. El try/finally garantiza que driver.quit() se ejecute incluso si la aserción falla: sin eso, cada corrida fallida deja un proceso de navegador vivo en segundo plano, y después de una tarde de trabajo tenés la memoria llena. Y quit() no es lo mismo que close(): close() cierra la ventana actual, quit() termina el proceso del driver y con él todas las ventanas.
Cómo encontrar elementos sin que se rompa
Selenium busca elementos con la clase By, que ofrece ocho estrategias. Estas son las que valen la pena en la práctica:
| Estrategia | Ejemplo | Cuándo usarla |
|---|---|---|
By.ID | By.ID, "login" | Primera opción si el elemento tiene un id estable y único. |
By.CSS_SELECTOR | By.CSS_SELECTOR, "[data-test=enviar]" | La más versátil. Ideal con atributos puestos a propósito para pruebas. |
By.NAME | By.NAME, "email" | Campos de formulario, que casi siempre tienen name. |
By.LINK_TEXT | By.LINK_TEXT, "Ver guía" | Enlaces, cuando el texto visible es estable. |
By.XPATH | By.XPATH, "//button[text()='Enviar']" | Último recurso: cuando hay que subir en el árbol o filtrar por texto. |
La regla que ahorra más mantenimiento: pedile al equipo de desarrollo un atributo dedicado a las pruebas, del tipo data-test="boton-enviar". Un selector apoyado en clases de CSS se rompe la primera vez que alguien retoca el diseño, y un XPath copiado del navegador —esos que se ven como /html/body/div[3]/div/div[2]/button— se rompe cuando cambia cualquier cosa en el camino. El atributo dedicado, en cambio, existe solo para esto y nadie lo toca por accidente.
Ojo con la diferencia entre find_element y find_elements: el primero devuelve el primer elemento coincidente y lanza una excepción si no hay ninguno; el segundo devuelve una lista, posiblemente vacía. Para comprobar que algo no está, usá el segundo y verificá que la lista esté vacía.
Esperas: el error que rompe más suites
Este es el punto donde se cae casi todo el mundo, así que vale la pena leerlo despacio. Selenium no espera solo. Cuando pedís un elemento que la página todavía no terminó de renderizar, no hay reintento: falla. Y como el momento exacto depende de la red y de la máquina, la prueba anda en tu computadora y falla en el servidor de integración continua.
Hay tres formas de manejarlo, y solo dos son buenas.
Espera implícita
Se configura una vez y aplica a todas las búsquedas de elementos: el driver reintenta durante ese tiempo antes de dar error. Su valor por defecto es 0, es decir, sin espera.
# Aplica a todo find_element de esta sesión
driver.implicitly_wait(10)
Es cómoda pero tosca: espera a que el elemento exista en el DOM, no a que sea visible o clicable, y no sirve para esperar que un texto cambie.
Espera explícita
Espera una condición concreta en un punto concreto del código. Es la que conviene usar casi siempre.
# Esperar hasta 10 s a que el botón sea clicable
boton = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "[data-test=enviar]"))
)
boton.click()
Las condiciones más usadas de expected_conditions son visibility_of_element_located, element_to_be_clickable, text_to_be_present_in_element y invisibility_of_element_located —esta última, perfecta para esperar que desaparezca un indicador de carga.
La documentación oficial es explícita: «no mezcles esperas implícitas y explícitas, hacerlo puede causar tiempos de espera impredecibles». El ejemplo que da es elocuente: una implícita de 10 segundos junto a una explícita de 15 puede terminar esperando 20. Elegí una estrategia —idealmente, explícitas— y dejá la implícita en 0.
Y la que no hay que usar
time.sleep(5). Una pausa fija siempre está mal calibrada: es demasiado larga cuando la app responde rápido, y demasiado corta el día que la red va lenta. Multiplicada por doscientas pruebas, convierte una suite de tres minutos en una de media hora que igual falla.
Sin ventana y en integración continua
En un servidor de CI no hay pantalla, así que el navegador tiene que correr en modo headless —sin interfaz gráfica—. Se configura con las opciones del navegador:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
opciones = Options()
opciones.add_argument("--headless=new")
opciones.add_argument("--window-size=1440,900")
driver = webdriver.Chrome(options=opciones)
Fijar el tamaño de ventana no es un detalle: sin pantalla, el navegador adopta un tamaño por defecto que puede dejar elementos fuera de la vista y hacer fallar clics que localmente funcionan. Es una de las causas más frecuentes de «anda en mi máquina pero no en CI».
Para que las pruebas se ejecuten como una suite de verdad —con informes, ejecución en paralelo y capturas al fallar— hay que combinarlas con el framework de tu lenguaje. En Python, con pytest, el patrón habitual es una fixture que abre y cierra el navegador por cada prueba:
import pytest
from selenium import webdriver
@pytest.fixture
def driver():
navegador = webdriver.Chrome()
yield navegador # acá corre la prueba
navegador.quit() # y esto se ejecuta siempre al terminar
def test_titulo_del_indice(driver):
driver.get("https://underc0de.org/guias/")
assert "Underc0de" in driver.title
Con esto ya podés correr pytest y tener el andamiaje que Selenium no incluye: descubrimiento de pruebas, aserciones legibles, informes y ejecución selectiva.
Cómo organizarlo cuando crece
Con diez pruebas cualquier estructura funciona. A partir de cincuenta, el problema deja de ser escribirlas y pasa a ser mantenerlas: si el botón de login cambió de selector y ese selector está copiado en treinta archivos, tenés treinta ediciones por delante.
La respuesta clásica se llama Page Object Model (modelo de objetos de página): cada pantalla de la aplicación se representa como una clase que concentra sus selectores y expone acciones con nombres del dominio. Las pruebas dejan de hablar de CSS y empiezan a hablar de negocio.
class IndiceDeGuias:
URL = "https://underc0de.org/guias/"
BUSCADOR = (By.CSS_SELECTOR, "[data-guide-search]")
CONTADOR = (By.CSS_SELECTOR, "[data-result-count]")
def __init__(self, driver):
self.driver = driver
def abrir(self):
self.driver.get(self.URL)
return self
def buscar(self, texto):
self.driver.find_element(*self.BUSCADOR).send_keys(texto)
return self
# La prueba queda legible y sin un solo selector a la vista
def test_busqueda_filtra(driver):
IndiceDeGuias(driver).abrir().buscar("wardriving")
El selector vive en un solo lugar. Cuando cambia, se edita una línea. Es el patrón más difundido en suites de Selenium y vale la pena adoptarlo antes de que la suite crezca, no después.
Errores frecuentes al empezar
- Seguir un tutorial anterior a 2022. Si te dice que descargues
chromedriver, que useswebdriver-managero que llames afind_element_by_id(), está desactualizado: esos métodos se eliminaron en Selenium 4.3 y el driver lo resuelve Selenium Manager desde la 4.6. - Olvidar
quit(). Cada corrida deja un proceso vivo. Usátry/finallyo una fixture del framework de pruebas. - Resolver la intermitencia con
sleep. Esconde el problema y multiplica el tiempo de ejecución. - Copiar XPath desde las herramientas del navegador. Son rutas absolutas que se rompen con cualquier cambio de estructura.
- Guardar elementos en variables y reutilizarlos después de que la página cambie. Si el elemento se vuelve a renderizar, la referencia queda huérfana y aparece el clásico
StaleElementReferenceException. Volvé a buscarlo. - Automatizar por la interfaz lo que se verifica mejor en la API. Una regla de negocio se comprueba con una petición HTTP en milisegundos; moverla a un navegador la vuelve lenta y frágil.
Preguntas frecuentes
¿Necesito descargar chromedriver a mano?
No. Desde Selenium 4.6 el paquete incluye Selenium Manager, que detecta el navegador instalado, descarga el driver compatible y lo guarda en caché sin que configures nada. Actúa como respaldo: si en tu código ya indicás la ruta de un driver, esa tiene prioridad. Si venís de tutoriales viejos, podés borrar de tu proyecto webdriver-manager y las líneas que definían webdriver.chrome.driver.
¿Qué lenguaje conviene usar con Selenium?
El que ya escriba tu equipo. Selenium tiene bindings oficiales para Java, Python, C#, Ruby y JavaScript, y los ocho bloques de un script son idénticos en los cinco: cambia la sintaxis, no los conceptos. Java es el más extendido en suites corporativas grandes, Python el más cómodo para arrancar, y C# el habitual en equipos .NET. Kotlin usa las bindings de Java.
¿Por qué mi prueba falla de manera intermitente?
Casi siempre es un problema de esperas. Selenium no espera solo: si buscás un elemento que todavía no existe porque la página lo carga con JavaScript, falla. La solución no es agregar pausas fijas con sleep, que hacen la suite lenta y siguen fallando cuando la red va más despacio, sino usar esperas explícitas con WebDriverWait sobre la condición concreta que necesitás. Y no mezclar esperas implícitas con explícitas: la documentación oficial advierte que hacerlo produce tiempos de espera impredecibles.
¿Selenium sirve para hacer scraping o bots?
Técnicamente sí, y de hecho mucha gente lo conoce por ahí. Pero antes de automatizar un sitio que no es tuyo hay que revisar sus términos de servicio y su archivo robots.txt, y no generar carga que afecte el servicio. Automatizar tu propia aplicación o un entorno de pruebas autorizado no tiene ese problema. Para extraer datos, además, una API o una petición HTTP directa suele ser más rápida y estable que mover un navegador completo.
¿Qué es Selenium Grid y cuándo lo necesito?
Es el componente que distribuye la ejecución en varias máquinas o contenedores, para correr pruebas en paralelo y en distintas combinaciones de navegador y sistema operativo. No lo necesitás para empezar: tiene sentido cuando la suite creció tanto que ejecutarla en serie en una sola máquina tarda demasiado, o cuando tenés que certificar navegadores que no están en tu equipo.
¿Selenium incluye aserciones e informes?
No. Selenium WebDriver automatiza el navegador y nada más; a diferencia de Cypress y Playwright, no trae ejecutor de pruebas, aserciones ni informes. Eso se lo agregás vos con el framework de tu lenguaje: pytest o unittest en Python, JUnit o TestNG en Java, NUnit o xUnit en C#, RSpec en Ruby, Mocha o Jest en JavaScript.
Fuentes
Documentación oficial y registros de paquetes consultados para esta guía. Fecha de consulta: 27 de julio de 2026.
- Selenium. Install a Selenium library. Comandos de instalación para los cinco lenguajes y coordenadas de Maven y Gradle.
- Selenium. Write your first Selenium script. Los ocho bloques de un script y el comportamiento de
driver.quit(). - Selenium. Waiting strategies. Esperas implícitas, explícitas y fluidas, valor por defecto y advertencia sobre mezclarlas.
- Selenium. Selenium Manager (Beta). Gestión automática de drivers desde la versión 4.6.
- Selenium. Locator strategies. Las estrategias disponibles en la clase
By. - SeleniumHQ, en GitHub. [py]: remove deprecated
find_element_by_methods. Eliminación de los métodos de localización antiguos en Python. - PyPI. selenium. Versión 4.46.0 y Python ≥ 3.10. El requisito de Node.js ≥ 20 figura en el campo
enginesdel paqueteselenium-webdriverdel registro de npm. - Underc0de, foro. «Selenium: aprende a crear tus propios bots con Python», por Mortal_Poison, 5 de octubre de 2017. Aporte de la comunidad que introdujo el tema en el foro; su código usa la API anterior a Selenium 4.