Una plataforma de código bajo que combina la simplicidad sin código con el poder del código completo 🚀
Empieza ahora gratis
Ejecución de JavaScript en el contexto de la página con page.evaluate en Puppeteer
Marzo 21, 2025
12
min leer

Ejecución de JavaScript en el contexto de la página con page.evaluate en Puppeteer

George Miloradovich
Investigador, redactor y entrevistador de casos prácticos
Tabla de contenidos.

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.
  • Como 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:

const title = await page.evaluate(() => document.title);

Esto recupera el título de la página directamente del navegador.

Comparación: Node.js vs. Contexto del navegador

Node.js

Feature 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 la API API de Node.js API web del navegador

Use 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

Titiritero

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.

He aquí una rápida comparación de sus características clave:

Feature 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
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:

  1. La función se convierte en una cadena usando Function.prototype.toString().
  2. Esta cadena se envía al navegador a través de Protocolo de Chrome DevTools.
  3. El navegador evalúa la función dentro de su entorno.
  4. Los resultados se serializan en JSON y se envían de vuelta al contexto Node.js.

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.
  • page.exposeFunction(): Permite que el navegador llame a funciones Node.js.
  • evaluateOnNewDocument():Ejecuta el código antes de que se cargue cualquier script de página.

Sin embargo, la serialización JSON puede eliminar ciertas propiedades, especialmente con objetos complejos como los nodos DOM. Para evitar problemas, pase los datos como argumentos de función en lugar de usar variables de Node.js.

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:

await page.evaluate(pageFunction, ...args)
Parámetro Tipo Descripción original
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 opción de 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 Mecanografiado 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:
const headingText = await page.evaluate(() => {
    return document.querySelector('h1').textContent;
});
  • Automatizar el envío de formularios 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');
  • Manipule el DOM agregando 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 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:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 100 // Adds a 100ms delay to each operation
});

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 'text', 42, true
Matrices/Objetos ✓ Compatible con JSON { key: 'value' }, [1, 2, 3]
Funciones ✗ No directamente Use page.exposeFunction
Elementos DOM ✓ A través de JSHandle Use page.evaluateHandle

Ahora, veamos cómo se devuelven estos valores desde el contexto del navegador.

Manejo de salida

Cuando usas page.evaluateLos valores devueltos se serializan automáticamente a JSON. Así 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 dada es más complicado que un objeto JSON (por ejemplo, la mayoría de las clases), entonces evaluate Probablemente 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.

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
const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose(); // Always clean up to avoid memory leaks
  • Uso de 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');
});
  • Ajuste de la configuración del transpilador

Si está trabajando 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 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:

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 una tabla

Este enfoque recupera datos de una tabla iterando a través de 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 los campos del 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();
});

Manejo de formularios complejos

Para tareas como seleccionar opciones 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 se desplaza por una página hasta que recopila 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: 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:

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 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

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:

// 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 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:

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 en todos los 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 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:

// 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 un mejor manejo:

// 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');
});

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:

// 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, le explicamos cómo:

// 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 múltiples elementos, pase 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 oyentes de eventos, asegúrese de 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);
  });
});

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 del rendimiento

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:

// 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;
});

La elección de los selectores adecuados también juega un papel importante en el rendimiento:

Tipo de selector Velocidad Ejemplo
ID Empresarial #main-content
Clase Rápido .product-item
Etiqueta Moderado div > span
XPath complejo El más lento //div[@class='wrapper']//span

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:

// 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 pasarlos 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 optimizado el rendimiento y el cambio de contexto, concé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 trabajo de Latenode, tenga en cuenta estos consejos adicionales:

  • Use userDataDir para 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.

Resum

Revisión de puntos clave

La opción de 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:

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()
  }));
});

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 evaluate contexto.
  • 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:

Propósito Mejor caso de uso
page.evaluateHandle Devuelve referencias de objetos Interactuar directamente con elementos DOM
page.exposeFunction Hace que las funciones de Node.js sean utilizables en el navegador Gestión de 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 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.

Blog y artículos

Blogs relacionados

Caso de uso

Respaldado por