--- 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: , 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`.