feat(browser): auto-commit con 6 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: cdp_set_file_input
|
||||
kind: function
|
||||
lang: py
|
||||
domain: browser
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def cdp_set_file_input(selector: str, file_paths, *, port: int = 9222, target_url_substr: str = '', timeout_s: float = 10.0) -> dict"
|
||||
description: "Asigna uno o varios archivos a un <input type=file> de una pestana de un Chrome con remote debugging, via CDP, SIN abrir el dialogo nativo del sistema operativo. Localiza el target por substring de URL, abre el WebSocket y ejecuta DOM.enable -> DOM.getDocument -> DOM.querySelector(selector) -> DOM.setFileInputFiles con las rutas ABSOLUTAS. Es el unico metodo robusto para subir archivos por CDP: el navegador no permite escribir el value de un file input desde JS (seguridad) y simular drag&drop es fragil; setFileInputFiles inyecta los File y dispara el evento change que la SPA escucha. Base de whatsapp_send_image y de cualquier flujo de subida de archivos sobre el navegador diario sin robar el foco al usuario."
|
||||
tags: [cdp, browser, automation, upload, file-input, python, navegator]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: ["json", "os", "urllib.request", "websocket"]
|
||||
params_schema:
|
||||
params:
|
||||
- name: selector
|
||||
desc: "Selector CSS del <input type=file> destino. Debe resolver a UN elemento (se usa el primer match). El input puede estar oculto (display:none); CDP lo localiza igual."
|
||||
- name: file_paths
|
||||
desc: "Ruta (str) o lista de rutas a asignar. Se expanden (~) y se convierten a rutas ABSOLUTAS; cada una debe existir en disco o se aborta con ok=False antes de tocar la red."
|
||||
- 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: timeout_s
|
||||
desc: "Timeout en segundos para la conexion WebSocket. Default 10.0."
|
||||
output: "dict {ok: bool, error: str, node_id: int (nodeId CDP del input localizado, 0 si no se encontro), selector: str (eco), files: list[str] (rutas absolutas asignadas)}. ok=True solo si el input se localizo y setFileInputFiles no devolvio error. Nunca lanza: errores de archivo/red/conexion/transport se devuelven en 'error' con ok=False."
|
||||
tested: true
|
||||
tests: ["test_golden_asigna_archivos_al_input", "test_edge_archivo_inexistente_ok_false_sin_red", "test_edge_selector_no_encontrado_ok_false", "test_error_create_connection_lanza_ok_false"]
|
||||
test_file_path: "python/functions/browser/cdp_set_file_input_test.py"
|
||||
file_path: "python/functions/browser/cdp_set_file_input.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from browser.cdp_set_file_input import cdp_set_file_input
|
||||
|
||||
# Requiere un Chrome lanzado con --remote-debugging-port=9222.
|
||||
# Adjuntar una imagen al input de subida de una pestana (WhatsApp Web, un formulario, etc).
|
||||
# El input "vivo" suele exponerse tras pulsar el boton "Adjuntar"/"Subir" (haz el click antes).
|
||||
res = cdp_set_file_input(
|
||||
'input[type="file"][multiple]',
|
||||
"/home/enmanuel/ComfyUI/output/item_icon_potion_00001_.png",
|
||||
target_url_substr="whatsapp",
|
||||
)
|
||||
print(res["ok"], res["node_id"], res["error"])
|
||||
# -> True 120
|
||||
```
|
||||
|
||||
O directo por CLI: `python3 python/functions/browser/cdp_set_file_input.py 'input[type="file"]' /ruta/abs.png whatsapp`.
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando necesites **subir/adjuntar un archivo** a una pestana abierta sin que aparezca el
|
||||
dialogo nativo de archivos del sistema operativo (que CDP no puede operar). Es la primitiva
|
||||
de subida sobre la que se construye `whatsapp_send_image_py_browser` y cualquier
|
||||
automatizacion de formularios con `<input type=file>`. El patron tipico: primero un click
|
||||
real (`cdp_click_xy_py_browser`) en el boton que expone el input vivo, luego esta funcion
|
||||
con el selector del input y la ruta absoluta del archivo.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **El input debe existir en el DOM al llamar.** Muchas SPAs (WhatsApp Web) solo crean/activan
|
||||
el `<input type=file>` "vivo" DESPUES de pulsar el boton de adjuntar. Haz el click real
|
||||
primero; si asignas sobre un input persistente/decoy, `setFileInputFiles` puede devolver ok
|
||||
pero la SPA no reacciona (no aparece el preview).
|
||||
- **Rutas ABSOLUTAS obligatorias.** `setFileInputFiles` exige rutas absolutas; la funcion ya
|
||||
convierte (`os.path.abspath` + expanduser), pero el archivo debe existir o aborta con ok=False
|
||||
antes de abrir la conexion.
|
||||
- **El selector debe resolver al input correcto.** Si hay varios `<input type=file>` (uno por
|
||||
tipo: fotos, documento...), afina el selector (`[multiple]`, `[accept*="image"]`). Si no
|
||||
matchea ninguno, devuelve `ok=False` con "no element matches selector".
|
||||
- **Dispara `change`, no `input`.** `DOM.setFileInputFiles` emite el evento `change` nativo
|
||||
(que la mayoria de uploads escuchan). Si una SPA solo escucha otro evento, no bastara.
|
||||
- Requiere un Chrome lanzado con `--remote-debugging-port=9222` (o el puerto que pases). Sin
|
||||
remote debugging, `GET /json` falla y devuelve `ok=False`.
|
||||
- Nunca lanza: errores de archivo/red/WS/transport se reportan en `error` con `ok=False`.
|
||||
Reference in New Issue
Block a user