Raspado web con Selenium: Una guía práctica de Python
Lead Scraping Automation Engineer
Resumen:
- Selenium controla un Chrome real a través del protocolo WebDriver, por lo que ve el DOM que una página construye con JavaScript — el contenido que una solicitud HTTP simple nunca recibe.
- Una ejecución en vivo a continuación lee las diez citas de una página de demostración que envía un contenedor vacío y lo llena del lado del cliente; la misma página devuelve cero filas a una solicitud
requests.getbásica. - Selenium moderno resuelve su propio controlador: Selenium Manager empareja ChromeDriver con tu Chrome instalado, por lo que
webdriver.Chrome(options=...)funciona sin necesidad de una descarga manual. - El verdadero costo de Selenium es operativo: cada trabajador es un navegador completo saliendo desde tu propia IP, lo que es difícil de escalar y sencillo para que los sistemas anti-bot apliquen límites de tasa.
- El pivote de límites honestos envía la misma URL a la API de Scraping Universal de Scrapeless, que renderiza la página del lado del servidor y devuelve HTML terminado, sin navegador para que tú ejecutes o escales.
- Obtén una clave de API de Scrapeless en el plan gratuito y ejecuta ambas mitades tú mismo.
Lo que Selenium hace para scraping
Selenium automatiza un navegador real. Tu código en Python habla el protocolo WebDriver a ChromeDriver, ChromeDriver controla Chrome, y Chrome hace lo que hace un navegador: solicita la página, ejecuta los scripts y construye el DOM. Esa última parte es la razón por la que los scrapers lo utilizan. Una página que ensambla su contenido en el cliente — una cuadrícula de productos renderizada por un marco, un feed que llega a través de una solicitud en segundo plano — está vacía en el HTML sin procesar y completa solo después de que se ejecutan los scripts. Selenium espera por esa ejecución y te entrega la página terminada.
La desventaja es el peso. Selenium ejecuta un Chrome real por sesión, lo que consume memoria y tiempo de inicio, y la solicitud sale desde la IP de tu máquina. Para un puñado de páginas, está bien. Esta guía construye primero el scraper funcional de Selenium y luego muestra el punto donde ejecutar tus propios navegadores deja de ser rentable y qué hacer al respecto. Cada camino de código aquí se ejecutó contra la página en vivo.
Instalación
Instala los bindings de Selenium para Python:
bash
pip install selenium
No debes instalar ChromeDriver manualmente. A partir de la versión 4.6, Selenium incluye las herramientas de Selenium WebDriver con Selenium Manager, que detecta tu Chrome y resuelve el controlador coincidente en el primer uso. Necesitas tener instalado un Google Chrome reciente; los bindings manejan el resto.
Configuración
Para el pivote más adelante en esta guía, coloca tu clave de API de Scrapeless en el entorno para que nunca aparezca en el código fuente:
bash
export SCRAPELESS_API_KEY="tu_clave_de_api_scrapeless"
Implementación básica: renderizar una página de JavaScript
Apunta Selenium a una página que construye sus filas en el cliente, y los elementos están ahí una vez que la navegación regresa. La demostración a continuación envía un contenedor vacío y lo pobla con JavaScript; el HTML sin procesar no lleva nodos .quote, mientras que el DOM renderizado por el navegador lleva diez porque Chrome ejecutó primero los scripts, siguiendo el modelo de análisis y scripting HTML.
python
import tempfile
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
opts = Options()
opts.add_argument("--headless=new")
opts.add_argument("--no-sandbox")
opts.add_argument("--disable-dev-shm-usage")
opts.add_argument(f"--user-data-dir={tempfile.mkdtemp()}")
driver = webdriver.Chrome(options=opts) # Selenium Manager resuelve el controlador
try:
driver.get("https://quotes.toscrape.com/js/")
quotes = driver.find_elements(By.CSS_SELECTOR, ".quote")
print("bloques de citas en la página de JS:", len(quotes))
print("primer autor:", quotes[0].find_element(By.CSS_SELECTOR, ".author").text)
finally:
driver.quit()
La ejecución imprime el conteo y el primer registro:
text
bloques de citas en la página de JS: 10
primer autor: Albert Einstein
La bandera --headless=new ejecuta Chrome sin una ventana visible, que es lo que quieres en un servidor. --no-sandbox y --disable-dev-shm-usage mantienen Chrome estable dentro de contenedores y entornos restringidos, y el --user-data-dir desechable da a cada ejecución su propio perfil para que las sesiones paralelas no choquen.
Patrones avanzados: esperando y seleccionando
driver.get regresa cuando el documento se carga, pero un elemento construido por un script puede aparecer un momento después. En lugar de dormir un intervalo fijo, espera la condición específica. WebDriverWait emparejado con expected_conditions bloquea hasta que el elemento que nombras esté presente, de modo que el scraping comience en el instante en que los datos existan y no antes:
python
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".quote"))
)
Prefiera selectores estables sobre clases CSS cifradas: un id, un atributo data-* o una etiqueta semántica sobreviven a un rediseño que renombra clases de estilo. Para una página que paginas, lee el href del enlace "siguiente" y síguelo en lugar de adivinar los números de página.
Obtén tu clave API en el plan gratuito: app.scrapeless.com
El límite honesto y el pivote
Selenium renderiza JavaScript bien; lo que no hace es hacer que ejecutar navegadores sea barato o evitar que tu tráfico se distinga. Cada trabajador de Selenium es un Chrome completo, por lo que escalar a muchas páginas significa escalar navegadores y la memoria que necesitan, y cada solicitud sale de tu propia IP, que un sitio ocupado puede limitar o desafiar. Selenium no tiene respuesta incorporada a un desafío de anti-bots gestionado; renderiza la página que se le da, y una página que nunca alcanza se renderiza como nada.
La API Universal de Scraping de Scrapeless quita esa mitad operativa de tu máquina. Le envías la URL con js_render habilitado; renderiza la página del lado del servidor detrás de una gestión de anti-bots y salida residencial rotativa gestionadas, y devuelve el HTML final en su campo data. No hay navegador que lanzar, y la solicitud no proviene de tu IP. Analizas el HTML devuelto exactamente como analizarías el origen de la página de Selenium:
python
import os, re, json, requests
resp = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"], "Content-Type": "application/json"},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://quotes.toscrape.com/js/", "js_render": True}},
timeout=120,
)
resp.raise_for_status()
html = resp.json()["data"]
authors = re.findall(r'<small class="author">(.*?)</small>', html)
print("bloques de citas renderizados a través de la API Universal de Scraping:", html.count('class="quote"'))
print("autores extraídos:", len(authors))
print("primer autor:", authors[0])
La única solicitud devuelve la misma página renderizada, del lado del servidor:
text
bloques de citas renderizados a través de la API Universal de Scraping: 10
autores extraídos: 10
primer autor: Albert Einstein
La regla general: mantén Selenium mientras controles el objetivo y el volumen sea pequeño, y mueve la obtención a la API cuando el trabajo se convierte en las operaciones: muchas páginas, IPs bloqueadas o un desafío que Selenium no puede superar. El código de análisis no cambia; solo cambia la fuente del HTML.
Solución de problemas
Un error de versión del controlador casi siempre significa que Chrome se actualizó y un controlador antiguo persistió; en Selenium 4.6 y versiones más recientes, Selenium Manager resuelve el controlador actual por ti, por lo que eliminar un ChromeDriver fijado manualmente de tu PATH generalmente lo soluciona. Un resultado vacío en una página que puedes ver en un navegador normal significa que el contenido llegó después de que driver.get devolvió; añade el WebDriverWait anterior para el selector que necesitas. Un proceso que se queda atascado en una página que nunca se queda en silencio en la red significa que esperaste la condición equivocada; espera por el elemento, no por la red.
Mantén el trabajo dentro de los límites establecidos de un sitio. Lee sus términos y su protocolo de exclusión de robots, solicita solo páginas públicas y mantén la concurrencia moderada: la misma disciplina que se cubre en la guía sobre el modelo de objetos del documento que lee Selenium. Para un recorrido más amplio de descubrimiento y extracción, el tutorial sobre cómo construir un scraper web desde cero se complementa bien con este.
Conclusión
Selenium gana su lugar cuando una página necesita un navegador real para existir: controla Chrome a través del protocolo WebDriver, ejecuta los scripts y te entrega el DOM renderizado: diez citas de una página que no envía ninguna en su marcado. Donde deja de ser rentable son las operaciones en torno a ese navegador: la memoria de sesiones escaladas, la exposición de tu propia IP y los desafíos que no puede superar. En ese punto, la misma URL a través de la API Universal de Scraping de Scrapeless devuelve el HTML renderizado sin ningún navegador que ejecutar, y tu análisis se mantiene igual. Verifica el volumen de solicitudes que necesitas contra la página de precios antes de escalar.
Únete a nuestra comunidad para reclamar un plan gratuito y comparar notas con otros desarrolladores que están creando scrapers: Discord · Telegram.
Preguntas Frecuentes
P: ¿Necesito descargar ChromeDriver para usar Selenium?
No. Selenium 4.6 y versiones posteriores incluyen Selenium Manager, que detecta tu Chrome instalado y resuelve el ChromeDriver correspondiente en su primer uso, por lo que webdriver.Chrome(options=...) funciona sin necesidad de descargar manualmente el driver.
P: ¿Por qué Selenium encuentra elementos que requests no puede?
Selenium ejecuta un navegador real que ejecuta el JavaScript de la página y construye el DOM, por lo que los elementos generados por scripts existen para cuando los consultas. Un cliente HTTP sin procesar recibe solo la marca inicial del servidor, que en una página renderizada por el cliente no contiene ese contenido.
P: ¿Cuándo debo cambiar de Selenium a la API de Scraping Universal?
Cambia cuando la dificultad sea operativa en lugar de renderizar — muchas páginas que recuperar, tu IP siendo limitada o un reto de anti-bot gestionado que Selenium no puede superar. La API se renderiza del lado del servidor y devuelve HTML terminado, por lo que mantienes tu procesamiento y dejas de necesitar la flota de navegadores.
P: ¿Cómo espero el contenido que se carga después de la página?
Usa WebDriverWait con expected_conditions para bloquearte hasta que un selector específico esté presente, en lugar de un time.sleep fijo. La extracción comienza en el momento en que el elemento existe, lo cual es más rápido y más confiable que una demora adivinada.
P: ¿Es legal hacer scraping con Selenium?
Hacer scraping de datos públicos es generalmente permitido, pero la responsabilidad es tuya: respeta los términos del sitio y sus directrices para robots, recoge solo páginas públicas, evita datos personales que no tienes base para procesar y mantén las tasas de solicitud moderadas.
En Scrapeless, solo accedemos a datos disponibles públicamente y cumplimos estrictamente con las leyes, regulaciones y políticas de privacidad del sitio web aplicables. El contenido de este blog es sólo para fines de demostración y no implica ninguna actividad ilegal o infractora. No ofrecemos garantías y renunciamos a toda responsabilidad por el uso de la información de este blog o enlaces de terceros. Antes de realizar cualquier actividad de scraping, consulte a su asesor legal y revise los términos de servicio del sitio web de destino u obtenga los permisos necesarios.



