171 lines
9.5 KiB
Markdown
171 lines
9.5 KiB
Markdown
# 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):
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
# 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>` |
|