Files
web_scraping/CONVENTIONS.md
2026-06-05 17:27:18 +02:00

9.5 KiB

Convenciones del proyecto web_scraping

Reglas operativas para todo control de navegador y extracción web del proyecto. Aplican a la app script_navegador, a los scripts YAML y a cualquier función del dominio browser que se use desde aquí. Construido 100% sobre Linux nativo (sin WSL/Windows).

Nota: estas son convenciones (cómo se trabaja), no datos. Los datos extraídos (pliegos, RFPs, listados) van en vaults/ cuando empecemos a capturar.

1. Tamaño de ventana fijo

Todo navegador se lanza con un tamaño de ventana explícito y estable. Por defecto 1366x768 (resolución de portátil muy común → menos sospechosa que un viewport raro).

  • Motivo: reproducibilidad de selectores/screenshots y menor superficie de fingerprinting (un viewport común y consistente es menos señalable que uno aleatorio por sesión).
  • Implementación: script-navegador launch --width 1366 --height 768 (flags --window-size a Chrome). Nunca lanzar sin tamaño definido.

2. Carpeta de usuario dedicada del proyecto

Siempre se define un user-data-dir propio del proyecto, nunca el perfil real del usuario por defecto (evita locks y contaminación de la sesión personal).

  • Ruta por defecto: ~/.local/share/web_scraping/chrome-profile.
  • Implementación: script-navegador launch --profile <dir> (default ya apunta ahí).
  • El perfil es persistente entre ejecuciones (cookies, login, estado de extensiones).

3. Flujo headless: primero visible, luego headless

Se empieza desarrollando con ventana visible (headless=false) para ver lo que pasa y depurar selectores junto al humano. Solo cuando un flujo está estandarizado y probado se pasa a headless=true para correrlo desatendido/en lote.

  • Default de launch: headless=false.
  • Promoción a headless: pasar --headless una vez el script YAML del flujo es estable.

4. Esperas inteligentes + pequeños sleeps aleatorios

Nunca sleep ciegos fijos como mecanismo de sincronización. Se espera a condiciones reales:

  • readyState=complete (cdp_wait_load).
  • Red en reposo (cdp_wait_idle): nº de peticiones HTTP/WS en vuelo == 0 durante N ms (señal "network idle"). Es inmune a extensiones que mutan el DOM y a animaciones JS. Timeout corto (8s) porque páginas con polling/websockets persistentes pueden no llegar nunca a 0.
  • Selector presente (cdp_wait_element).

Sobre esas esperas se añaden micro-pausas aleatorias < 500 ms (jitter) entre acciones, para imitar el ritmo humano (anti-detección). El random es complemento, no sustituto, de la espera real.

Histórico: cdp_wait_idle usó al principio la longitud de innerHTML como señal de quietud, pero con extensiones como Dark Reader (que reinyecta estilos sin parar) el DOM nunca se estabilizaba y la espera agotaba siempre el timeout. Por eso se migró a network-idle.

5. Captura de datos vía extensión mitm (web_proxy)

El tráfico se puede capturar con la infraestructura web_proxy (mitmproxy + extensión de toggle ya presente en /etc/chromium.d/). Por eso los navegadores se lanzan con --keep-extensions (no --disable-extensions): la extensión de captura debe seguir cargada.

  • mitmweb corre en 127.0.0.1:8081; el proxy de captura en :8889.
  • Las capturas rotan a ~/captures (ver rotate_capture_flows.py).
  • El toggle del proxy es per-perfil; activarlo en el perfil del proyecto cuando se quiera capturar.

6. Movimientos de ratón + clics realistas

Las interacciones (click, drag) deben simular trayectorias humanas (curvas, aceleración, micro- desvíos), no saltos instantáneos a coordenadas. Stack decidido: Go puro — curvas Bézier sobre Input.dispatchMouseEvent como funciones del registry (cdp_move_mouse_human, cdp_click_human), sin dependencias externas. Integrado y por defecto (script_navegador v0.2.0): el comando click y la acción click del runner YAML usan Bézier sin pedir nada. Opt-out con --instant (CLI) o instant: true (paso YAML) cuando el elemento no tiene bounding box visible y conviene el click directo.

7. Proxys rotativos (Decodo) — futuro

Más adelante se integrarán proxys residenciales rotativos con Decodo (antes Smartproxy) para distribuir las peticiones y evitar bloqueos por IP. Pendiente de implementar (ver ## Pendientes).

8. CDP siempre activo en el navegador del usuario — futuro / decisión de seguridad

Objetivo: poder usar las capacidades de automatización sobre el chromium que el usuario usa a diario mientras navega, modificando el launcher (/etc/chromium.d/) para que todo chromium nazca con CDP activado.

APLICADO (2026-06-05): fragmento /etc/chromium.d/cdp con --remote-debugging-port=9222 --remote-allow-origins=*, sin --remote-debugging-address=0.0.0.0 → el puerto bindea solo en loopback (127.0.0.1), no accesible desde la red. Todo chromium que el usuario abra a partir de ahora nace con CDP. (El chromium ya abierto antes del cambio no tiene CDP hasta reiniciarlo.)

Reproducible entre PCs con la función del registry apply_chromium_cdp_flag_bash_browser (no editar el fragmento a mano):

fn run apply_chromium_cdp_flag                 # escribe /etc/chromium.d/cdp (loopback 9222, idempotente)
fn run apply_chromium_cdp_flag --dry-run       # previsualiza sin tocar nada
fn run apply_chromium_cdp_flag --remove        # desactiva CDP global
# --network añade --remote-debugging-address=0.0.0.0 (expone a la red: riesgo, ver Gotchas)

Coordinación de puertos: el chromium diario ocupa el 9222 global. Para sesiones de automatización con perfil dedicado, lanzar en OTRO puerto: script-navegador launch --port 9333. Dos procesos chromium no pueden compartir el mismo --remote-debugging-port.

⚠️ Implicación de seguridad: con CDP abierto, cualquier proceso local del usuario puede controlar el navegador y leer cookies/sesiones autenticadas. El bind solo-local evita acceso desde la red, pero NO protege de procesos locales. Aceptado conscientemente para este equipo de un solo usuario. No replicar en máquinas compartidas/multiusuario.

9. Perfiles nuevos: solo uBlock Origin Lite

Al preparar un perfil de usuario nuevo para automatización (clonando del perfil real del usuario), se conserva únicamente uBlock Origin Lite (ddkjiahejlhfcafbddmgiahcphecmpfh) y se eliminan el resto de extensiones del usuario.

  • Motivo: uBlock reduce ruido (anuncios, trackers) → páginas más limpias y rápidas de scrapear. Las demás estorban la automatización:
    • Dark Reader: reinyecta estilos sin parar → rompe esperas por DOM y oscurece screenshots.
    • NoScript: bloquea JavaScript → rompe SPAs y scraping de contenido dinámico.
    • OneTab: interfiere con la gestión de pestañas.
  • La extensión de captura web_proxy es aparte: se carga globalmente vía /etc/chromium.d/ (no es una extensión del perfil), por lo que esta regla no la toca. uBlock + web_proxy conviven.

Dos mecanismos (sistema + clonado)

  1. Política de sistema (primario)/etc/chromium/policies/managed/extensions.json con ExtensionInstallForcelist fuerza la instalación de extensiones en cualquier perfil de chromium del equipo. Reducido el 2026-06-05 a solo uBlock Origin Lite (ddkjiahejlhfcafbddmgiahcphecmpfh). Antes forzaba 4 (uBlock + Dark Reader + NoScript + OneTab). Esto garantiza que todo perfil nuevo —lo cree quien lo cree— nazca solo con uBlock, sin pasos extra. Backup del original en extensions.json.bak.20260605.

    • ⚠️ Afecta también el perfil diario del usuario: al reiniciar chromium, las extensiones que ya no están en la forcelist se desinstalan.

    • Editar requiere sudo (pass claude/sudo).

    • Reproducible entre PCs con la función del registry apply_chromium_extension_policy_bash_browser (no editar el JSON a mano): escribe la forcelist de forma idempotente con backup automático.

      # Forzar solo uBlock Origin Lite en todos los perfiles
      fn run apply_chromium_extension_policy --keep ddkjiahejlhfcafbddmgiahcphecmpfh
      fn run apply_chromium_extension_policy --keep ddkjiahejlhfcafbddmgiahcphecmpfh --dry-run
      
  2. Clonado con filtro (secundario)prepare_chrome_profile --src ~/.config/chromium --dst <perfil_proyecto> clona un perfil existente (cookies, sesiones) conservando solo la whitelist de extensiones (--keep <id>, default uBlock). Útil cuando se quiere arrancar de una copia del perfil real; la base de extensiones ya la garantiza la política de sistema.


Pendientes (decisiones abiertas)

# Tema Estado
7 Proxys rotativos con Decodo Futuro, sin empezar

Estado de implementación

Regla Estado Dónde
1. Tamaño de ventana fijo script-navegador launch --width/--height (default 1366x768)
2. Carpeta de usuario del proyecto --profile (default ~/.local/share/web_scraping/chrome-profile)
3. Flujo headless visible→true convención launch default headless=false
4. Esperas inteligentes + jitter cdp_wait_load+cdp_wait_idle (network-idle)+jitter()
5. Captura mitm infra --keep-extensions + web_proxy
6. Ratón/clics realistas cdp_move_mouse_human + cdp_click_human; default en script-navegador click y runner YAML (opt-out --instant / instant: true)
7. Proxys rotativos Decodo futuro
8. CDP global en chromium usuario /etc/chromium.d/cdp aplicado (loopback 9222)
9. Perfiles nuevos solo uBlock prepare_chrome_profile --src ~/.config/chromium --dst <perfil>