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).
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,6 +26,13 @@ type ChromeLaunchOpts struct {
|
||||
ChromePath string
|
||||
// ExtraArgs permite pasar flags adicionales a Chrome.
|
||||
ExtraArgs []string
|
||||
// KeepExtensions, si es true, NO añade --disable-extensions (mantiene las
|
||||
// extensiones del perfil cargadas). Por defecto false (comportamiento actual).
|
||||
KeepExtensions bool
|
||||
// ProfileDirectory selecciona el perfil dentro del user-data-dir (--profile-directory).
|
||||
// Vacío = no se pasa el flag (Chrome usa su default o muestra el selector si hay varios perfiles).
|
||||
// Ej: "Default", "Automation".
|
||||
ProfileDirectory string
|
||||
}
|
||||
|
||||
// reWindowsPath coincide con rutas absolutas de Windows (C:\... D:\... etc.).
|
||||
@@ -74,20 +82,43 @@ func defaultWindowsUserDataDir() (string, error) {
|
||||
return translateUserDataDirForWindows(linuxPath)
|
||||
}
|
||||
|
||||
// chromePaths lista los ejecutables de Chrome conocidos en WSL2/Linux.
|
||||
var chromePaths = []string{
|
||||
"chrome.exe",
|
||||
"google-chrome",
|
||||
"chromium-browser",
|
||||
// chromePathsLinux lista los binarios Linux-nativos de Chrome en orden de preferencia.
|
||||
var chromePathsLinux = []string{
|
||||
"chromium",
|
||||
"chromium-browser",
|
||||
"google-chrome",
|
||||
"google-chrome-stable",
|
||||
"brave-browser",
|
||||
}
|
||||
|
||||
// chromePathsWSL lista los ejecutables de Chrome para WSL2 (Windows .exe primero).
|
||||
var chromePathsWSL = []string{
|
||||
"chrome.exe",
|
||||
"/mnt/c/Program Files/Google/Chrome/Application/chrome.exe",
|
||||
"/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
||||
"/mnt/c/Users/Public/Desktop/chrome.exe",
|
||||
// binarios Linux como ultimo recurso en WSL
|
||||
"chromium",
|
||||
"chromium-browser",
|
||||
"google-chrome",
|
||||
"google-chrome-stable",
|
||||
}
|
||||
|
||||
// findChrome localiza el ejecutable de Chrome en el sistema.
|
||||
// En Linux nativo busca primero binarios Linux; en WSL2 busca primero chrome.exe.
|
||||
func findChrome() (string, error) {
|
||||
for _, p := range chromePaths {
|
||||
var paths []string
|
||||
if isWSL2() {
|
||||
paths = chromePathsWSL
|
||||
} else {
|
||||
// Linux nativo: primero binarios nativos, despues .exe como ultimo recurso
|
||||
paths = append(chromePathsLinux,
|
||||
"chrome.exe",
|
||||
"/mnt/c/Program Files/Google/Chrome/Application/chrome.exe",
|
||||
"/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
||||
)
|
||||
}
|
||||
for _, p := range paths {
|
||||
if path, err := exec.LookPath(p); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
@@ -95,7 +126,7 @@ func findChrome() (string, error) {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("chrome: ejecutable no encontrado en PATH ni en rutas conocidas de Windows")
|
||||
return "", fmt.Errorf("chrome: ejecutable no encontrado en PATH ni en rutas conocidas")
|
||||
}
|
||||
|
||||
// waitCDPReady espera hasta que el puerto CDP responda conexiones TCP.
|
||||
@@ -187,7 +218,6 @@ func ChromeLaunch(opts ChromeLaunchOpts) (int, error) {
|
||||
"--disable-background-networking",
|
||||
"--disable-client-side-phishing-detection",
|
||||
"--disable-default-apps",
|
||||
"--disable-extensions",
|
||||
"--disable-hang-monitor",
|
||||
"--disable-popup-blocking",
|
||||
"--disable-prompt-on-repost",
|
||||
@@ -197,6 +227,12 @@ func ChromeLaunch(opts ChromeLaunchOpts) (int, error) {
|
||||
"--safebrowsing-disable-auto-update",
|
||||
"--remote-allow-origins=*",
|
||||
}
|
||||
if !opts.KeepExtensions {
|
||||
args = append(args, "--disable-extensions")
|
||||
}
|
||||
if opts.ProfileDirectory != "" {
|
||||
args = append(args, fmt.Sprintf("--profile-directory=%s", opts.ProfileDirectory))
|
||||
}
|
||||
|
||||
if opts.Headless {
|
||||
args = append(args, "--headless=new", "--disable-gpu")
|
||||
@@ -222,6 +258,14 @@ func ChromeLaunch(opts ChromeLaunchOpts) (int, error) {
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
|
||||
// En Linux nativo (no WSL+Windows), crear un grupo de proceso propio para que
|
||||
// el proceso sobreviva al fin del padre y para poder matar el arbol completo
|
||||
// (chromium lanza zygote, gpu-process, renderers como hijos).
|
||||
// No aplicar en WSL+Windows: chrome.exe se gestiona de forma distinta.
|
||||
if !wsl2WindowsMode {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return 0, fmt.Errorf("chrome: arrancar proceso: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user