page.evaluate() es un método clave de Puppeteer que le permite ejecutar JavaScript directamente en el contexto del navegador. Conecta Node.js y el navegador, lo que permite realizar 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:
- Qué 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 principales:
- Extraer datos de sitios web (por ejemplo, texto, tablas o JSON).
- Automatizar envíos de formularios e interacciones de usuarios.
- Gestionar contenido dinámico, como desplazamiento infinito o actualizaciones AJAX.
- Limitaciones: Las funciones deben poder serializarse en JSON y las variables de Node.js no son accesibles directamente desde el contexto del navegador.
Ejemplo rápido:
const title = await page.evaluate(() => document.title);
Esto recupera el título de la página directamente desde el navegador.
Comparación: contexto de Node.js frente al del navegador
| Característica | Contexto de Node.js | Contexto del navegador |
|---|---|---|
| Objetos globales | process, require | window, document |
| Ubicación del script | Máquina local | Página web de destino |
| Acceso a API | API de Node.js | API web del navegador |
Use page.evaluate() para tareas de automatización precisas y eficientes, especialmente al trabajar con sitios web que dependen en gran medida de JavaScript.
NodeJS : Nodejs/Puppeteer - Cómo usar page.evaluate
Explicación del contexto de la página
Al trabajar con Puppeteer para la automatización web, es fundamental comprender la diferencia entre el contexto de Node.js y el contexto del navegador. Estos dos entornos están aislados y cada uno tiene sus propias reglas para ejecutar código e intercambiar datos.
Comparación entre los contextos de Node.js y del navegador
Puppeteer opera en dos entornos: el contexto de Node.js, donde se ejecuta su script principal, y el contexto del navegador, donde se producen las interacciones con la página web. Son procesos independientes, cada uno con su propia máquina virtual [3].
A continuación, se presenta una comparación rápida de sus principales características:
| Característica | Contexto de Node.js | Contexto del navegador |
|---|---|---|
| Objetos globales | process, require, __dirname | window, document, localStorage |
| Ubicación del script | Máquina local | Página web de destino |
| Ámbito de las variables | Ámbito del script de Puppeteer | Ámbito del contexto de la página |
| Acceso a API | API de Node.js | API web del navegador |
| Espacio de memoria | Proceso independiente | Proceso del navegador |
Cómo funciona la comunicación entre contextos
El intercambio de datos entre estos contextos implica una serie de pasos y depende en gran medida de la serialización:
- La función se convierte en una cadena mediante
Function.prototype.toString()[1]. - Esta cadena se envía al navegador a través del Chrome DevTools Protocol [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 de Node.js [1].
Limitaciones principales: Las 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 de Node.js [1].evaluateOnNewDocument(): Ejecuta código antes de que se cargue cualquier script de la página [1].
Sin embargo, la serialización JSON puede eliminar ciertas propiedades, especialmente en objetos complejos como los nodos DOM [2]. Para evitar problemas, pase los datos como argumentos de función en lugar de depender de variables de Node.js [3].
Dominar estas técnicas de comunicación le permite usar page.evaluate de forma eficaz para tareas de automatización. A continuación, veremos ejemplos prácticos para observar estos conceptos en acción.
Primeros pasos con page.evaluate
Estructura y parámetros del método
Sintaxis:
await page.evaluate(pageFunction, ...args)
| Parámetro | Tipo | Descripción |
|---|---|---|
| pageFunction | Función o cadena | Código JavaScript que se ejecutará en el contexto del navegador |
| args | Parámetros opcionales | Valores transferidos de Node.js al contexto del navegador |
| Valor de retorno | Promise | Se resuelve con el valor de retorno de la función |
La pageFunction puede ser una función o una cadena que contiene código JavaScript. Normalmente, usar una función es mejor para la depuración y la compatibilidad con TypeScript. A continuación se incluyen algunos ejemplos para mostrar cómo funciona.
Ejemplos básicos de código
Ejemplos:
- Extraer texto del primer
<h1>directamente del DOM:
const headingText = await page.evaluate(() => {
return document.querySelector('h1').textContent;
});
- Automatizar el envío de un formulario pasando parámetros:
await page.evaluate((username, password) => {
document.getElementById('username').value = username;
document.getElementById('password').value = password;
document.querySelector('#login-form').submit();
}, 'myUsername', 'myPassword');
- Manipular el DOM añadiendo un nuevo elemento:
await page.evaluate(() => {
const div = document.createElement('div');
div.textContent = 'Added by Puppeteer';
document.body.appendChild(div);
return div.textContent;
});
Notas clave para el desarrollo
- Las funciones se ejecutan de forma aislada de su código de Node.js.
- Los argumentos transferidos a la función deben ser serializables en JSON.
- Los valores devueltos se envuelven automáticamente en una Promise.
- La gestión de objetos complejos, como nodos DOM, requiere especial cuidado.
Consejo de depuración: Use la siguiente configuración para activar la depuración durante el desarrollo:
const browser = await puppeteer.launch({
headless: false,
slowMo: 100 // Adds a 100ms delay to each operation
});
A continuación, veremos técnicas para intercambiar datos entre los contextos de Node.js y del navegador.
Intercambio de datos entre contextos
Parámetros de entrada
Al transferir datos con page.evaluate, limite los argumentos de entrada a valores serializables en JSON.
A continuación se muestra un desglose rápido de los tipos de parámetros admitidos:
| Tipo de parámetro | ¿Compatible? | Ejemplo |
|---|---|---|
| Primitivos | ✓ Totalmente | 'text', 42, true |
| Matrices/objetos | ✓ Compatibles con JSON | { key: 'value' }, [1, 2, 3] |
| Funciones | ✗ No directamente | Use page.exposeFunction |
| Elementos DOM | ✓ Mediante JSHandle | Use page.evaluateHandle |
Ahora, veamos cómo se devuelven estos valores desde el contexto del navegador.
Gestión de la salida
Al usar page.evaluate, los valores devueltos se serializan automáticamente en JSON. Así es como funciona:
// Returning a simple value
const pageTitle = await page.evaluate(() => document.title);
// Returning a complex object
const metrics = await page.evaluate(() => ({
viewport: window.innerWidth,
scrollHeight: document.body.scrollHeight,
timestamp: Date.now()
}));
"Como regla general, si el valor de retorno de la función proporcionada es más complejo que un objeto JSON (por ejemplo, la mayoría de las clases), es probable que
evaluatedevuelva 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 a Puppeteer mediante un protocolo." [1]
Una vez recuperada la salida, puede encontrarse con desafíos relacionados con la serialización. A continuación se explica cómo resolverlos.
Gestión de problemas de serialización
Algunos casos habituales requieren soluciones específicas:
- Trabajar con elementos DOM
const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose(); // Always clean up to avoid memory leaks
- Usar funciones de Node.js
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex')
);
const hash = await page.evaluate(async () => {
return await window.md5('test-string');
});
- Ajustar la configuración del transpilador
Si trabaja con TypeScript, asegúrese de que su transpilador esté configurado correctamente:
// tsconfig.json
{
"compilerOptions": {
"target": "es2018"
}
}
Estas estrategias le ayudarán a gestionar eficazmente el intercambio de datos en distintos contextos.
sbb-itb-23997f1
Ejemplos prácticos
A continuación se muestra cómo puede usar page.evaluate en situaciones reales, con fragmentos de código prácticos.
Extracción de datos
Ejemplo: extracción de detalles de productos
Este script recopila datos como el título, el precio, la valoración y el estado de existencias a partir de las tarjetas de productos de una página web:
const productData = await page.evaluate(() => {
const products = Array.from(document.querySelectorAll('.product-card'));
return products.map(product => ({
title: product.querySelector('.title').textContent.trim(),
price: product.querySelector('.price').textContent.trim(),
rating: parseFloat(product.querySelector('.rating').dataset.value),
inStock: product.querySelector('.stock').textContent.includes('Available')
}));
});
Ejemplo: extracción de datos de tablas
Este enfoque recupera datos de una tabla recorriendo sus filas y columnas:
const tableData = await page.evaluate(() => {
const rows = Array.from(document.querySelectorAll('table tr'));
return rows.map(row => {
const columns = row.querySelectorAll('td');
return Array.from(columns, column => column.innerText);
});
});
Automatización de formularios
Automatización básica de formularios
A continuación se explica cómo completar campos de formulario, activar eventos y enviar el formulario:
await page.evaluate(() => {
// Fill form fields
document.querySelector('#username').value = 'testuser';
document.querySelector('#password').value = 'secretpass';
// Trigger input events for dynamic forms
const event = new Event('input', { bubbles: true });
document.querySelector('#username').dispatchEvent(event);
// Submit form
document.querySelector('form').submit();
});
Gestión de formularios complejos
Para tareas como seleccionar opciones de listas desplegables o marcar botones de opción:
await page.evaluate(() => {
// Select dropdown option
const select = document.querySelector('#country');
select.value = 'US';
select.dispatchEvent(new Event('change', { bubbles: true }));
// Check radio button
const radio = document.querySelector('input[value="express"]');
radio.checked = true;
radio.dispatchEvent(new Event('change', { bubbles: true }));
});
Gestión de elementos dinámicos
Ejemplo: desplazamiento infinito
Este script recorre una página hasta recopilar al menos 100 elementos:
const items = await page.evaluate(async () => {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const items = new Set();
while (items.size < 100) {
// Scroll to bottom
window.scrollTo(0, document.body.scrollHeight);
// Wait for new content
await delay(1000);
// Collect items
document.querySelectorAll('.item').forEach(item =>
items.add(item.textContent.trim())
);
}
return Array.from(items);
});
Ejemplo: gestión de contenido AJAX
Para cargar más contenido de forma dinámica, este script hace clic en un botón "Cargar más" y espera a que aparezcan nuevos elementos:
await page.evaluate(async () => {
// Click load more button
document.querySelector('#loadMore').click();
// Wait for content update
await new Promise(resolve => {
const observer = new MutationObserver((mutations, obs) => {
if (document.querySelectorAll('.item').length > 10) {
obs.disconnect();
resolve();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
});
Estos ejemplos muestran cómo gestionar diversos casos, como la extracción de datos, la automatización de formularios y el contenido dinámico. Puede realizar ajustes en función de la estructura y el comportamiento específicos de la página web con la que esté trabajando.
Uso de page.evaluate en Latenode
Latenode integra las funciones principales de Puppeteer en sus flujos de automatización, lo que facilita la ejecución de JavaScript directamente en el navegador. Con page.evaluate, los usuarios pueden manipular el DOM y extraer datos de forma eficiente. Este enfoque permite integrar sin fricciones una gestión avanzada de datos y operaciones DOM en el entorno de automatización de Latenode.
Scripts de navegador en Latenode
El módulo de automatización del navegador de Latenode utiliza page.evaluate para gestionar desde tareas sencillas del DOM hasta ejecuciones más complejas de JavaScript. Así funciona en distintos casos:
// Basic DOM interaction
await page.evaluate(() => {
const loginButton = document.querySelector('#login');
loginButton.click();
// Trigger a custom event
loginButton.dispatchEvent(new Event('customClick'));
});
// Processing data with exposed functions
await page.exposeFunction('processData', async (data) => {
// Process data in Node.js context
return transformedData;
});
await page.evaluate(async () => {
const rawData = document.querySelector('#data').textContent;
const processed = await window.processData(rawData);
return 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 preparado 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:
const extractProductData = await page.evaluate(async () => {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
// Wait for dynamic content to load
while (!document.querySelector('.product-grid')) {
await delay(100);
}
return Array.from(document.querySelectorAll('.product'))
.map(product => ({
name: product.querySelector('.name').textContent,
price: product.querySelector('.price').textContent,
availability: product.querySelector('.stock').dataset.status
}));
});
Para operaciones más avanzadas, page.exposeFunction permite una interacción fluida entre Node.js y el navegador:
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex')
);
const processedData = await page.evaluate(async () => {
const sensitiveData = document.querySelector('#secure-data').value;
return await window.md5(sensitiveData);
});
Para mantener referencias a elementos DOM entre pasos, Latenode utiliza page.evaluateHandle:
const elementHandle = await page.evaluateHandle(() => {
return document.querySelector('.dynamic-content');
});
await page.evaluate(element => {
element.scrollIntoView();
}, elementHandle);
Estas técnicas garantizan que Latenode pueda gestionar contenido dinámico de forma eficaz y mantener un rendimiento fiable. Para los usuarios del plan Prime, la plataforma admite hasta 1,5 millones de ejecuciones de flujos cada mes, lo que proporciona amplias capacidades de automatización.
Guía de resolución de errores
Al trabajar con page.evaluate en la automatización de navegadores, puede encontrar diversos problemas. A continuación se presentan soluciones prácticas para resolverlos 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:
// Use direct, non-transpiled functions
await page.evaluate(() => {
document.querySelector('#button').click();
});
await page.evaluate(`(async () => {
document.querySelector('#button').click();
})()`);
Evite devolver elementos DOM directamente desde page.evaluate. En su lugar, use ElementHandle para gestionarlos mejor:
// Incorrect: Returning a DOM element
const element = await page.evaluate(() => {
return document.querySelector('.dynamic-element');
});
// Correct: Using ElementHandle
const element = await page.evaluateHandle(() => {
return document.querySelector('.dynamic-element');
});
Resolución de problemas de temporización
Los scripts pueden ejecutarse antes de que la página se haya cargado por completo, lo que genera errores de temporización. Use estas estrategias para gestionar estos casos:
// Wait for navigation after an action
await Promise.all([
page.waitForNavigation(),
page.click('#submit-button')
]);
// Wait for a specific condition
await page.waitForFunction(() => {
const element = document.querySelector('.lazy-loaded');
return element && element.dataset.loaded === 'true';
}, { timeout: 5000 });
Para sitios web dinámicos, adopte mecanismos de espera más específicos:
// Wait for specific network requests
await page.waitForResponse(
response => response.url().includes('/api/data')
);
// Ensure elements are both present and visible
await page.waitForSelector('.dynamic-content', {
visible: true,
timeout: 3000
});
Gestión de referencias DOM
Para evitar fugas de memoria, gestione cuidadosamente las referencias DOM. A continuación se muestra cómo hacerlo:
// Use and dispose ElementHandles
const handle = await page.evaluateHandle(() => {
return document.querySelector('.temporary-element');
});
await handle.evaluate(element => {
// Perform operations
});
await handle.dispose(); // Dispose of handle after use
Al trabajar con varios elementos, transfiera datos de forma segura entre contextos:
// Extract data from the DOM
const selector = '.product-price';
const price = await page.evaluate((sel) => {
const element = document.querySelector(sel);
return element ? element.textContent.trim() : null;
}, selector);
Para los detectores de eventos, asegúrese de realizar una limpieza adecuada para evitar controladores persistentes:
await page.evaluate(() => {
const handler = () => console.log('clicked');
const button = document.querySelector('#button');
button.addEventListener('click', handler);
// Store cleanup references
window._cleanupHandlers = window._cleanupHandlers || [];
window._cleanupHandlers.push(() => {
button.removeEventListener('click', handler);
});
});
Directrices de implementación
Para obtener los mejores resultados con page.evaluate, debe centrarse en mejorar el rendimiento, reducir los cambios de contexto innecesarios y garantizar la seguridad. Así puede optimizar sus flujos de automatización del navegador.
Optimización del rendimiento
Ejecutar código de forma eficiente dentro del contexto de la página ahorra tiempo y recursos del sistema. A continuación se presentan algunas técnicas para acelerar sus scripts:
// Block unnecessary resources like images and stylesheets
await page.setRequestInterception(true);
page.on('request', request => {
if (['image', 'stylesheet'].includes(request.resourceType())) {
request.abort();
} else {
request.continue();
}
});
// Batch operations to reduce overhead
await page.evaluate(() => {
const results = [];
document.querySelectorAll('.product-item').forEach(item => {
results.push({
title: item.querySelector('.title').textContent,
price: item.querySelector('.price').textContent,
stock: item.querySelector('.stock').dataset.value
});
});
return results;
});
Elegir los selectores adecuados también desempeña un papel importante en el rendimiento:
| Tipo de selector | Velocidad | Ejemplo |
|---|---|---|
| ID | Más rápido | #main-content |
| Clase | Rápido | .product-item |
| Etiqueta | Moderado | div > span |
| XPath complejo | Más lento | //div[@class='wrapper']//span |
Gestión de cambios de contexto
Cambiar de contexto entre Node.js y el entorno del navegador puede ralentizar el proceso. A continuación se explica cómo reducirlo al mínimo:
// Example of inefficient context switching
for (const item of items) {
await page.evaluate((i) => {
document.querySelector(`#item-${i}`).click();
}, item);
}
// Better: Batch operations in a single context switch
await page.evaluate((itemsList) => {
itemsList.forEach(i => {
document.querySelector(`#item-${i}`).click();
});
}, items);
Si necesita procesar datos en Node.js y transferirlos de vuelta al navegador, exponga funciones en lugar de cambiar de contexto repetidamente:
await page.exposeFunction('processData', async (data) => {
// Process data in Node.js
return transformedData;
});
await page.evaluate(async () => {
const result = await window.processData(documentData);
// Use the processed data in the browser
});
Directrices de seguridad
Una vez optimizados el rendimiento y los cambios de contexto, céntrese en mantener la seguridad de sus scripts. Estas son algunas prácticas recomendadas:
// Always sanitize inputs before using them
const sanitizedInput = sanitizeHtml(userInput);
await page.evaluate((input) => {
document.querySelector('#search').value = input;
}, sanitizedInput);
// Use error handling for critical operations
try {
await page.evaluate(() => {
if (!window.__securityCheck) {
throw new Error('Security check failed');
}
// Continue with the operation
});
} catch (error) {
console.error('Security violation:', error);
}
Para los flujos de Latenode, tenga en cuenta estos consejos adicionales:
- Use
userDataDirpara almacenar recursos en caché y mejorar el rendimiento entre sesiones. - Cierre las páginas y las instancias del navegador que no utilice para ahorrar memoria.
- Gestione las capturas de pantalla con búferes en lugar de depender de operaciones del sistema de archivos.
- Implemente una gestión sólida de errores y comprobaciones de seguridad exhaustivas.
Resumen
Revisión de puntos clave
El método page.evaluate conecta los contextos de Node.js y del navegador enviando una función de JavaScript convertida en cadena para ejecutarse en el navegador. Esta función opera de forma independiente del entorno de Node.js, por lo que debe gestionar cuidadosamente la transferencia de datos.
A continuación se muestra un ejemplo habitual de extracción de datos:
const data = await page.evaluate(async () => {
const results = document.querySelectorAll('.data-item');
return Array.from(results, item => ({
id: item.dataset.id,
value: item.textContent.trim()
}));
});
Aspectos que debe tener en cuenta:
- Los argumentos deben poder serializarse en JSON.
- Los valores devueltos se deserializan automáticamente.
- Las API del navegador solo están disponibles dentro del contexto de
evaluate. - Las variables de Node.js no son accesibles desde el contexto del navegador.
Estos fundamentos sientan las bases para usar Puppeteer de forma eficaz. Las herramientas adicionales pueden optimizar aún más sus tareas de automatización.
Herramientas adicionales de Puppeteer
Puppeteer ofrece varias herramientas para ampliar las capacidades de page.evaluate:
| Herramienta | Propósito | Mejor caso de uso |
|---|---|---|
| page.evaluateHandle | Devuelve referencias a objetos | Interactuar directamente con elementos DOM |
| page.exposeFunction | Hace que las funciones de Node.js se puedan usar en el navegador | Gestionar lógica compleja del lado del servidor |
| page.evaluateOnNewDocument | Ejecuta scripts antes de que se cargue una página | Preparar el entorno del navegador con antelación |
Por ejemplo, exponer funciones de Node.js al navegador puede simplificar el procesamiento avanzado de datos en flujos como los de Latenode. Aunque page.evaluate funciona bien para gestionar tipos primitivos y objetos serializables en JSON, page.evaluateHandle es esencial para trabajar con objetos complejos del navegador que no se pueden serializar.


