Files
navegator/cmd/buscar.go
T
Developer 7d5339acad refactor: eliminar time.Sleep innecesarios
Reemplaza todos los time.Sleep arbitrarios por esperas basadas en eventos CDP.

Cambios:
- examples/basic.go: usa WaitUntil en Navigate
- cmd/navegar.go: elimina sleeps después de acciones
- cmd/buscar.go y buscar_v2.go: usa networkidle
- cmd/list_blog.go: elimina sleep innecesario
- main.go: usa WaitUntil load

Mejora performance y robustez al no esperar más de lo necesario.

Archivos: examples/basic.go, cmd/*.go, main.go
2026-03-25 00:48:54 +01:00

151 lines
3.9 KiB
Go

package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"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")
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()
// Configurar navegador
currentDir, _ := os.Getwd()
profilesDir := filepath.Join(currentDir, "perfiles")
config := browser.DefaultConfig()
config.ProfilesBaseDir = profilesDir
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)
// 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 (más amigable para bots que Google)
searchURL := fmt.Sprintf("https://duckduckgo.com/?q=%s", *query)
log.Println("🌐 Navegando a DuckDuckGo...")
navOpts := browser.DefaultNavigateOptions()
navOpts.WaitUntil = "networkidle"
if err := b.Navigate(ctx, searchURL, navOpts); err != nil {
log.Fatalf("❌ Error al navegar: %v", err)
}
log.Println("📥 Extrayendo resultados...")
// Script para extraer resultados
extractScript := fmt.Sprintf(`
(() => {
const results = [];
const maxResults = %d;
// DuckDuckGo usa article con data-testid="result"
const items = document.querySelectorAll('article[data-testid="result"]');
for (let i = 0; i < Math.min(items.length, maxResults); i++) {
const item = items[i];
// Título
const titleEl = item.querySelector('h2 a');
const titulo = titleEl ? titleEl.textContent : '';
const url = titleEl ? titleEl.href : '';
// Descripción
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!")
}