Ejecución de JavaScript en el contexto de la página con page.evaluate en Puppeteer
Aprenda a utilizar eficazmente el método page.evaluate de Puppeteer para ejecutar JavaScript en el contexto del navegador para tareas de automatización web.

page.evaluate() es una clave Titiritero método que permite ejecutar JavaScript directamente en el contexto del navegador. Une Node.js y el navegador, lo que permite tareas como la manipulación del DOM, la extracción de datos y la automatización de páginas web dinámicas. Esto es lo que necesita saber:
- Que hace:Ejecuta JavaScript en el navegador, como si estuviera usando la consola del navegador.
- Cómo funciona:Convierte una función en una cadena, la envía al navegador, la ejecuta y devuelve el resultado.
- Usos clave:
- Extracción de datos de sitios web (por ejemplo, texto, tablas, JSON).
- Automatizar el envío de formularios y las interacciones de los usuarios.
- Manejo de contenido dinámico como desplazamiento infinito o actualizaciones AJAX.
- Limitaciones:Las funciones deben ser serializables en JSON y las variables Node.js no son directamente accesibles en el contexto del navegador.
Ejemplo rápido:
<span class="hljs-keyword">const</span> title = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> <span class="hljs-variable language_">document</span>.<span class="hljs-property">title</span>);
Esto recupera el título de la página directamente del navegador.
Comparación: Node.js vs. Contexto del navegador
| Característica | Contexto de Node.js | Contexto del navegador |
|---|---|---|
| Objetos globales | proceso, requerir | ventana, documento |
| Ubicación del script | Máquina local | Página web de destino |
| Acceso a la API | API de Node.js | API web del navegador |
Usa page.evaluate() para tareas de automatización precisas y eficientes, especialmente cuando se trabaja con sitios web que utilizan mucho JavaScript.
NodeJS: Nodejs/Titiritero - Cómo utilizar page.evaluate
Contexto de la página explicado
Al trabajar con Puppeteer para la automatización web, es fundamental comprender la distinción entre Contexto de Node.js y la contexto del navegadorEstos dos entornos están aislados, cada uno con sus propias reglas para ejecutar código e intercambiar datos.
Comparación de contextos de Node.js y del navegador
Puppeteer opera en dos entornos: el Contexto de Node.js, donde se ejecuta el script principal y el contexto del navegador, donde se producen las interacciones con la página web. Son procesos separados, cada uno con su propia máquina virtual. [ 3 ].
He aquí una rápida comparación de sus características clave:
| Característica | Contexto de Node.js | Contexto del navegador |
|---|---|---|
| Objetos globales | proceso, requerir, __dirname | ventana, documento, almacenamiento local |
| Ubicación del script | Máquina local | Página web de destino |
| Alcance variable | Alcance del script de Puppeteer | Ámbito del contexto de la página |
| Acceso a la API | API de Node.js | API web del navegador |
| Espacio de memoria | Proceso separado | Proceso del navegador |
Cómo funciona la comunicación contextual
El intercambio de datos entre estos contextos implica una serie de pasos que dependen en gran medida de la serialización:
- La función se convierte en una cadena usando
Function.prototype.toString()[ 1 ]. - Esta cadena se envía al navegador a través de Protocolo de Chrome DevTools [ 1 ].
- El navegador evalúa la función dentro de su entorno.
- Los resultados se serializan en JSON y se envían de vuelta al contexto Node.js [ 1 ].
Limitaciones claveLas funciones en el contexto del navegador no pueden acceder directamente a las variables del ámbito de Node.js. Puppeteer ofrece herramientas específicas para abordar estos desafíos:
page.evaluateHandle(): Devuelve referencias a objetos en el contexto del navegador [ 1 ].page.exposeFunction(): Permite que el navegador llame a funciones Node.js [ 1 ].evaluateOnNewDocument():Ejecuta el código antes de que se cargue cualquier script de página [ 1 ].
Sin embargo, la serialización JSON puede eliminar ciertas propiedades, especialmente con objetos complejos como los nodos DOM. [ 2 ]Para evitar problemas, pase los datos como argumentos de función en lugar de depender de las variables de Node.js. [ 3 ].
Dominar estas técnicas de comunicación garantiza que puedas utilizarlas page.evaluate Eficaz para tareas de automatización. A continuación, analizaremos ejemplos prácticos para ver estos conceptos en acción.
Introducción a page.evaluate
Estructura y parámetros del método
Sintaxis:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(pageFunction, ...args)
| Parámetro | Tipo | Descripción |
|---|---|---|
| Función de página | Función o cadena | Código JavaScript para ejecutar en el contexto del navegador |
| args | Parámetros opcionales | Valores pasados desde Node.js al contexto del navegador |
| Valor de retorno | Promesa | Se resuelve con el valor de retorno de la función. |
La Función de página Puede ser una función o una cadena que contiene código JavaScript. Usar una función suele ser mejor para la depuración y TypeScript Compatibilidad. A continuación se muestran algunos ejemplos para demostrar cómo funciona.
Ejemplos de código básico
Ejemplos:
- Extraer texto del primero
<h1>directamente desde el DOM:
<span class="hljs-keyword">const</span> headingText = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'h1'</span>).<span class="hljs-property">textContent</span>;
});
- Automatizar el envío de formularios pasando parámetros:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">(<span class="hljs-params">username, password</span>) =></span> {
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'username'</span>).<span class="hljs-property">value</span> = username;
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'password'</span>).<span class="hljs-property">value</span> = password;
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#login-form'</span>).<span class="hljs-title function_">submit</span>();
}, <span class="hljs-string">'myUsername'</span>, <span class="hljs-string">'myPassword'</span>);
- Manipule el DOM agregando un nuevo elemento:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> div = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">'div'</span>);
div.<span class="hljs-property">textContent</span> = <span class="hljs-string">'Added by Puppeteer'</span>;
<span class="hljs-variable language_">document</span>.<span class="hljs-property">body</span>.<span class="hljs-title function_">appendChild</span>(div);
<span class="hljs-keyword">return</span> div.<span class="hljs-property">textContent</span>;
});
Notas clave para el desarrollo
- Las funciones se ejecutan de forma aislada del código Node.js.
- Los argumentos pasados a la función deben ser JSON serializable.
- Los valores devueltos se envuelven automáticamente en un Promesa.
- El manejo de objetos complejos, como nodos DOM, requiere un cuidado especial.
Consejo de depuración: Utilice la siguiente configuración para habilitar la depuración durante el desarrollo:
<span class="hljs-keyword">const</span> browser = <span class="hljs-keyword">await</span> puppeteer.<span class="hljs-title function_">launch</span>({
<span class="hljs-attr">headless</span>: <span class="hljs-literal">false</span>,
<span class="hljs-attr">slowMo</span>: <span class="hljs-number">100</span> <span class="hljs-comment">// Adds a 100ms delay to each operation</span>
});
A continuación, profundizaremos en las técnicas para intercambiar datos entre Node.js y los contextos del navegador.
Intercambio de datos entre contextos
Parámetros de entrada
Al transferir datos con page.evaluate, utilice valores serializables en JSON para los argumentos de entrada.
A continuación se muestra un desglose rápido de los tipos de parámetros admitidos:
| Tipo de parámetro | ¿Soportado? | Ejemplo |
|---|---|---|
| Primitivas | ✓ Completamente | 'texto', 42, verdadero |
| Matrices/Objetos | ✓ Compatible con JSON | { clave: 'valor' }, [1, 2, 3] |
| Funciones | ✗ No directamente | Utilice page.exposeFunction |
| Elementos DOM | ✓ A través de JSHandle | Utilice page.evaluateHandle |
Ahora, veamos cómo se devuelven estos valores desde el contexto del navegador.
Manejo de salida
Cuando use page.evaluateLos valores devueltos se serializan automáticamente a JSON. Así funciona:
<span class="hljs-comment">// Returning a simple value</span>
<span class="hljs-keyword">const</span> pageTitle = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> <span class="hljs-variable language_">document</span>.<span class="hljs-property">title</span>);
<span class="hljs-comment">// Returning a complex object</span>
<span class="hljs-keyword">const</span> metrics = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> ({
<span class="hljs-attr">viewport</span>: <span class="hljs-variable language_">window</span>.<span class="hljs-property">innerWidth</span>,
<span class="hljs-attr">scrollHeight</span>: <span class="hljs-variable language_">document</span>.<span class="hljs-property">body</span>.<span class="hljs-property">scrollHeight</span>,
<span class="hljs-attr">timestamp</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>()
}));
"Como regla general, si el valor de retorno de la función dada es más complicado que un objeto JSON (por ejemplo, la mayoría de las clases), entonces
evaluateProbablemente devolverá algún valor truncado (o{}). Esto se debe a que no devolvemos el valor de retorno real, sino una versión deserializada como resultado de transferir el valor de retorno mediante un protocolo a Puppeteer. [ 1 ]
Una vez que haya recuperado la salida, podría encontrar problemas relacionados con la serialización. Aquí le mostramos cómo solucionarlos.
Manejo de problemas de serialización
Algunos escenarios comunes requieren soluciones alternativas específicas:
- Trabajar con elementos DOM
<span class="hljs-keyword">const</span> bodyHandle = <span class="hljs-keyword">await</span> page.$(<span class="hljs-string">'body'</span>);
<span class="hljs-keyword">const</span> html = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function"><span class="hljs-params">body</span> =></span> body.<span class="hljs-property">innerHTML</span>, bodyHandle);
<span class="hljs-keyword">await</span> bodyHandle.<span class="hljs-title function_">dispose</span>(); <span class="hljs-comment">// Always clean up to avoid memory leaks</span>
- Uso de funciones de Node.js
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">exposeFunction</span>(<span class="hljs-string">'md5'</span>, <span class="hljs-function"><span class="hljs-params">text</span> =></span>
crypto.<span class="hljs-title function_">createHash</span>(<span class="hljs-string">'md5'</span>).<span class="hljs-title function_">update</span>(text).<span class="hljs-title function_">digest</span>(<span class="hljs-string">'hex'</span>)
);
<span class="hljs-keyword">const</span> hash = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">md5</span>(<span class="hljs-string">'test-string'</span>);
});
- Ajuste de la configuración del transpilador
Si está trabajando con TypeScript, asegúrese de que su transpilador esté configurado correctamente:
<span class="hljs-comment">// tsconfig.json</span>
{
<span class="hljs-string">"compilerOptions"</span>: {
<span class="hljs-string">"target"</span>: <span class="hljs-string">"es2018"</span>
}
}
Estas estrategias le ayudarán a gestionar eficazmente el intercambio de datos en diversos contextos.
sbb-itb-23997f1
Ejemplos prácticos
Así es como puedes usar page.evaluate en escenarios del mundo real, completos con fragmentos de código prácticos.
Extrayendo datos
Ejemplo: Rastreo de detalles del producto
Este script recopila detalles como título, precio, calificación y estado de stock de las tarjetas de producto en una página web:
<span class="hljs-keyword">const</span> productData = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> products = <span class="hljs-title class_">Array</span>.<span class="hljs-title function_">from</span>(<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'.product-card'</span>));
<span class="hljs-keyword">return</span> products.<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">product</span> =></span> ({
<span class="hljs-attr">title</span>: product.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.title'</span>).<span class="hljs-property">textContent</span>.<span class="hljs-title function_">trim</span>(),
<span class="hljs-attr">price</span>: product.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.price'</span>).<span class="hljs-property">textContent</span>.<span class="hljs-title function_">trim</span>(),
<span class="hljs-attr">rating</span>: <span class="hljs-built_in">parseFloat</span>(product.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.rating'</span>).<span class="hljs-property">dataset</span>.<span class="hljs-property">value</span>),
<span class="hljs-attr">inStock</span>: product.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.stock'</span>).<span class="hljs-property">textContent</span>.<span class="hljs-title function_">includes</span>(<span class="hljs-string">'Available'</span>)
}));
});
Ejemplo: extracción de datos de una tabla
Este enfoque recupera datos de una tabla iterando a través de sus filas y columnas:
<span class="hljs-keyword">const</span> tableData = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> rows = <span class="hljs-title class_">Array</span>.<span class="hljs-title function_">from</span>(<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'table tr'</span>));
<span class="hljs-keyword">return</span> rows.<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">row</span> =></span> {
<span class="hljs-keyword">const</span> columns = row.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'td'</span>);
<span class="hljs-keyword">return</span> <span class="hljs-title class_">Array</span>.<span class="hljs-title function_">from</span>(columns, <span class="hljs-function"><span class="hljs-params">column</span> =></span> column.<span class="hljs-property">innerText</span>);
});
});
Automatización de formularios
Automatización básica de formularios
A continuación se explica cómo completar los campos del formulario, activar eventos y enviar el formulario:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-comment">// Fill form fields</span>
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#username'</span>).<span class="hljs-property">value</span> = <span class="hljs-string">'testuser'</span>;
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#password'</span>).<span class="hljs-property">value</span> = <span class="hljs-string">'secretpass'</span>;
<span class="hljs-comment">// Trigger input events for dynamic forms</span>
<span class="hljs-keyword">const</span> event = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Event</span>(<span class="hljs-string">'input'</span>, { <span class="hljs-attr">bubbles</span>: <span class="hljs-literal">true</span> });
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#username'</span>).<span class="hljs-title function_">dispatchEvent</span>(event);
<span class="hljs-comment">// Submit form</span>
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'form'</span>).<span class="hljs-title function_">submit</span>();
});
Manejo de formularios complejos
Para tareas como seleccionar opciones desplegables o marcar botones de opción:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-comment">// Select dropdown option</span>
<span class="hljs-keyword">const</span> select = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#country'</span>);
select.<span class="hljs-property">value</span> = <span class="hljs-string">'US'</span>;
select.<span class="hljs-title function_">dispatchEvent</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Event</span>(<span class="hljs-string">'change'</span>, { <span class="hljs-attr">bubbles</span>: <span class="hljs-literal">true</span> }));
<span class="hljs-comment">// Check radio button</span>
<span class="hljs-keyword">const</span> radio = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'input[value="express"]'</span>);
radio.<span class="hljs-property">checked</span> = <span class="hljs-literal">true</span>;
radio.<span class="hljs-title function_">dispatchEvent</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Event</span>(<span class="hljs-string">'change'</span>, { <span class="hljs-attr">bubbles</span>: <span class="hljs-literal">true</span> }));
});
Gestión de elementos dinámicos
Ejemplo: desplazamiento infinito
Este script se desplaza por una página hasta que recopila al menos 100 elementos:
<span class="hljs-keyword">const</span> items = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-keyword">const</span> <span class="hljs-title function_">delay</span> = ms => <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> <span class="hljs-built_in">setTimeout</span>(resolve, ms));
<span class="hljs-keyword">const</span> items = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Set</span>();
<span class="hljs-keyword">while</span> (items.<span class="hljs-property">size</span> < <span class="hljs-number">100</span>) {
<span class="hljs-comment">// Scroll to bottom</span>
<span class="hljs-variable language_">window</span>.<span class="hljs-title function_">scrollTo</span>(<span class="hljs-number">0</span>, <span class="hljs-variable language_">document</span>.<span class="hljs-property">body</span>.<span class="hljs-property">scrollHeight</span>);
<span class="hljs-comment">// Wait for new content</span>
<span class="hljs-keyword">await</span> <span class="hljs-title function_">delay</span>(<span class="hljs-number">1000</span>);
<span class="hljs-comment">// Collect items</span>
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'.item'</span>).<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">item</span> =></span>
items.<span class="hljs-title function_">add</span>(item.<span class="hljs-property">textContent</span>.<span class="hljs-title function_">trim</span>())
);
}
<span class="hljs-keyword">return</span> <span class="hljs-title class_">Array</span>.<span class="hljs-title function_">from</span>(items);
});
Ejemplo: Manejo de contenido AJAX
Para cargar más contenido dinámicamente, este script hace clic en el botón "Cargar más" y espera a que aparezcan nuevos elementos:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-comment">// Click load more button</span>
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#loadMore'</span>).<span class="hljs-title function_">click</span>();
<span class="hljs-comment">// Wait for content update</span>
<span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> {
<span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> <span class="hljs-title class_">MutationObserver</span>(<span class="hljs-function">(<span class="hljs-params">mutations, obs</span>) =></span> {
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'.item'</span>).<span class="hljs-property">length</span> > <span class="hljs-number">10</span>) {
obs.<span class="hljs-title function_">disconnect</span>();
<span class="hljs-title function_">resolve</span>();
}
});
observer.<span class="hljs-title function_">observe</span>(<span class="hljs-variable language_">document</span>.<span class="hljs-property">body</span>, {
<span class="hljs-attr">childList</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">subtree</span>: <span class="hljs-literal">true</span>
});
});
});
Estos ejemplos muestran cómo gestionar diversos escenarios, como el scraping, la automatización de formularios y el contenido dinámico. Se pueden realizar ajustes según la estructura y el comportamiento específicos de la página web con la que se trabaja.
Usando page.evaluate en Nodo tardío
Latenode incorpora las funciones principales de Puppeteer en sus flujos de trabajo de automatización, lo que facilita la ejecución de JavaScript directamente en el navegador. Con page.evaluateLos usuarios pueden manipular el DOM y extraer datos eficientemente. Este enfoque permite una integración fluida del manejo avanzado de datos y las operaciones del DOM en el entorno de automatización de Latenode.
Scripts del navegador en Latenode
El módulo de automatización del navegador de Latenode utiliza page.evaluate Para gestionar todo, desde tareas DOM sencillas hasta la ejecución más compleja de JavaScript. Así funciona en diferentes escenarios:
<span class="hljs-comment">// Basic DOM interaction</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> loginButton = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#login'</span>);
loginButton.<span class="hljs-title function_">click</span>();
<span class="hljs-comment">// Trigger a custom event</span>
loginButton.<span class="hljs-title function_">dispatchEvent</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Event</span>(<span class="hljs-string">'customClick'</span>));
});
<span class="hljs-comment">// Processing data with exposed functions</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">exposeFunction</span>(<span class="hljs-string">'processData'</span>, <span class="hljs-title function_">async</span> (data) => {
<span class="hljs-comment">// Process data in Node.js context</span>
<span class="hljs-keyword">return</span> transformedData;
});
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-keyword">const</span> rawData = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#data'</span>).<span class="hljs-property">textContent</span>;
<span class="hljs-keyword">const</span> processed = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">processData</span>(rawData);
<span class="hljs-keyword">return</span> processed;
});
Latenode también mantiene un registro del historial de ejecución, lo que facilita la depuración de scripts.
Ejemplos de automatización
Latenode está bien equipado para gestionar contenido dinámico y tareas de automatización complejas. A continuación, se muestra un ejemplo de procesamiento de contenido dinámico en una página:
<span class="hljs-keyword">const</span> extractProductData = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-keyword">const</span> <span class="hljs-title function_">delay</span> = ms => <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> <span class="hljs-built_in">setTimeout</span>(resolve, ms));
<span class="hljs-comment">// Wait for dynamic content to load</span>
<span class="hljs-keyword">while</span> (!<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.product-grid'</span>)) {
<span class="hljs-keyword">await</span> <span class="hljs-title function_">delay</span>(<span class="hljs-number">100</span>);
}
<span class="hljs-keyword">return</span> <span class="hljs-title class_">Array</span>.<span class="hljs-title function_">from</span>(<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'.product'</span>))
.<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">product</span> =></span> ({
<span class="hljs-attr">name</span>: product.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.name'</span>).<span class="hljs-property">textContent</span>,
<span class="hljs-attr">price</span>: product.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.price'</span>).<span class="hljs-property">textContent</span>,
<span class="hljs-attr">availability</span>: product.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.stock'</span>).<span class="hljs-property">dataset</span>.<span class="hljs-property">status</span>
}));
});
Para operaciones más avanzadas, page.exposeFunction permite una interacción fluida entre Node.js y el navegador:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">exposeFunction</span>(<span class="hljs-string">'md5'</span>, <span class="hljs-function"><span class="hljs-params">text</span> =></span>
crypto.<span class="hljs-title function_">createHash</span>(<span class="hljs-string">'md5'</span>).<span class="hljs-title function_">update</span>(text).<span class="hljs-title function_">digest</span>(<span class="hljs-string">'hex'</span>)
);
<span class="hljs-keyword">const</span> processedData = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-keyword">const</span> sensitiveData = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#secure-data'</span>).<span class="hljs-property">value</span>;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">md5</span>(sensitiveData);
});
Para mantener referencias a elementos DOM en todos los pasos, Latenode utiliza page.evaluateHandle:
<span class="hljs-keyword">const</span> elementHandle = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluateHandle</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.dynamic-content'</span>);
});
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function"><span class="hljs-params">element</span> =></span> {
element.<span class="hljs-title function_">scrollIntoView</span>();
}, elementHandle);
Estas técnicas garantizan que Latenode pueda gestionar contenido dinámico eficazmente y mantener un rendimiento fiable. Para los usuarios del plan Prime, la plataforma admite hasta 1.5 millones de ejecuciones de escenarios al mes, lo que proporciona amplias capacidades de automatización.
Guía de resolución de errores
Cuando se trabaja con page.evaluate En la automatización del navegador, podrías encontrarte con varios problemas. Aquí tienes soluciones prácticas para solucionarlos y garantizar una ejecución más fluida.
Corrección de errores de contexto
Configure correctamente sus ajustes de TypeScript para evitar problemas causados por la transpilación. Por ejemplo:
<span class="hljs-comment">// Use direct, non-transpiled functions</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#button'</span>).<span class="hljs-title function_">click</span>();
});
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-string">`(async () => {
document.querySelector('#button').click();
})()`</span>);
Evite devolver elementos DOM directamente desde page.evaluate. En su lugar, use ElementHandle Para un mejor manejo:
<span class="hljs-comment">// Incorrect: Returning a DOM element</span>
<span class="hljs-keyword">const</span> element = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.dynamic-element'</span>);
});
<span class="hljs-comment">// Correct: Using ElementHandle</span>
<span class="hljs-keyword">const</span> element = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluateHandle</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.dynamic-element'</span>);
});
Solución de problemas de sincronización
Los scripts pueden ejecutarse antes de que la página se cargue por completo, lo que provoca errores de sincronización. Utilice estas estrategias para gestionar estos casos:
<span class="hljs-comment">// Wait for navigation after an action</span>
<span class="hljs-keyword">await</span> <span class="hljs-title class_">Promise</span>.<span class="hljs-title function_">all</span>([
page.<span class="hljs-title function_">waitForNavigation</span>(),
page.<span class="hljs-title function_">click</span>(<span class="hljs-string">'#submit-button'</span>)
]);
<span class="hljs-comment">// Wait for a specific condition</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">waitForFunction</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> element = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.lazy-loaded'</span>);
<span class="hljs-keyword">return</span> element && element.<span class="hljs-property">dataset</span>.<span class="hljs-property">loaded</span> === <span class="hljs-string">'true'</span>;
}, { <span class="hljs-attr">timeout</span>: <span class="hljs-number">5000</span> });
Para sitios web dinámicos, adopte mecanismos de espera más específicos:
<span class="hljs-comment">// Wait for specific network requests</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">waitForResponse</span>(
<span class="hljs-function"><span class="hljs-params">response</span> =></span> response.<span class="hljs-title function_">url</span>().<span class="hljs-title function_">includes</span>(<span class="hljs-string">'/api/data'</span>)
);
<span class="hljs-comment">// Ensure elements are both present and visible</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">waitForSelector</span>(<span class="hljs-string">'.dynamic-content'</span>, {
<span class="hljs-attr">visible</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">timeout</span>: <span class="hljs-number">3000</span>
});
Gestión de referencias DOM
Para evitar fugas de memoria, gestione cuidadosamente las referencias DOM. A continuación, le explicamos cómo:
<span class="hljs-comment">// Use and dispose ElementHandles</span>
<span class="hljs-keyword">const</span> handle = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluateHandle</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.temporary-element'</span>);
});
<span class="hljs-keyword">await</span> handle.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function"><span class="hljs-params">element</span> =></span> {
<span class="hljs-comment">// Perform operations</span>
});
<span class="hljs-keyword">await</span> handle.<span class="hljs-title function_">dispose</span>(); <span class="hljs-comment">// Dispose of handle after use</span>
Al trabajar con múltiples elementos, pase datos de forma segura entre contextos:
<span class="hljs-comment">// Extract data from the DOM</span>
<span class="hljs-keyword">const</span> selector = <span class="hljs-string">'.product-price'</span>;
<span class="hljs-keyword">const</span> price = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">(<span class="hljs-params">sel</span>) =></span> {
<span class="hljs-keyword">const</span> element = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(sel);
<span class="hljs-keyword">return</span> element ? element.<span class="hljs-property">textContent</span>.<span class="hljs-title function_">trim</span>() : <span class="hljs-literal">null</span>;
}, selector);
Para los oyentes de eventos, asegúrese de una limpieza adecuada para evitar controladores persistentes:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> <span class="hljs-title function_">handler</span> = (<span class="hljs-params"></span>) => <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'clicked'</span>);
<span class="hljs-keyword">const</span> button = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#button'</span>);
button.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>, handler);
<span class="hljs-comment">// Store cleanup references</span>
<span class="hljs-variable language_">window</span>.<span class="hljs-property">_cleanupHandlers</span> = <span class="hljs-variable language_">window</span>.<span class="hljs-property">_cleanupHandlers</span> || [];
<span class="hljs-variable language_">window</span>.<span class="hljs-property">_cleanupHandlers</span>.<span class="hljs-title function_">push</span>(<span class="hljs-function">() =></span> {
button.<span class="hljs-title function_">removeEventListener</span>(<span class="hljs-string">'click'</span>, handler);
});
});
Pautas de implementación
Para obtener los mejores resultados con page.evaluateDebes centrarte en mejorar el rendimiento, reducir los cambios de contexto innecesarios y garantizar la seguridad. Aquí te explicamos cómo optimizar los flujos de trabajo de automatización de tu navegador.
Optimización de performance
Ejecutar código eficientemente dentro del contexto de la página ahorra tiempo y recursos del sistema. A continuación, se presentan algunas técnicas para agilizar sus scripts:
<span class="hljs-comment">// Block unnecessary resources like images and stylesheets</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">setRequestInterception</span>(<span class="hljs-literal">true</span>);
page.<span class="hljs-title function_">on</span>(<span class="hljs-string">'request'</span>, <span class="hljs-function"><span class="hljs-params">request</span> =></span> {
<span class="hljs-keyword">if</span> ([<span class="hljs-string">'image'</span>, <span class="hljs-string">'stylesheet'</span>].<span class="hljs-title function_">includes</span>(request.<span class="hljs-title function_">resourceType</span>())) {
request.<span class="hljs-title function_">abort</span>();
} <span class="hljs-keyword">else</span> {
request.<span class="hljs-title function_">continue</span>();
}
});
<span class="hljs-comment">// Batch operations to reduce overhead</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> results = [];
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'.product-item'</span>).<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">item</span> =></span> {
results.<span class="hljs-title function_">push</span>({
<span class="hljs-attr">title</span>: item.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.title'</span>).<span class="hljs-property">textContent</span>,
<span class="hljs-attr">price</span>: item.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.price'</span>).<span class="hljs-property">textContent</span>,
<span class="hljs-attr">stock</span>: item.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'.stock'</span>).<span class="hljs-property">dataset</span>.<span class="hljs-property">value</span>
});
});
<span class="hljs-keyword">return</span> results;
});
La elección de los selectores adecuados también juega un papel importante en el rendimiento:
| Tipo de selector | Speed (Rapidez) | Ejemplo |
|---|---|---|
| ID | Empresarial | #contenido principal |
| Clase | Rápido | .producto-artículo |
| Etiqueta | Moderada | div > lapso |
| XPath complejo | El más lento | //div[@class='wrapper']//lapso |
Gestión del cambio de contexto
El cambio de contexto entre Node.js y el entorno del navegador puede ralentizar el proceso. Aquí te explicamos cómo minimizarlo:
<span class="hljs-comment">// Example of inefficient context switching</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> item <span class="hljs-keyword">of</span> items) {
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">(<span class="hljs-params">i</span>) =></span> {
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">`#item-<span class="hljs-subst">${i}</span>`</span>).<span class="hljs-title function_">click</span>();
}, item);
}
<span class="hljs-comment">// Better: Batch operations in a single context switch</span>
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">(<span class="hljs-params">itemsList</span>) =></span> {
itemsList.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">i</span> =></span> {
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">`#item-<span class="hljs-subst">${i}</span>`</span>).<span class="hljs-title function_">click</span>();
});
}, items);
Si necesita procesar datos en Node.js y pasarlos de vuelta al navegador, exponga funciones en lugar de cambiar de contexto repetidamente:
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">exposeFunction</span>(<span class="hljs-string">'processData'</span>, <span class="hljs-title function_">async</span> (data) => {
<span class="hljs-comment">// Process data in Node.js</span>
<span class="hljs-keyword">return</span> transformedData;
});
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">processData</span>(documentData);
<span class="hljs-comment">// Use the processed data in the browser</span>
});
Directrices de seguridad
Una vez optimizado el rendimiento y el cambio de contexto, concéntrese en mantener la seguridad de sus scripts. Estas son algunas prácticas recomendadas:
<span class="hljs-comment">// Always sanitize inputs before using them</span>
<span class="hljs-keyword">const</span> sanitizedInput = <span class="hljs-title function_">sanitizeHtml</span>(userInput);
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">(<span class="hljs-params">input</span>) =></span> {
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#search'</span>).<span class="hljs-property">value</span> = input;
}, sanitizedInput);
<span class="hljs-comment">// Use error handling for critical operations</span>
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">if</span> (!<span class="hljs-variable language_">window</span>.<span class="hljs-property">__securityCheck</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">'Security check failed'</span>);
}
<span class="hljs-comment">// Continue with the operation</span>
});
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Security violation:'</span>, error);
}
Para los flujos de trabajo de Latenode, tenga en cuenta estos consejos adicionales:
- Usa
userDataDirpara almacenar en caché recursos y mejorar el rendimiento en todas las sesiones. - Cierre las páginas y las instancias del navegador no utilizadas para ahorrar memoria.
- Maneje capturas de pantalla con buffers en lugar de depender de operaciones del sistema de archivos.
- Implementar un manejo robusto de errores y controles de seguridad exhaustivos.
Resumen
Revisión de puntos clave
La page.evaluate El método conecta Node.js y los contextos del navegador mediante el envío de una función JavaScript convertida en cadena para su ejecución en el navegador. Esta función opera independientemente del entorno de Node.js, por lo que es necesario gestionar la transferencia de datos con cuidado.
He aquí un ejemplo común de extracción de datos:
<span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> page.<span class="hljs-title function_">evaluate</span>(<span class="hljs-title function_">async</span> () => {
<span class="hljs-keyword">const</span> results = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'.data-item'</span>);
<span class="hljs-keyword">return</span> <span class="hljs-title class_">Array</span>.<span class="hljs-title function_">from</span>(results, <span class="hljs-function"><span class="hljs-params">item</span> =></span> ({
<span class="hljs-attr">id</span>: item.<span class="hljs-property">dataset</span>.<span class="hljs-property">id</span>,
<span class="hljs-attr">value</span>: item.<span class="hljs-property">textContent</span>.<span class="hljs-title function_">trim</span>()
}));
});
Cosas para tener en cuenta:
- Los argumentos deben ser serializables en JSON.
- Los valores de retorno se deserializan automáticamente.
- Las API del navegador solo están disponibles dentro del
evaluatecontexto. - Las variables de Node.js no son accesibles en el contexto del navegador.
Estos conceptos básicos sientan las bases para usar Puppeteer eficazmente. Herramientas adicionales pueden optimizar aún más sus tareas de automatización.
Herramientas adicionales para titiritero
Puppeteer ofrece varias herramientas para ampliar las capacidades de page.evaluate:
| Proposito | Mejor caso de uso | |
|---|---|---|
| página.evaluateHandle | Devuelve referencias de objetos | Interactuar directamente con elementos DOM |
| página.exposeFunction | Hace que las funciones de Node.js sean utilizables en el navegador | Gestión de lógica compleja del lado del servidor |
| página.evaluarEnNuevoDocumento | Ejecuta scripts antes de que se cargue una página | Preparar el entorno del navegador con antelación |
Por ejemplo, exponer las funciones de Node.js al navegador puede simplificar el procesamiento avanzado de datos en flujos de trabajo como los de Latenode. Mientras que page.evaluate funciona bien para manejar tipos primitivos y objetos serializables en JSON, page.evaluateHandle es esencial para tratar con objetos de navegador complejos que no se pueden serializar.
Artículos relacionados con
- Operaciones de clic de Puppeteer: manejo de elementos complejos, clics dobles y solución de problemas
- Automatización de formularios con Puppeteer: entrada de texto, llenado de formularios y simulación de usuario
- Condiciones de espera personalizadas con waitForFunction en Puppeteer
- Automatización del navegador con Puppeteer y JavaScript: Implementación práctica en Node.js



