8742cb25be
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
3.6 KiB
Markdown
66 lines
3.6 KiB
Markdown
---
|
|
name: cdp_eval
|
|
kind: function
|
|
lang: py
|
|
domain: browser
|
|
version: "1.0.0"
|
|
purity: impure
|
|
signature: "def cdp_eval(expression: str, *, port: int = 9222, target_url_substr: str = '', await_promise: bool = False, timeout_s: float = 10.0) -> dict"
|
|
description: "Evalua una expresion JavaScript en una pestana de un Chrome con remote debugging, eligiendo el target por substring de su URL. Primitiva de transport CDP reutilizable para operar el navegador diario por codigo sin abrir ventana nueva."
|
|
tags: [cdp, browser, automation, python, navegator]
|
|
uses_functions: []
|
|
uses_types: []
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: "error_go_core"
|
|
imports: ["json", "urllib.request", "websocket"]
|
|
params_schema:
|
|
params:
|
|
- name: expression
|
|
desc: "Expresion JavaScript a evaluar en el contexto de la pagina (ej. 'document.title', 'document.querySelector(\".x\").click()')."
|
|
- name: port
|
|
desc: "Puerto de remote debugging de Chrome. Default 9222."
|
|
- name: target_url_substr
|
|
desc: "Substring que debe contener la URL del target (pestana). Si vacio, usa el primer target de tipo 'page'."
|
|
- name: await_promise
|
|
desc: "Si True, espera a que la expresion resuelva una Promise antes de devolver el valor (awaitPromise de CDP). Default False."
|
|
- name: timeout_s
|
|
desc: "Timeout en segundos para la conexion WebSocket. Default 10.0."
|
|
output: "dict {ok: bool, value: <valor Python serializable o None>, error: str, target_url: str}. ok=True si la evaluacion produjo valor sin excepcion. Nunca lanza: errores de red/conexion/excepcion JS se devuelven en 'error'."
|
|
tested: true
|
|
tests: ["test_golden_selecciona_target_por_substr_y_devuelve_value", "test_edge_substr_sin_match_devuelve_ok_false", "test_error_urlopen_lanza_devuelve_ok_false"]
|
|
test_file_path: "python/functions/browser/cdp_eval_test.py"
|
|
file_path: "python/functions/browser/cdp_eval.py"
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```python
|
|
import sys, os
|
|
sys.path.insert(0, os.path.join("python", "functions"))
|
|
from browser.cdp_eval import cdp_eval
|
|
|
|
# Requiere un Chrome lanzado con --remote-debugging-port=9222
|
|
# y una pestana de WhatsApp Web abierta.
|
|
res = cdp_eval("document.title", port=9222, target_url_substr="whatsapp")
|
|
print(res["value"]) # -> "WhatsApp" (o None si no hay target)
|
|
print(res["ok"], res["target_url"])
|
|
```
|
|
|
|
O directo por CLI: `python3 python/functions/browser/cdp_eval.py "document.title" "whatsapp"`.
|
|
|
|
## Cuando usarla
|
|
|
|
Cuando quieras leer datos o ejecutar JS (focus, querySelector, `element.click()`, scroll)
|
|
sobre una pestana **ya abierta** del navegador diario sin abrir ventana nueva ni darle
|
|
foco al sistema. Es la primitiva de transport sobre la que se construyen las funciones
|
|
`whatsapp_*_py_browser` y cualquier script que opere una pestana existente via CDP.
|
|
|
|
## Gotchas
|
|
|
|
- Requiere un Chrome lanzado con `--remote-debugging-port=9222` (o el puerto que pases). Sin remote debugging, `GET /json` falla y devuelve `ok=False`.
|
|
- `target_url_substr` hace match de **substring** sobre la URL del target (no regex). El primer `page` que contenga el substring gana.
|
|
- `returnByValue` solo serializa valores JSON (str, num, bool, list, dict, None). Los nodos del DOM NO son serializables: devuelve la expresion ya reducida a un valor (ej. `el.textContent`, no `el`).
|
|
- Para **escribir** en inputs o `contenteditable` NO uses `document.execCommand` ni `el.value = ...`: editores como React/Lexical (WhatsApp Web) ignoran esos cambios programaticos. Usa `cdp_type_chars_py_browser` (teclea caracter a caracter via CDP `Input.dispatchKeyEvent`).
|
|
- Nunca lanza: errores de red, conexion WS o excepciones de la propia evaluacion JS se reportan en el campo `error` con `ok=False`.
|