Files
Egutierrez ccfa5bc78b feat(browser): funciones anti-deteccion + perfiles para web_scraping
Funciones nuevas del dominio browser (grupo navegator):
- cdp_move_mouse_human / cdp_click_human: movimiento de raton con curva
  de Bezier cubica, easing y micro-jitter para imitar comportamiento
  humano y reducir deteccion de automatizacion.
- cdp_wait_idle: espera network-idle contando requests en vuelo via
  eventos CDP Network.*; inmune a extensiones que mutan el DOM
  (Dark Reader, uBlock) y a animaciones JS.
- list_chrome_profiles: lista perfiles de un user-data-dir (extensiones,
  nombre legible, preferencias).
- prepare_chrome_profile (bash): clona un user-data-dir conservando solo
  una whitelist de extensiones (default uBlock Origin Lite).

Modificadas:
- chrome_launch: Linux-first (chromium/google-chrome/brave antes que
  chrome.exe), KeepExtensions y Setpgid para matar el arbol con cdp_close.
- cdp_close: kill por grupo de proceso.

Todas con tests verdes (go test ./functions/browser ok).
2026-06-05 16:25:11 +02:00

4.6 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
cdp_wait_idle function go browser 1.1.0 impure func CdpWaitIdle(c *CDPConn, opts CdpWaitIdleOpts) error Espera a que la actividad de red de la pagina llegue a idle usando eventos CDP Network.*. Lleva un contador de requests en vuelo (inflight): +1 en requestWillBeSent, -1 en loadingFinished/loadingFailed. Cuando inflight <= MaxInflight de forma continuada durante QuietMs ms, retorna nil. Inmune a extensiones que mutan el DOM (Dark Reader, uBlock) y a animaciones JS. Si se alcanza Timeout sin lograr la ventana quieta, retorna error con el inflight actual.
cdp
chrome
browser
wait
spa
network
idle
polling
hydration
navegator
false error_go_core
fmt
sync
time
name desc
c conexion CDP activa (obtenida con CdpConnect)
name desc
opts opciones de espera: QuietMs ms de red quieta (default 500), Timeout maximo total (default 8s), MaxInflight requests en vuelo tolerados para considerar idle (default 0), PollMs intervalo de chequeo (default 100). Campos a 0 usan el default.
nil si la red llega a idle dentro del timeout; error descriptivo con inflight actual si se agota el tiempo o la conexion falla true
conexion nula retorna error inmediato
opts con ceros aplica defaults antes de usar
error de conexion nula contiene texto descriptivo
mensaje de error nil-conn menciona cdp wait idle
functions/browser/cdp_wait_idle_test.go functions/browser/cdp_wait_idle.go

Ejemplo

conn, _ := CdpConnect(9222)
CdpNavigate(conn, "https://my-spa.com/dashboard")

// Esperar readyState=complete primero.
_ = CdpWaitLoad(conn, 30*time.Second)

// Luego esperar a que la red quede idle (sin requests en vuelo).
if err := CdpWaitIdle(conn, CdpWaitIdleOpts{
    QuietMs:     500,             // 500 ms sin requests en vuelo
    Timeout:     8 * time.Second,
    MaxInflight: 0,               // 0 = idle absoluto; 1+ = tolera polling/WS
    PollMs:      100,
}); err != nil {
    log.Fatal("red no llego a idle:", err)
}

html, _ := CdpGetHTML(conn)

Cuando usarla

Cuando CdpWaitLoad no basta porque la SPA lanza fetch/XHR adicionales tras readyState=complete y necesitas esperar a que terminen antes de extraer HTML o hacer clicks. Usar justo despues de CdpWaitLoad o de CdpNavigate.

Preferir esta funcion sobre la version DOM-length anterior cuando la pagina tenga extensiones activas (Dark Reader, uBlock) o animaciones JS que mutan el DOM continuamente: esas fuentes de ruido no afectan el contador de red.

Implementacion: eventos CDP (no fallback JS)

La funcion suscribe Network.requestWillBeSent, Network.loadingFinished y Network.loadingFailed usando c.OnEvent, el mismo mecanismo que cdp_har_record. CDPConn soporta multiples consumidores por metodo (slice de handlers), por lo que esta funcion y cdp_har_record pueden usarse en paralelo sobre la misma conexion sin conflicto. El fallback JS (window.__fn_inflight via XHR/fetch hook) no fue necesario.

Gotchas

  • Paginas con polling persistente o WebSockets: si la pagina lanza un request periodico (ej. SSE, long-poll cada 30 s), inflight puede no llegar a 0 durante QuietMs. Solucionar con MaxInflight: 1 para tolerar ese request de fondo, o reducir QuietMs (ej. 200 ms) para capturar la ventana entre polls.
  • Timeout corto por defecto (8 s): es deliberado. Para paginas de polling persistente donde inflight nunca llega a 0, un timeout largo solo bloquea. Preferir MaxInflight > 0 o Timeout mas largo explicitamente.
  • Error incluye inflight actual: el mensaje de timeout incluye inflight=N para facilitar diagnostico (saber cuantos requests quedaron colgados).
  • Network.enable/disable: la funcion habilita el dominio Network al entrar y lo deshabilita al salir via defer. Si otra funcion en la misma conexion (ej. cdp_har_record) ya lo tiene habilitado, el disable al salir lo desactivara para todos. Usar MaxInflight y Timeout razonables y no interleave con cdp_har_record en la misma conexion salvo que el orden de cierre sea controlado.
  • Test e2e real: los tests del paquete no requieren Chrome. Para pruebas reales, lanzar Chrome con --remote-debugging-port=9222, navegar a la pagina objetivo y llamar esta funcion tras CdpWaitLoad.

Capability growth log

  • v1.1.0 (2026-06-05) — cambia señal DOM-length → network-idle via eventos CDP Network.*; añade MaxInflight configurable; defaults mas ajustados (QuietMs 800→500, Timeout 15s→8s, PollMs 200→100).