package main import ( "context" "encoding/json" "flag" "fmt" "log" "os" "path/filepath" "time" "navegator/pkg/browser" ) // Resultado representa un resultado de búsqueda type Resultado struct { Titulo string `json:"titulo"` URL string `json:"url"` Descripcion string `json:"descripcion"` } func main() { // Definir flags/parámetros query := flag.String("q", "", "Consulta de búsqueda (requerido)") maxResults := flag.Int("n", 10, "Número máximo de resultados (default: 10)") headless := flag.Bool("headless", true, "Modo headless (default: true)") outputJSON := flag.String("output", "", "Guardar resultados en archivo JSON") profileName := flag.String("profile", "search-bot", "Nombre del perfil a usar") // NUEVO: Directorio de perfiles compartido profilesDir := flag.String("profiles-dir", "", "Directorio de perfiles (default: ~/.navegator/profiles)") flag.Parse() // Validar que se proporcionó la consulta if *query == "" { fmt.Println("Error: debes proporcionar una consulta con -q") fmt.Println("\nEjemplo:") fmt.Println(" ./buscar -q \"golang tutorial\" -n 20") fmt.Println("\nOpciones:") flag.PrintDefaults() os.Exit(1) } ctx := context.Background() // Determinar directorio de perfiles var perfilesPath string if *profilesDir != "" { perfilesPath = *profilesDir } else { // Default: ~/.navegator/profiles homeDir, err := os.UserHomeDir() if err != nil { log.Fatalf("❌ Error al obtener home dir: %v", err) } perfilesPath = filepath.Join(homeDir, ".navegator", "profiles") } // Crear directorio si no existe if err := os.MkdirAll(perfilesPath, 0755); err != nil { log.Fatalf("❌ Error al crear directorio de perfiles: %v", err) } config := browser.DefaultConfig() config.ProfilesBaseDir = perfilesPath config.ProfileName = *profileName config.StealthFlags.Headless = *headless config.StealthFlags.WindowSize = [2]int{1280, 720} log.Printf("🔍 Buscando: %s", *query) log.Printf("📊 Máximo de resultados: %d", *maxResults) log.Printf("👤 Usando perfil: %s", *profileName) log.Printf("📂 Perfiles en: %s", perfilesPath) // Lanzar navegador b, err := browser.Launch(ctx, config) if err != nil { log.Fatalf("❌ Error al lanzar navegador: %v", err) } defer b.Close() // Navegar a DuckDuckGo searchURL := fmt.Sprintf("https://duckduckgo.com/?q=%s", *query) log.Println("🌐 Navegando a DuckDuckGo...") if err := b.Navigate(ctx, searchURL, nil); err != nil { log.Fatalf("❌ Error al navegar: %v", err) } // Esperar a que carguen los resultados time.Sleep(3 * time.Second) log.Println("📥 Extrayendo resultados...") // Script para extraer resultados extractScript := fmt.Sprintf(` (() => { const results = []; const maxResults = %d; const items = document.querySelectorAll('article[data-testid="result"]'); for (let i = 0; i < Math.min(items.length, maxResults); i++) { const item = items[i]; const titleEl = item.querySelector('h2 a'); const titulo = titleEl ? titleEl.textContent : ''; const url = titleEl ? titleEl.href : ''; const descEl = item.querySelector('[data-result="snippet"]'); const descripcion = descEl ? descEl.textContent : ''; if (titulo && url) { results.push({ titulo: titulo.trim(), url: url, descripcion: descripcion.trim() }); } } return results; })() `, *maxResults) result, err := b.Evaluate(ctx, extractScript) if err != nil { log.Fatalf("❌ Error al extraer resultados: %v", err) } // Parsear resultados resultadosJSON, err := json.Marshal(result.Value) if err != nil { log.Fatalf("❌ Error al parsear resultados: %v", err) } var resultados []Resultado if err := json.Unmarshal(resultadosJSON, &resultados); err != nil { log.Fatalf("❌ Error al deserializar: %v", err) } // Mostrar resultados log.Printf("\n✅ Encontrados %d resultados:\n", len(resultados)) for i, r := range resultados { fmt.Printf("\n%d. %s\n", i+1, r.Titulo) fmt.Printf(" 🔗 %s\n", r.URL) if r.Descripcion != "" { fmt.Printf(" 📝 %s\n", r.Descripcion) } } // Guardar en JSON si se especificó if *outputJSON != "" { data, _ := json.MarshalIndent(resultados, "", " ") if err := os.WriteFile(*outputJSON, data, 0644); err != nil { log.Printf("⚠️ Error al guardar JSON: %v", err) } else { log.Printf("\n💾 Resultados guardados en: %s", *outputJSON) } } log.Println("\n✨ Búsqueda completada!") }