Initial commit: navegator - Chrome CDP automation for LLMs
Add complete navegator system for stealthy browser automation: - CDP client with WebSocket communication - Browser API with navigation, storage, network, runtime - Stealth flags and anti-detection scripts - Persistent profile support - Examples and comprehensive documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package browser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Action representa una acción realizada en el navegador.
|
||||
type Action struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Type string `json:"type"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Result interface{} `json:"result,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Recorder registra todas las acciones del navegador.
|
||||
type Recorder struct {
|
||||
file *os.File
|
||||
encoder *json.Encoder
|
||||
mu sync.Mutex
|
||||
enabled bool
|
||||
}
|
||||
|
||||
// NewRecorder crea un nuevo recorder que escribe en un archivo.
|
||||
func NewRecorder(filepath string) (*Recorder, error) {
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create recorder file: %w", err)
|
||||
}
|
||||
|
||||
r := &Recorder{
|
||||
file: file,
|
||||
encoder: json.NewEncoder(file),
|
||||
enabled: true,
|
||||
}
|
||||
|
||||
// Escribir header
|
||||
fmt.Fprintf(file, "# Navegator Recording - %s\n", time.Now().Format(time.RFC3339))
|
||||
fmt.Fprintf(file, "# Este archivo puede ser usado para reproducir las acciones\n\n")
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Record registra una acción.
|
||||
func (r *Recorder) Record(actionType string, params map[string]interface{}, result interface{}, err error) {
|
||||
if !r.enabled {
|
||||
return
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
action := Action{
|
||||
Timestamp: time.Now(),
|
||||
Type: actionType,
|
||||
Params: params,
|
||||
Result: result,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
action.Error = err.Error()
|
||||
}
|
||||
|
||||
// Escribir JSON
|
||||
r.encoder.Encode(action)
|
||||
|
||||
// También escribir comentario legible
|
||||
if params["url"] != nil {
|
||||
fmt.Fprintf(r.file, "# %s - %s: %v\n", action.Timestamp.Format("15:04:05"), actionType, params["url"])
|
||||
} else if params["selector"] != nil {
|
||||
fmt.Fprintf(r.file, "# %s - %s: %v\n", action.Timestamp.Format("15:04:05"), actionType, params["selector"])
|
||||
} else {
|
||||
fmt.Fprintf(r.file, "# %s - %s\n", action.Timestamp.Format("15:04:05"), actionType)
|
||||
}
|
||||
}
|
||||
|
||||
// Close cierra el recorder.
|
||||
func (r *Recorder) Close() error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.file != nil {
|
||||
fmt.Fprintf(r.file, "\n# Recording ended at %s\n", time.Now().Format(time.RFC3339))
|
||||
return r.file.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Enable activa el recording.
|
||||
func (r *Recorder) Enable() {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.enabled = true
|
||||
}
|
||||
|
||||
// Disable desactiva el recording.
|
||||
func (r *Recorder) Disable() {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.enabled = false
|
||||
}
|
||||
|
||||
// AddComment agrega un comentario al log.
|
||||
func (r *Recorder) AddComment(comment string) {
|
||||
if !r.enabled {
|
||||
return
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
fmt.Fprintf(r.file, "\n# %s\n", comment)
|
||||
}
|
||||
Reference in New Issue
Block a user