763e06c127
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
62 lines
3.7 KiB
Markdown
62 lines
3.7 KiB
Markdown
---
|
|
name: detect_captcha
|
|
kind: function
|
|
lang: go
|
|
domain: browser
|
|
version: "1.0.0"
|
|
purity: impure
|
|
signature: "func DetectCaptcha(c *CDPConn) (detected bool, types []string, url string, err error)"
|
|
description: "Detecta captchas y challenges anti-bot en la pagina actual via CDP: reCAPTCHA, hCaptcha, Cloudflare Turnstile (por iframe/widget) y el JS-challenge de Cloudflare (por texto). Solo detecta — no resuelve ni notifica. Una responsabilidad."
|
|
tags: [captcha, browser, cdp, antibot, detection, perception]
|
|
uses_functions: [cdp_evaluate_go_browser]
|
|
uses_types: []
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: "error_go_core"
|
|
imports: [encoding/json, fmt]
|
|
params:
|
|
- name: c
|
|
desc: "Conexion CDP activa a una tab de Chrome de tipo 'page'. La evaluacion corre en el top frame."
|
|
output: "Tupla (detected, types, url, err). detected=true si hay al menos una senal anti-bot. types es el subconjunto de senales detectadas (de: 'recaptcha', 'hcaptcha', 'turnstile', 'challenge'), siempre slice no nulo (vacio si nada). url es la location.href del top frame. err si la conexion es nula, falla el eval CDP, o el JSON resultante es invalido. Una excepcion JS en la pagina se trata como detected=false best-effort, sin error."
|
|
tested: true
|
|
tests: ["recaptcha detectado", "hcaptcha detectado", "turnstile detectado", "challenge por texto", "multiples senales", "ninguno", "campo error best-effort no rompe", "types ausente se normaliza a slice vacio", "json invalido devuelve error"]
|
|
test_file_path: "functions/browser/detect_captcha_test.go"
|
|
file_path: "functions/browser/detect_captcha.go"
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```go
|
|
// Conectar a un Chrome con CDP abierto (mismo patron que cdp_get_text)
|
|
conn, err := CdpConnect(9222)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer CdpDisconnect(conn)
|
|
|
|
// Tras navegar y esperar la carga, comprobar si la pagina puso un captcha
|
|
detected, types, url, err := DetectCaptcha(conn)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if detected {
|
|
fmt.Printf("captcha detectado en %s: %v\n", url, types)
|
|
// p.ej. -> "captcha detectado en https://x.test/login: [recaptcha]"
|
|
} else {
|
|
fmt.Println("sin captcha, seguir clicando")
|
|
}
|
|
```
|
|
|
|
## Cuando usarla
|
|
|
|
Tras navegar o esperar la carga de una pagina, para saber si esta puso un captcha o challenge anti-bot antes de seguir clicando o enviando formularios. La usa el `browser_mcp` en sus handlers de navegacion para decidir el handoff humano: si `DetectCaptcha` devuelve `detected=true`, el flujo automatico se detiene y avisa para resolucion manual en vez de chocar contra el muro.
|
|
|
|
## Gotchas
|
|
|
|
- **Solo top frame**: la evaluacion corre en el frame principal. Un captcha incrustado en un iframe anidado profundo cuyo `src` no matchee los patrones no se detecta.
|
|
- **Iframes cross-origin**: el contenido de los iframes de reCAPTCHA/hCaptcha/Turnstile NO se lee (politica same-origin), pero SI se detectan por su `src` y por las clases del widget host (`.g-recaptcha`, `.h-captcha`, `.cf-turnstile`), que viven en el top document.
|
|
- **Falsos positivos posibles**: la senal `challenge` viene de regex sobre `innerText` (p.ej. "verify you are human", "unusual traffic"). Una pagina con ese texto en otro contexto (un articulo, una FAQ sobre bots) puede dar `detected=true` sin haber captcha real.
|
|
- **No detecta captchas custom**: solo cubre los proveedores listados (reCAPTCHA, hCaptcha, Turnstile) + el JS-challenge de Cloudflare. Captchas propios o de otros vendors no se reconocen.
|
|
- **Depende de innerText**: la pagina debe haber pintado el body. En una tab aun cargando (`document.body` nulo o vacio) la senal `challenge` puede no dispararse — esperar con `cdp_wait_load` antes de detectar si el contenido es dinamico.
|
|
- **Impura**: hace un round-trip CDP (I/O de red). Requiere conexion activa a una tab de tipo `page`.
|