
Olvida Selenium: Construyendo Agentes de IA con uso de navegador y DeepSeek (El Nuevo Estándar de 2026)
Si alguna vez has escrito un web scraper en Selenium, conoces el dolor.
Pasas horas inspeccionando HTML, buscando el selector CSS perfecto (div > span > button.id-42), y ejecutando tu script… solo para que el sitio web cambie su diseño al día siguiente y rompa todo. Lo arreglas, lo despliegas, y luego aparece una ventana emergente aleatoria que tu script no estaba programado para clicar, y todo se bloquea de nuevo.
Need Fast Hosting? I Use Hostinger Business
This site runs on the Business Hosting Plan. It handles high traffic, includes NVMe storage, and makes my pages load instantly.
Get Up to 75% Off Hostinger →⚡ 30-Day Money-Back Guarantee
He pasado los últimos 1.5 años construyendo Scripts de automatización y he hecho muchos scripts de python para Automatización de Video y Automatización de Pósters, y puedo decir con confianza: **El scraping basado en DOM está muerto.**
En 2026, ya no necesitamos cazar etiquetas div. Tenemos Modelos de Visión.
Una nueva librería llamada **browser-use** ha tomado el mundo de Python por asalto (superando las 20k+ estrellas en GitHub en meses). En lugar de escribir código frágil para encontrar botones, simplemente le dices a un LLM: *’Ve a Amazon, encuentra el teclado mecánico más barato y añádelo a mi carrito.’*
Y realmente funciona. Ve la página, entiende cómo luce un botón de «Carrito» y hace clic en él, tal como lo haría un humano.
Recientemente conecté browser-use a nuestra pila **Local DeepSeek-R1**, y los resultados fueron aterradoramente buenos. Mi agente navegó por aplicaciones React complejas, manejó ventanas emergentes y completó formularios, todo ejecutándose localmente por $0.
Aquí está la guía completa para construir tu primer agente web autónomo en 5 minutos.
La Revolución «Visual»: Por qué browser-use Acaba con Selenium
Para entender por qué esto es un cambio de paradigma, tienes que mirar cómo solíamos hacer las cosas frente a cómo las hace browser-use.
La Vieja Escuela: Automatización Ciega (Selenium/Playwright)
Las herramientas tradicionales son «Ciegas». No ven la pantalla; solo ven el código subyacente.
Cuando le dices a Selenium que haga click('login_btn'), busca en el texto HTML ese ID.
- Frágil: Si el desarrollador cambia el ID a
login_button_v2, tu script falla. - Alto Mantenimiento: Estás actualizando selectores constantemente.
- Propenso a Anti-Bots: Los sitios web saben que los humanos no miran el HTML; miran los píxeles.
La Nueva Era: Automatización Visual (browser-use)
browser-use opera con una filosofía completamente diferente. Usa Playwright para abrir el navegador, pero en lugar de pedirte selectores, toma una **Captura de Pantalla** y extrae el **Árbol de Accesibilidad**.
Alimenta con estos datos visuales a un LLM (como DeepSeek o GPT-4o) y pregunta: *’¿Dónde está el botón de ‘Login’?’*
El LLM responde: *’Está en las coordenadas (x: 200, y: 500).’*
La librería entonces simula un clic del mouse en esas coordenadas.
| Característica | Selenium / Playwright | browser-use |
| Navegación | driver.find_element(By.ID, "login") | "Inicia sesión en el sitio" |
| Resiliencia | Se rompe si el ID cambia | Auto-Reparación (Encuentra el botón visualmente) |
| Código de Configuración | 50+ líneas | 5 líneas |
| Costo | Gratis | Gratis (con DeepSeek Local) |
Esto significa que browser-use es **Auto-Reparable**. Si el botón de «Login» se mueve de la esquina superior derecha al centro de la pantalla, tu script no se rompe. La IA simplemente lo «ve» en la nueva ubicación y hace clic de todos modos.
Paso 1: La Pila Tecnológica (100% Local)
La mayoría de los tutoriales para browser-use te dirán que uses GPT-4o de OpenAI. Aunque GPT-4o es excelente en tareas de visión, cuesta dinero—alrededor de $0.01 por paso. Si tu agente se atasca en un bucle, puedes gastar $10 en unos pocos minutos.
Vamos a construir la **»Pila Gratuita»** usando el modelo local DeepSeek que configuramos la última vez.
Prerrequisitos:
- Python 3.11+ instalado en tu máquina.
- Ollama ejecutándose en segundo plano.
- RAM: Al menos 16GB (ya que estamos ejecutando un navegador Y un LLM o kaggle que estoy usando y proporcioné el código al final).
Instalando las Dependencias
Abre tu terminal. Necesitamos la librería principal, el puente LangChain (para hablar con Ollama), y Playwright (el motor del navegador).
# Instalar las librerías de Python
pip install browser-use langchain-ollama playwright
# Instalar los binarios del navegador (Chromium)
playwright install
Nota: Si estás en Linux, podrías necesitar instalar dependencias del sistema adicionales para Playwright.
Paso 2: El Código (Integración con DeepSeek)
Esta es la parte complicada donde la mayoría de la gente se atasca. browser-use está diseñado nativamente para OpenAI. Para hacerlo funcionar con Ollama, tenemos que realizar una pequeña «cirugía» usando LangChain.
Necesitamos pasar una ventana de contexto (`num_ctx`) que sea lo suficientemente grande. ¿Por qué? Porque el «Árbol de Accesibilidad» de un sitio web moderno (como Amazon o LinkedIn) es enorme. Si usas la ventana de contexto predeterminada de 4k, la IA «olvidará» la mitad de la página y no podrá encontrar los botones.
Crea un archivo llamado web_agent.py y pega este código:
import asyncio
from langchain_ollama import ChatOllama
from browser_use import Agent
from browser_use.browser.browser import Browser, BrowserConfig
# ==========================================
# CONFIGURATION
# ==========================================
# 1. Configurar el LLM Gratuito (DeepSeek vía Ollama)
# CONSEJO CRÍTICO: Aumentamos 'num_ctx' a 32000.
# DeepSeek necesita un contexto masivo para "leer" toda la estructura HTML de una página.
llm = ChatOllama(
model="deepseek-r1:8b",
num_ctx=32000,
temperature=0.0, # Queremos precisión, no creatividad
)
# 2. Configurar el Navegador
# Ejecutamos en modo 'headless=False' para que puedas ver al bot trabajar.
browser = Browser(
config=BrowserConfig(
headless=False,
disable_security=True # Ayuda a evitar algunas protecciones básicas contra bots
)
)
# ==========================================
# THE TASK
# ==========================================
# Sin selectores CSS. Solo instrucciones en lenguaje natural.
# Nota cómo le damos un objetivo de varios pasos.
task = (
"Go to 'google.com'. "
"Search for 'Python release date 2026'. "
"Click on the first non-ad result. "
"Find the exact release date in the text and print it to the console."
)
# ==========================================
# EXECUTION
# ==========================================
agent = Agent(
task=task,
llm=llm,
browser=browser,
)
async def main():
print("🚀 Agent starting... Watch the popup window!")
# Ejecutar el agente y capturar el historial
result = await agent.run()
print("\n✅ FINAL RESULT:")
print(result.final_result())
# Siempre cerrar el navegador para liberar RAM
await browser.close()
if **name** == "**main**":
asyncio.run(main())
Paso 3: Ejecutando el Agente (y Qué Observar)
Ejecuta el script en tu terminal:
python web_agent.py
)
Aquí está lo que sucederá, paso a paso:
- El Lanzamiento: Aparecerá una ventana de Chromium. Se verá como un navegador Chrome normal.
- El Análisis: Verás una breve pausa. Esto es DeepSeek «leyendo» la página. A diferencia de Selenium que es instantáneo,
browser-usetoma alrededor de 2-3 segundos por acción para procesar los datos visuales. - La Acción: Verás aparecer un **Cuadro Rojo** alrededor de la barra de Búsqueda de Google. Esto es el agente identificando el elemento.
- La Entrada: Escribirá «Python release date 2026» carácter por carácter.
- El Resultado: Hará clic en buscar, leerá la página y finalmente imprimirá la respuesta en tu terminal.
Se siente como magia. No le dijiste el ID de la barra de búsqueda. No le dijiste el XPath del botón de enviar. Simplemente lo averiguó.
Solución de Problemas: El «Bucle Infinito» y Otros Demonios
Aunque esta librería es increíble, no es perfecta. Dado que estamos tratando con IA, puede confundirse. Aquí están los tres problemas más comunes que enfrenté y cómo solucionarlos.
1. El Bucle del «Banner de Cookies»
El Problema: El agente va a un sitio y ve una ventana emergente gigante de «Aceptar Cookies». Intenta hacer clic en «Buscar» detrás de la ventana emergente, falla e intenta de nuevo para siempre.
La Solución: Debes tratar al agente como a un nuevo empleado. Tienes que decirle cómo manejar las distracciones.
- Mal Prompt: «Busca zapatos.»
- Prompt Pro: «Ve a amazon.com. Si ves un banner de cookies o ventana emergente, acéptalo inmediatamente. Luego busca zapatos.»
2. El Clic de «Alucinación»
El Problema: El agente intenta hacer clic en un botón que no existe, o hace clic en la cosa equivocada repetidamente.
La Solución: Esto generalmente sucede porque la ventana de contexto está llena. Asegúrate de configurar num_ctx=32000 en el código anterior. Si sigue fallando, cambia a un modelo más grande (como deepseek-r1:14b o 32b) si tu hardware puede manejarlo.
3. El Problema de «Atascado Cargando»
El Problema: El agente intenta leer la página antes de que haya terminado de cargar.
La Solución: Añade una instrucción específica para esperar.
- Prompt Pro: «Ve al sitio. Espera a que la página cargue completamente y a que aparezca el texto ‘Login’. Luego haz clic en él.»
Avanzado: Ejecución «Headless» para Producción
Una vez que estés feliz con tu bot, no querrás ver la ventana aparecer cada vez. Puedes ejecutarlo en modo «Headless» (modo en segundo plano), que es más rápido y usa menos RAM.
Simplemente cambia la configuración en tu código:
browser = Browser(
config=BrowserConfig(
headless=True, # Cambiado a True
disable_security=True
)
)
Advertencia: Algunos sitios web (como Amazon o sitios protegidos por Cloudflare) detectarán navegadores headless y los bloquearán. Si obtienes errores de «Access Denied», vuelve a cambiar a headless=False.
Código de Kaggle que estoy usando
Dado que mi laptop solo tiene 16gb de ram y Gráficos Intel Iris Xe, a veces siento que no es suficiente para tareas largas ya que se calienta demasiado pronto. Por lo tanto, siempre uso kaggle para este tipo de problemas (30gb ram+ t4 Gpu por 30 horas/semana). Aquí está el código que probé en kaggle:
import subprocess
import time
import sys
# 1. Instalar Dependencias del Sistema (¡zstd es crítico!)
print("⬇️ Installing System Dependencies...")
!sudo apt-get update
!sudo apt-get install -y pciutils lshw zstd # Agregado 'zstd' aquí
# 2. Instalar Ollama
print("⬇️ Installing Ollama...")
# Usamos curl para obtener el script y pasarlo a sh
!curl -fsSL [https://ollama.com/install.sh](https://ollama.com/install.sh) | sh
# 3. Iniciar Servidor Ollama en Segundo Plano
print("🚀 Starting Ollama Server...")
# Usamos subprocess para ejecutarlo en segundo plano para que no bloquee el notebook
process = subprocess.Popen(["ollama", "serve"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 4. Verificación
time.sleep(5) # Darle 5 segundos para arrancar
if process.poll() is None:
print("✅ Ollama is running in the background!")
else:
print("❌ Ollama failed to start. Check logs.")
print(process.stderr.read().decode())# Celda 2: Obtener el Modelo DeepSeek
# Usamos el modelo 8b porque cabe perfectamente en la GPU T4 de Kaggle.
print("🧠 Pulling DeepSeek-R1 (This takes ~2-3 mins)...")
# Usamos ! para ejecutar este comando directamente en la shell
!ollama pull deepseek-r1:8b
print("✅ Model Ready! You can now run the Agent code.")
# Instalar las librerías de Python faltantes
!pip install browser-use langchain-ollama playwright nest_asyncio
# Reinstalar navegadores Playwright (solo para estar seguros)
!playwright install chromium
import asyncio
import nest_asyncio
from langchain_ollama import ChatOllama
from pydantic import ConfigDict
import requests
from bs4 import BeautifulSoup
import re
nest_asyncio.apply()
# ==========================================
# CONFIGURATION
# ==========================================
class CleanedChatOllama(ChatOllama):
"""ChatOllama con eliminación de etiqueta de pensamiento de DeepSeek-R1"""
model_config = ConfigDict(extra="allow", frozen=False)
@property
def provider(self):
return "ollama"
@property
def model_name(self):
return self.model
def invoke(self, input, **kwargs):
response = super().invoke(input, **kwargs)
if hasattr(response, 'content'):
cleaned = re.sub(r'.*?', '', response.content, flags=re.DOTALL)
response.content = cleaned.strip()
return response
llm = CleanedChatOllama(
model="deepseek-r1:8b",
num_ctx=32000,
temperature=0.0,
)
# ==========================================
# AGENT LOGIC (sin navegador)
# ==========================================
def search_web(query):
"""Buscar en DuckDuckGo y devolver resultados"""
print(f"🔍 Searching: {query}")
response = requests.post(
"[https://html.duckduckgo.com/html/](https://html.duckduckgo.com/html/)",
data={'q': query},
headers={'User-Agent': 'Mozilla/5.0'},
timeout=10
)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
results = []
for result in soup.find_all('a', class_='result__a')[:3]:
title = result.get_text(strip=True)
url = result.get('href', '')
results.append({'title': title, 'url': url})
return results
return []
def fetch_page(url):
"""Obtener contenido de la página web"""
print(f"📄 Fetching: {url}")
try:
response = requests.get(
url,
timeout=10,
headers={'User-Agent': 'Mozilla/5.0'}
)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
# Eliminar elementos no deseados
for tag in soup(['script', 'style', 'nav', 'header', 'footer']):
tag.decompose()
text = soup.get_text(separator='\n', strip=True)
lines = [line.strip() for line in text.split('\n') if line.strip()]
return '\n'.join(lines)
except:
pass
return ""
async def agent_run(task):
"""
Agente simulado que imita el comportamiento de browser-use pero usa solicitudes HTTP
"""
print("🚀 Agent starting...")
print(f"🎯 Task: {task}\n")
# Paso 1: Analizar tarea con LLM
print("📍 Step 1: Understanding task...")
parse_prompt = f"""
Task: {task}
Extract the search query from this task. Reply with ONLY the search query, nothing else.
"""
response = llm.invoke(parse_prompt)
query = response.content.strip().strip('"'')
print(f"Query extracted: {query}\n")
# Paso 2: Buscar
print("📍 Step 2: Searching web...")
results = search_web(query)
if not results:
print("❌ No results found")
return None
print(f"Found {len(results)} results:")
for i, r in enumerate(results, 1):
print(f" {i}. {r['title']}")
print()
# Paso 3: Clicar primer resultado
print("📍 Step 3: Clicking first result...")
first_url = results[0]['url']
content = fetch_page(first_url)
if not content:
print("⚠️ Could not fetch content")
return None
print(f"✅ Fetched {len(content)} characters\n")
# Paso 4: Extraer respuesta con LLM
print("📍 Step 4: Finding answer...")
answer_prompt = f"""
Task: {task}
Page content from {results[0]['title']}:
{content[:15000]}
Based on the task, extract the exact information requested.
Be precise and direct.
"""
response = llm.invoke(answer_prompt)
answer = response.content.strip()
print("\n" + "=" * 70)
print("✅ FINAL RESULT:")
print("=" * 70)
print(answer)
print("=" * 70)
return answer
# ==========================================
# EXECUTION
# ==========================================
task = (
"Go to 'google.com'. "
"Search for 'Python release date 2026'. "
"Click on the first non-ad result. "
"Find the exact release date in the text and print it to the console."
)
async def main():
result = await agent_run(task)
# Run
await main()¿Es este el Fin de Selenium?
Sí y No.
Si estás ejecutando Pruebas Unitarias donde necesitas verificar si un botón específico funciona 10,000 veces por segundo, Selenium/Playwright sigue siendo el rey. Es rápido, determinista y barato.
Pero para Agentes—scripts que necesitan navegar por la web desordenada e impredecible para «hacer trabajo» (como aplicar a trabajos, encontrar clientes potenciales o reservar boletos)—browser-use es el nuevo estándar.
Baja la barrera de entrada de «Ingeniero Python Senior» a «Cualquiera que pueda escribir una oración».
)
¿Listo para Actualizar?
Hemos cubierto la Pila Gratuita (DeepSeek) y la Pila Visual (browser-use). ¿Pero qué sucede cuando quieres que tu agente recuerde cosas?
En el próximo artículo, exploraré la Memoria del Agente. Te mostraré cómo adjuntar una base de datos (Mem0) a tu agente para que no solo navegue—sino que aprenda.
¿Lograste hacer funcionar browser-use localmente? Déjame saber en los comentarios si te encontraste con algún ‘ImportError’—estoy reuniendo una lista de correcciones para la próxima actualización.

🚀 Let's Build Something Amazing Together
Hi, I'm Abdul Rehman Khan, founder of Dev Tech Insights & Dark Tech Insights. I specialize in turning ideas into fast, scalable, and modern web solutions. From startups to enterprises, I've helped teams launch products that grow.
- ⚡ Frontend Development (HTML, CSS, JavaScript)
- 📱 MVP Development (from idea to launch)
- 📱 Mobile & Web Apps (React, Next.js, Node.js)
- 📊 Streamlit Dashboards & AI Tools
- 🔍 SEO & Web Performance Optimization
- 🛠️ Custom WordPress & Plugin Development
