web-speed-agent
web-speed-agent
Automatización de navegador local + integración con Web Speed API para extracción web autenticada.
Dirige un agente de IA a cualquier sitio web —incluidos aquellos que requieren inicio de sesión— y obtén datos limpios y estructurados. Las credenciales permanecen en tu máquina. Solo el HTML extraído se envía al servidor.
pip install web-speed-agent
playwright install chromium¿Quieres usar esto con Claude, Gemini u otros clientes de IA?
Consulta la Guía de instalación del servidor MCP: es la forma más sencilla de permitir que los agentes de IA inicien sesión y extraigan datos mediante lenguaje natural.
Cómo funciona
Your machine Web Speed server
───────────────────────────────── ──────────────────────────
Playwright browser (local)
↓ navigates, logs in, clicks
↓ gets page HTML
↓ (no passwords sent)
agent.extract(html) ────────→ Advanced extraction engine
←──────── Structured JSONLas credenciales nunca abandonan tu máquina. El servidor solo ve el HTML.
Related MCP server: Agent Identity MCP Server
Inicio rápido
import asyncio
from web_speed_agent import Agent
async def main():
agent = Agent(api_key="wsp_...") # or set WEBSPEED_API_KEY env var
# Public pages — no browser needed
result = await agent.map("https://techcrunch.com/some-article/")
print(result["article"]["sections"])
# Authenticated pages — browser runs locally
agent.store_credential("mysite", "me@example.com", "mypassword")
async with agent.browser(session_name="mysite") as browser:
page = await browser.new_page()
await page.goto("https://mysite.com/login")
username, password = agent.get_credential("mysite")
await page.fill('[name="email"]', username)
await page.fill('[name="password"]', password)
await page.click('button[type="submit"]')
await page.wait_for_load_state("networkidle")
# Now on a logged-in page — extract it
html = await page.content()
result = await agent.extract(html, page_type="listing")
print(result["listing"]["items"])
asyncio.run(main())Obtén una clave API en getwebspeed.io.
Instalación
Requisitos: Python 3.10+, una clave API de Web Speed
pip install web-speed-agent
playwright install chromium
export WEBSPEED_API_KEY="wsp_..."Conceptos básicos
Agente
La clase principal. Gestiona credenciales, sesiones de navegador y llamadas a la API.
from web_speed_agent import Agent
# API key from argument
agent = Agent(api_key="wsp_...")
# API key from environment variable (recommended)
# export WEBSPEED_API_KEY="wsp_..."
agent = Agent()
# Use as async context manager (auto-closes HTTP client)
async with Agent() as agent:
...Extracción de páginas públicas
No se necesita navegador para páginas que no requieren inicio de sesión:
# Fetch + extract in one call
result = await agent.map("https://example.com/article")
# With JavaScript rendering (for heavy SPAs)
result = await agent.map("https://example.com/spa", js=True)Extracción de páginas autenticadas
Utiliza una sesión de navegador local. El navegador se ejecuta en tu máquina:
async with agent.browser(session_name="mysite") as browser:
page = await browser.new_page()
await page.goto("https://mysite.com/dashboard")
html = await page.content()
result = await agent.extract(html)El session_name guarda las cookies en ~/.webspeed/sessions/<name>/ para que las ejecuciones posteriores omitan el paso de inicio de sesión.
Gestión de credenciales
Las credenciales se almacenan en el llavero de tu sistema (macOS Keychain, Administrador de credenciales de Windows, secret-tool de Linux). Nunca se envían a los servidores de Web Speed.
# Store once
agent.store_credential("mysite", "me@example.com", "mypassword")
# Retrieve anywhere
username, password = agent.get_credential("mysite")
# Remove
agent.delete_credential("mysite")Salida de extracción
El servidor devuelve datos estructurados conscientes del tipo de página:
# Article
result = await agent.extract(html, page_type="article")
# result["page_type"] → "article"
# result["title"] → "Article Title"
# result["author"] → "Jane Smith"
# result["published_date"] → "2026-05-06"
# result["article"]["sections"] → [{"heading": "...", "paragraphs": [...]}]
# result["article"]["links"] → [{"text": "...", "url": "..."}]
# Product
result = await agent.extract(html, page_type="product")
# result["product"]["name"] → "Wireless Headphones"
# result["product"]["price"] → "$99.99"
# result["product"]["availability"] → "In Stock"
# result["product"]["rating"] → "4.5"
# result["product"]["specs"] → {"Battery": "30h", ...}
# Listing (search results, category pages)
result = await agent.extract(html, page_type="listing")
# result["listing"]["items"] → [{"title": "...", "url": "...", "price": "..."}]
# Auto-detect (default)
result = await agent.extract(html)
# result["page_type"] → "article" | "product" | "listing" | "other"Todos los resultados incluyen engine: "advanced" — entre un 60 y un 85% más eficiente en tokens que el HTML sin procesar.
Ejemplos
Monitor de precios
import asyncio
from web_speed_agent import Agent
async def check_price(url: str, site_name: str) -> str:
async with Agent() as agent:
agent.store_credential(site_name, "me@example.com", "password", overwrite=True)
async with agent.browser(session_name=site_name) as browser:
page = await browser.new_page()
# Login
await page.goto(f"https://{site_name}.com/login")
user, pwd = agent.get_credential(site_name)
await page.fill('[name="email"]', user)
await page.fill('[name="password"]', pwd)
await page.click('button[type="submit"]')
await page.wait_for_load_state("networkidle")
# Check product
await page.goto(url)
await page.wait_for_load_state("networkidle")
html = await page.content()
result = await agent.extract(html, page_type="product")
return result.get("product", {}).get("price", "unknown")
price = asyncio.run(check_price("https://example.com/product/123", "example"))
print(f"Current price: {price}")Leer un panel privado
import asyncio
from web_speed_agent import Agent
async def get_dashboard_data():
async with Agent() as agent:
async with agent.browser(session_name="analytics") as browser:
page = await browser.new_page()
# Login (first run only — session persists after)
creds = agent.get_credential("analytics")
if not creds:
agent.store_credential("analytics", "me@company.com", "password")
creds = agent.get_credential("analytics")
await page.goto("https://analytics.company.com/login")
await page.fill('[name="email"]', creds[0])
await page.fill('[name="password"]', creds[1])
await page.click('button[type="submit"]')
await page.wait_for_load_state("networkidle")
# Navigate to dashboard
await page.goto("https://analytics.company.com/dashboard")
await page.wait_for_selector(".metrics-table", timeout=10000)
html = await page.content()
result = await agent.extract(html)
return result
asyncio.run(get_dashboard_data())Scraping de varias páginas mientras estás conectado
import asyncio
from web_speed_agent import Agent
async def scrape_inbox():
async with Agent() as agent:
async with agent.browser(session_name="webmail") as browser:
page = await browser.new_page()
# Login
await page.goto("https://mail.example.com/login")
user, pwd = agent.get_credential("webmail")
await page.fill('[name="username"]', user)
await page.fill('[name="password"]', pwd)
await page.click('[type="submit"]')
await page.wait_for_load_state("networkidle")
# Scrape multiple pages
emails = []
for page_num in range(1, 4):
await page.goto(f"https://mail.example.com/inbox?page={page_num}")
await page.wait_for_load_state("networkidle")
html = await page.content()
result = await agent.extract(html, page_type="listing")
emails.extend(result.get("listing", {}).get("items", []))
return emails
asyncio.run(scrape_inbox())Integración con agentes de IA (MCP)
El servidor MCP incluido permite que Claude Desktop, Gemini CLI y cualquier agente compatible con MCP utilicen el SDK directamente. El agente puede iniciar sesión, navegar, hacer clic y extraer, todo a través del lenguaje natural.
Inicia el servidor MCP:
WEBSPEED_API_KEY="wsp_..." python3 agent_mcp_server.pyAñadir a Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"web-speed-agent": {
"command": "python3",
"args": ["/path/to/agent_mcp_server.py"],
"env": {
"WEBSPEED_API_KEY": "wsp_..."
}
}
}
}Añadir a Gemini CLI (~/.gemini/settings.json):
{
"mcpServers": {
"web-speed-agent": {
"command": "python3.11",
"args": ["/path/to/agent_mcp_server.py"],
"env": {
"WEBSPEED_API_KEY": "wsp_...",
"PYTHONPATH": "/path/to/web-speed-agent"
}
}
}
}Luego dile al agente:
"Guarda mis credenciales para united — usuario me@example.com, contraseña mi_contraseña"
"Inicia sesión en united.com y búscame el vuelo más barato de SFO a JFK el próximo viernes"
Herramientas MCP disponibles:
Herramienta | Descripción |
| Guardar inicio de sesión en el llavero del sistema |
| Abrir navegador + iniciar sesión |
| Ir a una URL en la sesión activa |
| Obtener datos estructurados de la página actual |
| Hacer clic en un botón o enlace |
| Escribir en un campo de formulario |
| Enviar un formulario |
| Finalizar la sesión del navegador |
| Comprobar el saldo de créditos de la API |
Referencia de la API
Agent
Agent(
api_key: str | None = None,
server_url: str | None = None,
config_dir: str = "~/.webspeed",
headless: bool = True,
)Parámetro | Descripción |
| Clave API de Web Speed. Utiliza la variable de entorno |
| Sobrescribir la URL del servidor API. Por defecto: |
| Directorio para configuración, sesiones y registros. Por defecto: |
| Ejecutar el navegador sin interfaz gráfica. Por defecto: |
agent.browser()
agent.browser(
session_name: str | None = None,
headless: bool | None = None,
proxy: str | None = None,
) -> ManagedBrowserDevuelve un gestor de contexto asíncrono. Dentro del bloque, llama a .new_page() para obtener una Page de Playwright.
Parámetro | Descripción |
| Persistir cookies en |
| Sobrescribir el |
| URL del proxy, p. ej. |
Los nombres de sesión deben ser alfanuméricos + guiones/guiones bajos, máximo 64 caracteres.
agent.extract()
await agent.extract(
html: str,
page_type: str = "auto",
) -> dictEnvía HTML a la API de Web Speed. Cuesta 1 crédito.
Parámetro | Descripción |
| Cadena HTML sin procesar (p. ej. desde |
|
|
agent.map()
await agent.map(
url: str,
js: bool = False,
) -> dictObtiene y extrae una URL pública a través del servidor. No se necesita navegador local. Cuesta 1 crédito.
Parámetro | Descripción |
| URL de la página. Debe ser |
| Renderizar JavaScript antes de extraer. |
agent.account()
await agent.account() -> dictDevuelve: credits, tier, status, lifetime (total/aciertos/fallos).
agent.store_credential()
agent.store_credential(
site: str,
username: str,
password: str,
overwrite: bool = False,
) -> NoneGuarda en el llavero del sistema. Lanza CredentialError si la credencial existe y overwrite=False.
agent.get_credential()
agent.get_credential(site: str) -> tuple[str, str] | NoneDevuelve (username, password) o None si no se encuentra.
agent.delete_credential()
agent.delete_credential(site: str) -> NoneElimina la credencial del llavero.
Excepciones
from web_speed_agent import (
WebSpeedError, # Base exception
AuthenticationError, # Invalid/missing API key
InsufficientCreditsError, # No credits remaining
APIError, # API returned 4xx/5xx
RateLimitError, # 429 Too Many Requests
CredentialError, # Keychain error
BrowserError, # Playwright error
NetworkError, # Timeout or DNS failure
PlaywrightNotInstalledError, # Run: playwright install chromium
)from web_speed_agent import Agent, InsufficientCreditsError, NetworkError
try:
result = await agent.extract(html)
except InsufficientCreditsError:
print("Out of credits — top up at getwebspeed.io")
except NetworkError as e:
print(f"Connection failed: {e}")Configuración
Variables de entorno
Variable | Descripción |
| Clave API (recomendado sobre el archivo de configuración) |
| Sobrescribir la URL del servidor (debe ser |
Archivo de configuración
~/.webspeed/config.yaml — creado automáticamente en la primera ejecución. Permisos establecidos en 0o600 (solo propietario).
api:
server_url: https://api.getwebspeed.io
timeout: 30
browser:
headless: trueArchivos de sesión
Las sesiones de navegador persistentes se almacenan en ~/.webspeed/sessions/<name>/storage.json.
Permisos:
0o600(solo propietario)Contiene: cookies, localStorage, sessionStorage
Seguro de eliminar: el agente volverá a autenticarse en la siguiente ejecución
Seguridad
Qué abandona tu máquina
Cuando llamas a agent.extract(html), el HTML de la página se envía a la API de Web Speed para su procesamiento. Todo lo demás permanece local.
Datos | A dónde van |
Credenciales de inicio de sesión | Nunca abandonan tu máquina (solo llavero del sistema) |
Cookies / sesión del navegador | Nunca abandonan tu máquina (Playwright local) |
HTML de la página | Enviado por HTTPS a la API de Web Speed para extracción |
JSON extraído | Devuelto a ti |
Limpieza de HTML (activada por defecto)
Antes de que se transmita cualquier HTML, el SDK lo limpia automáticamente de forma local:
Bloques
<script>y<style>en línea eliminadosCampos de formulario ocultos con nombres relacionados con la autenticación (
csrf,token,nonce,session, etc.) tienen sus valores vaciadosAtributos de contenido
<meta>sensibles borradosComentarios HTML eliminados
El contenido visible (texto, enlaces, tablas, encabezados, datos de productos) permanece intacto.
# Default: scrubbing is on
result = await agent.extract(html)
# Turn off only if the page has no sensitive data
result = await agent.extract(html, scrub=False)
# Or scrub manually and inspect before sending
from web_speed_agent import scrub
clean_html = scrub(raw_html)
print(clean_html) # inspect what will be sent
result = await agent.extract(clean_html, scrub=False)Manejo de datos del lado del servidor
HTML procesado solo en memoria — nunca escrito en disco, nunca registrado, nunca almacenado en caché
Páginas protegidas por autenticación nunca almacenadas en caché — las páginas que requieren inicio de sesión están explícitamente excluidas del registro compartido
Los registros de uso solo almacenan: un hash de tu clave API, un hash de la URL (o
"sdk-extract"), marca de tiempo y tipo de página detectado — sin contenidoSin HTML sin procesar en respuestas de error — las excepciones se desinfectan antes de devolver cualquier error
Otras protecciones
Credenciales almacenadas en el llavero del sistema, nunca en archivos, nunca enviadas a servidores
Archivos de sesión escritos con permisos
0o600(lectura/escritura solo para el propietario)Directorio de configuración creado con permisos
0o700TLS siempre verificado —
verify=Trueen todas las llamadas HTTP, no se puede desactivarHTTPS forzado —
server_urldebe comenzar conhttps://, HTTP plano rechazadoPrevención de recorrido de rutas — nombres de sesión validados contra una lista blanca
[a-zA-Z0-9_-]Sin registro de credenciales — las contraseñas nunca aparecen en registros o mensajes de error
Licencia
GNU General Public License v3.0 — ver LICENSE.
El uso de la API de Web Speed está sujeto a los Términos de servicio de Web Speed.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceReducing token usage by 70% with a deterministic mapping engine. Also links in with the Web Speed Agent SDK and MCP for post-auth agents.10GPL 3.0
- AlicenseNot gradedqualityDmaintenanceMCP Server for AI agent identity and authorization. Create, verify, and manage agent identities with trust scores and scoped authorization tokens.MIT
- AlicenseAqualityAmaintenanceProvides an MCP-native agent browser that enables autonomous agents to perceive and interact with web pages through stealth browsing, identity borrowing, and WAAP detection.9MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP-capable runtimes to read agent message rooms, sign and post public messages, and create or verify Ed25519 contribution proofs for Technocore.MIT
Related MCP Connectors
Agent-first web hosting: deploy sites, apps, databases and domains over MCP.
Hosted AgentLux MCP server for marketplace, identity, creator, services, and social flows.
MCP Server for agents to onboard, pay, and provision services autonomously with InFlow
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Dominic-Pi-Sunyer/web-speed-agent'
If you have feedback or need assistance with the MCP directory API, please join our Discord server