Habilidad de Búsqueda Local
Búsqueda web local con retroceso automático entre motores. Scraping HTML directo de DuckDuckGo / Bing / Google · resistente a límites de tasa · esquema de resultados canónico.
Esta habilidad llama a los motores de búsqueda públicos directamente desde tu máquina. Sin clave API, sin SDK, sin saltos de red. Si un motor te está limitando la tasa, el orquestador retrocede silenciosamente al siguiente — por lo que la llamada suele tener éxito en el primer intento, incluso desde IPs de datacenter donde Google está bloqueado.
Cada resultado es un SearchFunctionResultItem con los 7 campos canónicos (url, name, snippet, host_name, rank, date, favicon) más tres campos de extensión opcionales: source_engine, raw_html, score. El código consumidor escrito para cualquier habilidad de búsqueda web con forma similar funciona aquí sin cambios.
✨ Destacados
- Dependencia cero de SDK en la nube — solo
cheerio(analizador HTML) y elfetchintegrado de Node. - Tres motores, retroceso automático — DuckDuckGo → Bing → Google cuando
engine: "auto"(por defecto). - Consciente de configuración regional —
--locale en-US/zh-CN/ja-JP/ cualquier etiqueta BCP-47. Crítico para IPs no estadounidenses donde Bing muestra resultados localizados incluso para consultas en inglés. - Filtro de actualidad —
--recency-days 7restringe a resultados de la última semana. DDG admite días exactos; Bing/Google usan bloques de día/semana/mes. - Esquema de resultados canónico — campos
url/name/snippet/host_name/rank/date/favicon, idénticos en forma a otras habilidades de búsqueda web en el registro de ClawHub. - CLI + SDK — usa
tsx bin/web-search.ts <consulta>para usos puntuales, oimport { search } from "local-search"en código. - TypeScript ESM puro — se ejecuta en Node 18+ con
tsx, o sin configuración conbun.
🚀 Inicio Rápido
# 1. Instalar (una dependencia de ejecución: cheerio)
cd skills/local-search && npm install
# 2. Buscar (retroceso automático entre DDG → Bing → Google)
tsx bin/web-search.ts "inteligencia artificial"
# 3. Fijar un motor y configuración regional específicos
tsx bin/web-search.ts "aprendizaje automático" --engine bing --locale en-US --num 5
# 4. Noticias recientes como JSON
tsx bin/web-search.ts "avances en IA" --recency-days 7 --json -o ai_news.json
Uso programático:
import { search } from "local-search";
const outcome = await search("¿Cuál es la capital de Francia?", { num: 5 });
if (outcome.success) {
console.log(`Respondido por ${outcome.engine} en ${outcome.elapsedMs}ms`);
outcome.results.forEach(r => console.log(`- ${r.name}\n ${r.url}`));
}
🎯 Cuándo Usar Esta Habilidad
Usa local-search cuando el usuario necesite información que vive en la web pública — más allá de lo que está en los datos de entrenamiento del modelo:
- Información en tiempo real: noticias actuales, precios de acciones, clima, resultados deportivos
- Documentación más reciente: notas de versión de frameworks, cambios en APIs, artículos recién publicados
- Verificación de hechos: comprobar una afirmación contra fuentes web en vivo
- Investigación: recopilar múltiples fuentes sobre un tema, comparar perspectivas
- Descubrimiento de contenido: encontrar tutoriales, publicaciones de blog, charlas recientes
- Análisis competitivo / de mercado: anuncios de competidores, tendencias de la industria
- Consulta académica: buscar artículos, citas, páginas de autores
🔄 Comparación de Motores
| Motor | Endpoint | Clave API | IP Residencial | IP de Datacenter | Actualidad |
|---|---|---|---|---|---|
| DuckDuckGo | html.duckduckgo.com/html/ (GET) | ninguna | ✅ alta | ⚠️ límites de tasa bajo carga | df=d<N> (días exactos) |
| Bing | www.bing.com/search | ninguna | ✅ alta | ✅ alta | freshness=d1|w1|m1 (en bloques) |
www.google.com/search | ninguna | ⚠️ media | ❌ baja (pantalla enablejs) | tbs=qdr:d|w|m|y (en bloques) |
engine: "auto" los prueba en orden DuckDuckGo → Bing → Google, devolviendo el primer conjunto de resultados no vacío. Desde una IP de datacenter la cadena efectiva es DDG → Bing (Google suele estar bloqueado); desde una IP residencial los tres son viables. Edita AUTO_ENGINE_ORDER en src/engines/index.ts para cambiar la prioridad.
📦 Ruta de Instalación
Ubicación recomendada: {project_path}/skills/local-search
Extrae este paquete de habilidad a la ruta anterior en tu proyecto.
Prerrequisitos
- Node.js >= 18 (usa el
fetchglobal integrado). - Una dependencia npm:
cheerio(analizador HTML). - Una conexión a Internet funcional — la habilidad llama a los motores de búsqueda públicos directamente.
Instala una vez en el directorio de la habilidad:
cd {project_path}/skills/local-search
npm install # o: bun install / pnpm install
La habilidad es TypeScript ESM puro. Puedes ejecutarla con
tsx(recomendado, amigable para desarrollo) obun(sin configuración). También funcionanode --experimental-strip-types bin/web-search.tsen Node 22+.
¿Por Qué Local?
| Aspecto | Habilidades de búsqueda en la nube | Esta habilidad (local-search) |
|---|---|---|
| Backend de búsqueda | Función en la nube / API | HTTP directo a DuckDuckGo / Bing / Google |
| Clave API / SDK | Requerido | Ninguno |
| Ruta de red | Cliente → nube → motor de búsqueda | Cliente → motor de búsqueda |
| Manejo de fallos | Dependiente del SDK | Retroceso automático entre 3 motores |
| Esquema de resultados | SearchFunctionResultItem (7 campos) | Mismos 7 campos + 3 campos opcionales de extensión |
| CLI | Específico del SDK | tsx bin/web-search.ts |
Arquitectura
local-search/
├── SKILL.md ← estás aquí
├── LICENSE.txt
├── package.json ← declara la dependencia `cheerio`
├── tsconfig.json
├── bin/
│ └── web-search.ts ← entrada CLI
├── src/
│ ├── index.ts ← exportaciones públicas del SDK
│ ├── search.ts ← orquestador con retroceso automático
│ ├── types.ts ← SearchFunctionResultItem + opciones
│ └── engines/
│ ├── _shared.ts ← ayudantes de fetch / análisis
│ ├── duckduckgo.ts ← POST https://html.duckduckgo.com/html/
│ ├── bing.ts ← GET https://www.bing.com/search
│ ├── google.ts ← GET https://www.google.com/search
│ └── index.ts ← registro de motores + AUTO_ENGINE_ORDER
└── scripts/
└── web_search.ts ← ejemplo de inicio rápido
La única dependencia de ejecución es cheerio (analizador HTML), declarada en package.json. El fetch integrado de Node 18+ cubre la capa de red — no se importa ningún otro SDK en este paquete.
Uso de la CLI
La CLI reside en bin/web-search.ts. Ejecútala con tsx, bun o cualquier ejecutor compatible con TS.
Búsqueda Básica
# Por defecto: motor automático, 10 resultados, salida legible para humanos
tsx bin/web-search.ts "inteligencia artificial"
# Limitar número de resultados
tsx bin/web-search.ts "aprendizaje automático" --num 5
# (la opción corta también funciona)
tsx bin/web-search.ts "aprendizaje automático" -n 5
Fijar un Motor Específico
# Forzar solo DuckDuckGo
tsx bin/web-search.ts "últimas noticias de tecnología" --engine duckduckgo
# Forzar solo Bing
tsx bin/web-search.ts "últimas noticias de tecnología" --engine bing
# Forzar solo Google (mayor calidad, más propenso a límites de tasa)
tsx bin/web-search.ts "últimas noticias de tecnología" --engine google
# Por defecto — probar DDG → Bing → Google, devolver el primer no vacío
tsx bin/web-search.ts "últimas noticias de tecnología" --engine auto
Filtro de Actualidad
# Resultados de los últimos 7 días
tsx bin/web-search.ts "noticias de criptomonedas" --num 10 --recency-days 7
# (opción corta)
tsx bin/web-search.ts "noticias de criptomonedas" -r 7
Guardar Resultados en JSON
# Escribir JSON a un archivo (el banner legible se suprime)
tsx bin/web-search.ts "investigación sobre cambio climático" --num 5 --json -o search_results.json
# O canalizar JSON a la salida estándar
tsx bin/web-search.ts "avances en IA" --num 3 --recency-days 1 --json > ai_news.json
Modo Silencioso (Scripts / Tuberías)
# Suprimir el banner de "motor / temporización" — solo imprimir los resultados
tsx bin/web-search.ts "react hooks" --quiet
Parámetros de la CLI
| Flag | Corto | Descripción |
|---|---|---|
--num <N> | -n | Número de resultados (por defecto: 10, máximo: 50) |
--engine <id> | -e | duckduckgo | bing | google | auto (por defecto: auto) |
--recency-days <N> | -r | Restringir a resultados de los últimos N días (por defecto: 0 = sin filtro) |
--timeout <ms> | — | Tiempo de espera por motor en ms (por defecto: 8000) |
--json | — | Emitir JSON en lugar de salida legible |
--output <ruta> | -o | Escribir JSON a un archivo en lugar de la salida estándar |
--pretty | — | Imprimir JSON de forma bonita (por defecto activado; pasa --no-pretty para desactivar — aún no soportado, omite --json en su lugar) |
--quiet | -q | Suprimir el banner de información del motor |
--help | -h | Mostrar ayuda |
Estructura del Resultado de Búsqueda
Cada elemento de resultado es un SearchFunctionResultItem:
interface SearchFunctionResultItem {
// ----- Campos canónicos (forma compartida entre habilidades de búsqueda web de ClawHub) -----
url: string; // URL completa del resultado
name: string; // Título de la página
snippet: string; // Texto de vista previa / descripción
host_name: string; // Nombre de dominio (ej. "en.wikipedia.org")
rank: number; // Clasificación basada en 1 dentro del conjunto de resultados del motor
date: string; // Fecha de publicación / actualización; "N/A" cuando se desconoce
favicon: string; // URL del favicon (Google S2)
// ----- Campos de extensión (nuevos en local-search) -----
source_engine: "duckduckgo" | "bing" | "google";
raw_html?: string; // HTML original del elemento de snippet (opcional)
score?: number; // Puntuación de relevancia heurística [0, 100] (opcional)
}
Uso del SDK
Si estás escribiendo código TypeScript/JavaScript (no ejecutando la CLI), importa desde src/index.ts:
Búsqueda Simple
import { search } from "local-search";
const outcome = await search("¿Cuál es la capital de Francia?", { num: 5 });
if (outcome.success) {
console.log(`Motor usado: ${outcome.engine}`);
console.log(`Probados en orden: ${outcome.enginesTried.join(" → ")}`);
console.log(`Transcurrido: ${outcome.elapsedMs}ms`);
for (const item of outcome.results) {
console.log(`- ${item.name} [${item.source_engine}]`);
console.log(` ${item.url}`);
console.log(` ${item.snippet}`);
}
} else {
console.error("Búsqueda fallida:", outcome.error);
if (outcome.errors) {
// Modo automático: ver qué motores se probaron y qué informaron
for (const e of outcome.errors) {
console.error(` ${e.engine}:`, e.error);
}
}
}
Variante con Lanzamiento de Excepción en Fallo
import { searchOrThrow, AllEnginesFailedError } from "local-search";
try {
const results = await searchOrThrow("Frameworks de JavaScript", { num: 10 });
console.log(results);
} catch (err) {
if (err instanceof AllEnginesFailedError) {
console.error("Todos los motores fallaron:", err.errors);
} else {
console.error("Error de un solo motor:", err);
}
}
Fijar un Motor Específico
import { search } from "local-search";
// Saltar la cadena de retroceso — usar solo DuckDuckGo.
const outcome = await search("aplicaciones de computación cuántica", {
num: 8,
engine: "duckduckgo",
});
Filtro de Actualidad
const outcome = await search("investigación en genómica", {
num: 5,
recency_days: 30, // últimos 30 días
});
Fetch Personalizado (Pruebas / Entornos de Ejecución Edge)
const outcome = await search("hola mundo", {
fetchImpl: myMockFetch, // cualquier función compatible con WhatWG-fetch
userAgent: "mi-bot/1.0",
timeoutMs: 5000,
});
Motores Backend
DuckDuckGo (duckduckgo)
- Endpoint:
https://html.duckduckgo.com/html/(formulario POSTq=...) - Sin clave API. Sujeto a límites de tasa aproximados — el uso intensivo sostenido devuelve conjuntos de resultados vacíos.
- Actualidad: campo de formulario
df=d<N>. - Mejor para: primer intento por defecto; raramente bloqueado directamente; respeta la privacidad.
Bing (bing)
- Endpoint:
https://www.bing.com/search?q=...&count=... - Sin clave API. El diseño HTML es estable y fácil de analizar.
- Actualidad: bloque
freshness=d1/w1/m1(Bing no tiene un filtro de URL de N días arbitrarios). - Mejor para: segundo retroceso; buenos resultados en inglés; peculiaridades ocasionales de configuración regional (mitigadas por
ensearch=1).
Google (google)
- Endpoint:
https://www.google.com/search?q=...&num=... - Sin clave API, PERO Google es el más agresivo bloqueando scrapers. Desde IPs de datacenter / nube Google generalmente devuelve una página de redirección "por favor, habilite JS" (
/httpservice/retry/enablejs) con cero resultados analizables — el motor muestra esto como un fallo suave y la cadena automática retrocede. Desde IPs residenciales, el scraping HTML de Google a menudo funciona bien. - Actualidad: bloque
tbs=qdr:d|w|m|y. - Mejor para: retroceso de último recurso en IPs residenciales; generalmente fallará en IPs de nube (donde DDG+Bing ya cubren la necesidad).
Estrategia de Retroceso Automático
Cuando engine: "auto" (el valor por defecto), el orquestador prueba los motores en este orden:
- DuckDuckGo — bloqueo menos agresivo, filtro de fecha más detallado
- Bing — generalmente estable desde cualquier IP, incluyendo datacenter
- Google — mejor calidad de resultado cuando es accesible; a menudo bloqueado en IPs de datacenter
Devuelve el primer motor que produce ≥ 1 resultado. Si los tres fallan, el resultado es { success: false, errors: [...] } con el error de cada motor adjunto — o, en modo searchOrThrow, un AllEnginesFailedError.
Tabla de fiabilidad práctica (observada durante las pruebas):
| Tipo de IP del llamante | DDG | Bing | Cadena automática efectiva | |
|---|---|---|---|---|
| Residencial | alta | alta | media | DDG → Bing → Google (3 viables) |
| Datacenter / nube | media (límites de tasa bajo carga) | alta | baja (pantalla enablejs) | efectivamente DDG → Bing |
El orden se define en src/engines/index.ts (AUTO_ENGINE_ORDER); edita ese array si deseas una prioridad diferente.
Casos de Uso Comunes
- Información en tiempo real — noticias de última hora, clima, resultados deportivos, precios de acciones
- Documentación más reciente — notas de versión de frameworks, cambios en APIs, documentación actualizada
- Verificación de hechos — comprobar afirmaciones contra fuentes web en vivo para precisión
- Investigación — recopilar múltiples perspectivas sobre un tema para un análisis completo
- Descubrimiento de contenido — encontrar tutoriales, ejemplos de código, mejores prácticas
- Análisis competitivo — rastrear anuncios de competidores, tendencias del mercado
- Consulta académica — buscar artículos de investigación, citas académicas, páginas de autores
- Depuración — encontrar problemas conocidos, correcciones de errores, discusiones de la comunidad
Solución de Problemas
| Síntoma | Causa probable | Solución |
|---|---|---|
| DuckDuckGo devuelve un conjunto vacío | Límite de tasa alcanzado | Espera unos segundos o usa --engine bing |
| Google devuelve "Habilite JavaScript" | IP de datacenter / nube | Usa --engine auto (retrocede a Bing) o --engine duckduckgo |
| Resultados de Bing en un idioma inesperado | Configuración regional de la IP | Siempre usa --locale en-US (o tu BCP-47) |
| La búsqueda funciona en la CLI pero no en el código | Ruta de importación incorrecta | Importa desde local-search o la ruta relativa a src/index.ts |
| La búsqueda falla con un error de red | Sin conectividad / proxy bloqueante | Verifica la conexión a Internet / complementos de firewall |
El resultado date es "N/A" para todos los motores | El motor no expuso fechas | Es normal para algunos hitos — el campo siempre se proporciona |
Limitaciones
- No adecuado para búsqueda a gran escala — el uso intensivo sostenido desencadenará límites de tasa en DuckDuckGo y posiblemente en Bing. Estas herramientas están diseñadas para consultas esporádicas y bajo demanda disparadas por un usuario humano.
- Sin acceso a APIs de búsqueda premium — no se puede acceder a Google Custom Search, Bing Web Search API ni ningún servicio de nivel pago. Los resultados son puramente de scraping HTML público.
- Dependencia de la estabilidad del diseño HTML — si DuckDuckGo, Bing o Google rediseñan sus páginas de resultados, esta habilidad puede necesitar una actualización para adaptarse al nuevo diseño. El autor monitorea y actualiza activamente.
- JSON de salida sin streaming — la CLI recopila todos los resultados y luego los emite; no hay resultados en streaming mientras llegan. Esto es intencional: el orquestador espera hasta que un motor termina (o falla) antes de decidir retroceder.
Preguntas Frecuentes
P: ¿Se ejecuta esto en una función en la nube?
R: No. La habilidad ejecuta el scraping HTML directamente desde tu máquina. Sin intermediarios.
P: ¿Necesito una clave API?
R: No para DuckDuckGo, Bing ni Google. Todo es scraping de HTML público.
P: ¿Funciona esto en un entorno de nube (AWS Lambda, etc.)?
R: Sí, pero ten en cuenta: desde IPs de nube, Google es generalmente inaccesible. El motor automático retrocede a Bing, que funciona bien desde direcciones IP de nube.
P: ¿Cómo maneja la habilidad las diferencias de configuración regional?
R: Pasa --locale en-US (o zh-CN, ja-JP, cualquier BCP-47). Esto es particularmente importante para Bing, que por defecto sirve versiones localizadas según la IP.
P: ¿Puedo cambiar el orden de retroceso?
R: Sí. Edita AUTO_ENGINE_ORDER en src/engines/index.ts. Reordena el array como desees.
P: ¿Cuántos resultados puedo obtener?
R: El máximo es 50 (el límite de Google). El valor por defecto es 10. Valores más altos significan más solicitudes a medida que el motor de búsqueda carga más páginas.
P: ¿Puedo usar esto con Bun?
R: Sí. bun bin/web-search.ts "consulta" funciona inmediatamente (sin npm install necesario).
Hecho con ❤️ para desarrolladores que quieren búsqueda web directa y sin complicaciones.