Ir al contenido

Documentación de Fisherboy

Esta página documenta cómo funciona Fisherboy de principio a fin: los conceptos centrales, la interfaz web, las capacidades de descarga, las APIs REST y MCP, y la configuración avanzada.

Todo lo que hace Fisherboy es un trabajo. Envías un trabajo (una URL más opciones), se encola en Redis, un worker ejecuta el pipeline, y el resultado se almacena como un envelope — un único objeto que contiene el contenido extraído (content_md), los registros estructurados, el árbol de crawl, los enlaces descubiertos y los metadatos. Consultas el trabajo hasta que su estado sea ok.

Fetch por niveles (escala solo cuando se bloquea)

Sección titulada «Fetch por niveles (escala solo cuando se bloquea)»

Fisherboy nunca recurre a un navegador pesado hasta que tiene que hacerlo. Prueba el método más barato primero y sube de nivel solo cuando un gate detecta un bloqueo o un CAPTCHA:

  • Nivel 0 — HTTP estático con httpx. Rápido y barato; funciona para la mayoría de las páginas estáticas.
  • Nivel 1 — huella TLS con curl_cffi, para que la petición parezca la de un navegador real en la capa de red.
  • Nivel 2 — navegador stealth (Camoufox / Patchright) para páginas con mucho JavaScript y anti-bot; este nivel también impulsa la captura de API oculta.
  • Nivel 3 — un navegador real (nodriver / Playwright) como último recurso.

El nivel ganador se cachea por dominio (TIER_CACHE_TTL_S), de modo que la siguiente petición al mismo sitio empieza donde tuvo éxito por última vez. Los niveles altos se importan de forma perezosa — la imagen base se mantiene ligera, y cada nivel se activa solo si su librería está instalada. El techo de escalado se configura con MAX_FETCH_TIER, y tier_hint en un trabajo puede sugerir un punto de partida.

Las aplicaciones de una sola página y las grillas dinámicas se renderizan desde JSON que obtienen por XHR/fetch. En lugar de pelear con el HTML renderizado, Fisherboy puede observar esas respuestas de red y conservar el JSON que la página ya consume — normalmente la fuente más confiable y completa de los datos. Actívala por trabajo con capture_api.

El modo de privacidad se elige por trabajo y está acotado por rol (definido en privacy_matrix.yaml, nunca hardcodeado). El pipeline es fail-closed: si la anonimización falla, no se entrega nada crudo.

  • opaco (opaco) — cada entidad se convierte en un marcador tipado estable como «PERSON_1» o «ID_2». El LLM razona sobre los marcadores y nunca ve la PII; el original no es recuperable.
  • reversible — el mismo enmascarado, pero se conserva un mapa cifrado de token a valor para que puedas re-hidratar más tarde mediante POST /api/revert (un solo uso, acotado por rol). El mapa se cifra con una clave Fernet (REVERSIBLE_KEY) y expira después de REVERSIBLE_TTL_S.
  • directo (directo) — salida cruda, solo para datos no sensibles.

Una pasada determinista de regex siempre se ejecuta para la PII de alto riesgo (DNI nacional, email, IP, tarjeta válida por Luhn, teléfono). Cuando ANONIMAL_URL apunta a una instancia de Anonimal, el NER completo se ejecuta encima; en standalone recurre solo a la pasada de regex integrada.

Si un rol no permite el modo solicitado, el gateway devuelve 403 — nunca degrada silenciosamente.

Fisherboy tiene tres niveles de acceso, cada uno con su propia contraseña y límites de capacidad (qué niveles, proxies, captura de API, solver de captcha, crawl y tarántula están permitidos). Los roles se aplican en ambos, REST y MCP.

Rolopacoreversibledirecto
humano
angel
dios

En general: humano obtiene los niveles baratos y ninguna “arma” costosa; angel añade navegador, proxy y captura (pero no solver de captcha); dios tiene todo. La tarántula y la lectura de cookies del navegador están vetadas en el modo sidekick.

En modo standalone Fisherboy monta su propia interfaz web en la URL del servicio (p. ej. http://localhost:8000). Después de iniciar sesión con una contraseña de rol, tú:

  1. Pegas una URL y eliges la salida (markdown, llms_txt o json) y el modo de privacidad permitido por tu rol.
  2. Opcionalmente habilitas extras — paginación, captura de API, una profundidad de crawl, tarántula, un proxy, cookies.
  3. Ejecutas el trabajo; el resultado se abre en un editor modal.

El resultado se abre en un editor modal con tres pestañas:

  • Markdown — una barra de herramientas con vista previa en vivo.
  • JSON — un editor con validación.
  • Tabla — una tabla editable; JSON ↔ tabla es solo cambiar de pestaña.

Puedes descargar el resultado como .md, .json o .csv. Puedes descargar el envelope completo, solo los datos (contenido + registros + árbol + enlaces), o un array plano de registros. Un clic envía el resultado a Escriba para una conversión, anonimización, chunking y exportación adicionales.

Más allá del texto de la página, Fisherboy puede traer medios y datos de plataformas:

  • Archivos — descargas directas de archivos.
  • Video — mediante yt-dlp (YouTube, Vimeo y muchos otros). ffmpeg, incluido en la imagen, mezcla video + audio en mp4 de alta calidad; sin él, las descargas recurren al mejor archivo progresivo único.
  • Galerías / imágenes — mediante gallery-dl (Instagram, X, Reddit, Pinterest, Tumblr, Flickr, DeviantArt y más).
  • Comentarios / datos de plataformas — multiplataforma; los comentarios de publicaciones de Instagram y los datos de seguidores/seguidos usan instaloader, que necesita una cookie de sesión (IG_SESSIONID) y está restringido al rol dios.
POST /api/jobs # valida esquema, rol × modo de privacidad, callback y proxy (SSRF); encola → 202
GET /api/jobs/{job_id} # estado y resultado (el "envelope")
POST /api/proxy/test # enruta una petición a través de un proxy; devuelve IP de salida + país + latencia
POST /api/revert # re-hidrata contenido pseudonimizado (modo reversible)
POST /api/login # login de rol (sesión por cookie)
GET /healthz # liveness
GET /metrics # métricas Prometheus

Envía un trabajo y consúltalo:

Ventana de terminal
curl -X POST http://localhost:8000/api/jobs \
-H 'content-type: application/json' \
-d '{"url":"https://example.com/article","rol":"angel","privacy_mode":"opaco"}'
# → { "job_id": "…", "status": "pendiente" }
curl http://localhost:8000/api/jobs/<job_id>
# → el envelope con content_md anonimizado una vez que status == "ok"
CampoNotas
urlLa página a obtener.
rolhumano / angel / dios.
privacy_modeopaco / reversible / directo (acotado por rol).
output_formatmarkdown / llms_txt / json.
tier_hintNivel de partida sugerido, 03.
crawl_depthProfundidad para el crawl araña.
max_pagesPresupuesto de páginas (limitado por CRAWL_MAX_PAGES).
paginateBarre la paginación.
capture_apiCaptura el JSON XHR/fetch oculto.
tarantulaCaptura el contenido + API de cada nodo en un árbol de datos.
extract_schemaJSON Schema para extracción estructurada (con output_format=json).
proxyOverride de proxy por trabajo.
cookiesCookies de sesión para la petición.
callback_urlWebhook para recibir el envelope al completarse.

El mismo pipeline se expone como herramientas MCP (submit_job, get_job, revert) para que n8n, Claude Code o Escriba puedan encolar sin escribir HTTP a mano:

Ventana de terminal
python -m app.mcp_server # requiere fastmcp

El techo de rol del servidor MCP se configura con MCP_ROLE (no confía en un rol declarado por el llamador).

Pega un proxy en cualquier formatohost:port, host:port:user:pass, user:pass@host:port o una URL completa — y Fisherboy lo normaliza (socks5 soportado). El botón Test (o POST /api/proxy/test) enruta una petición a través de él y devuelve tu IP de salida + país + latencia, con una pista accionable si no puede conectarse. Configura un pool con PROXIES, elige la rotación con PROXY_ROTATION (round_robin / random / sticky), y ajusta PROXY_COOLDOWN_S y PROXY_ATTEMPTS. Un trabajo puede sobrescribir el pool con su propio proxy.

Usa páginas detrás de un login o una región sin una extensión de navegador. Pega cookies como Netscape cookies.txt, JSON o pares name=value, o léelas directamente desde tu navegador local (Chrome / Firefox / Edge / Brave). La lectura de cookies del navegador es solo standalone y está vetada en el modo sidekick.

La estrategia anti-CAPTCHA por defecto es la prevención por escalado (CAPTCHA_SOLVER=none): el gate de fetch detecta un CAPTCHA y sube un nivel. Opcionalmente, se puede configurar un solver de API externo con CAPTCHA_SOLVER=external, CAPTCHA_SOLVER_URL y CAPTCHA_SOLVER_KEY (acotado por rol).

Configura paginate en un trabajo para barrer listados de múltiples páginas. Fisherboy maneja esquemas comunes — postbacks de ASP.NET, enlaces “next” y patrones de query ?page=. El total está limitado por max_pages y el tope estricto CRAWL_MAX_PAGES.

Para los niveles 2 y 3, ajusta el navegador headless con BROWSER_HEADLESS, BROWSER_SETTLE_S (espera tras la carga), BROWSER_SCROLL (dispara el lazy-load), BROWSER_LOCALE y BROWSER_USER_AGENT.

  • Araña — sigue enlaces internos hacia un árbol (con acotación por sección) hasta crawl_depth, opcionalmente combinada con paginación.
  • Tarántula — el modo profundo: recorre cada nodo y captura tanto su contenido como su API oculta en un único árbol de datos. La tarántula está restringida a roles altos y vetada en el modo sidekick.

El crawling de múltiples páginas respeta robots.txt cuando RESPECT_ROBOTS=1.

Fisherboy es fail-closed y está endurecido: anti-SSRF (DNS resuelto; rangos privados/loopback/link-local/ metadata-de-nube bloqueados, re-validados en cada salto de redirección y cada petición del navegador, incluido el override de proxy), borrado de secretos por trabajo (credenciales de proxy, clave de captcha, cookies nunca aparecen en el envelope ni en el webhook), gating de roles en REST y MCP, limitación de tasa (MAX_JOBS_PER_MIN), topes estrictos de páginas y bytes (CRAWL_MAX_PAGES, JOB_MAX_TOTAL_BYTES), y un contenedor non-root. Revisa la checklist de producción antes de exponerlo — nunca configures ALLOW_PRIVATE_TARGETS=1 ni FISHERBOY_OPEN_GOD=1 en producción.

La persistencia con Postgres + pgvector es opcional (DATABASE_URL, más EMBEDDINGS_ENABLED para un almacén vectorial); sin ella el sistema funciona solo con Redis y se degrada con elegancia. Un stack de Prometheus + Loki + Grafana está disponible mediante docker-compose.observability.yml.