Uma plataforma de baixo código que combina a simplicidade sem código com o poder do código completo 🚀
Comece gratuitamente
Executando JavaScript no contexto da página com page.evaluate no Puppeteer
21 de março de 2025
.
12
min ler

Executando JavaScript no contexto da página com page.evaluate no Puppeteer

Jorge Miloradovitch
Pesquisador, redator e entrevistador de casos de uso
Índice

page.evaluate() é uma chave Marionetista método que permite executar JavaScript diretamente no contexto do navegador. Ele faz a ponte Node.js e o navegador, permitindo tarefas como manipulação de DOM, extração de dados e automação de páginas web dinâmicas. Aqui está o que você precisa saber:

  • O que faz: Executa JavaScript no navegador, como se você estivesse usando o console do navegador.
  • Como funciona: Converte uma função em uma string, envia-a ao navegador, executa-a e retorna o resultado.
  • Principais usos:
    • Extração de dados de sites (por exemplo, texto, tabelas, JSON).
    • Automatizando envios de formulários e interações do usuário.
    • Manipulando conteúdo dinâmico, como rolagem infinita ou atualizações AJAX.
  • Limitações: As funções devem ser serializáveis ​​em JSON, e as variáveis ​​do Node.js não são diretamente acessíveis no contexto do navegador.

Exemplo rápido:

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

Isso recupera o título da página diretamente do navegador.

Comparação: Node.js vs. Contexto do navegador

Node.js

Característica Contexto Node.js Contexto do navegador
Objetos Globais process, require window, document
Localização do script Máquina local Página da web de destino
Acesso API APIs do Node.js APIs da Web do navegador

Use page.evaluate() para tarefas de automação precisas e eficientes, especialmente ao trabalhar com sites com uso intenso de JavaScript.

NodeJS : Nodejs/Marionetista - Como usar page.evaluate

Marionetista

Contexto da página explicado

Ao trabalhar com o Puppeteer para automação web, é crucial entender a distinção entre Contexto Node.js e os votos de contexto do navegador. Esses dois ambientes são isolados, cada um com suas próprias regras para executar código e trocar dados.

Comparando Node.js e contextos de navegador

O marionetista opera em dois ambientes: o Contexto Node.js, onde seu script principal é executado e o contexto do navegador, onde ocorrem interações com a página da web. Esses são processos separados, cada um com sua própria máquina virtual.

Aqui está uma rápida comparação de suas principais características:

Característica Contexto Node.js Contexto do navegador
Objetos Globais process, require, __dirname window, document, localStorage
Localização do script Máquina local Página da web de destino
Escopo Variável Escopo do script do marionetista Âmbito do contexto da página
Acesso API APIs do Node.js APIs da Web do navegador
Espaço de Memória Processo separado Processo do navegador

Como funciona a comunicação de contexto

A troca de dados entre esses contextos envolve uma série de etapas, dependendo fortemente da serialização:

  1. A função é convertida em uma string usando Function.prototype.toString().
  2. Esta sequência é enviada ao navegador por meio do Protocolo Chrome DevTools.
  3. O navegador avalia a função dentro de seu ambiente.
  4. Os resultados são serializados em JSON e enviados de volta ao contexto do Node.js.

Principais limitações: Funções no contexto do navegador não podem acessar variáveis ​​diretamente do escopo do Node.js. O Puppeteer oferece ferramentas específicas para lidar com esses desafios:

  • page.evaluateHandle(): Retorna referências a objetos no contexto do navegador.
  • page.exposeFunction(): Permite que o navegador chame funções do Node.js.
  • evaluateOnNewDocument(): Executa o código antes que qualquer script de página seja carregado.

No entanto, a serialização JSON pode remover certas propriedades, especialmente com objetos complexos como nós DOM. Para evitar problemas, passe dados como argumentos de função em vez de depender de variáveis ​​Node.js.

Dominar essas técnicas de comunicação garante que você possa usar page.evaluate efetivamente para tarefas de automação. Em seguida, vamos mergulhar em exemplos práticos para ver esses conceitos em ação.

Introdução ao page.evaluate

Estrutura e parâmetros do método

Sintaxe:

await page.evaluate(pageFunction, ...args)
Parâmetro Formato Descrição
pageFunção Função ou string Código JavaScript para executar no contexto do navegador
args Parâmetros opcionais Valores passados ​​do Node.js para o contexto do navegador
Valor de retorno Promessa Resolve com o valor de retorno da função

A pageFunção pode ser uma função ou uma string contendo código JavaScript. Usar uma função geralmente é melhor para depuração e TypeScript compatibilidade. Abaixo estão alguns exemplos para demonstrar como funciona.

Exemplos de código básico

Exemplos:

  • Extrair texto do primeiro <h1> diretamente do DOM:
const headingText = await page.evaluate(() => {
    return document.querySelector('h1').textContent;
});
  • Automatize o envio de formulários passando 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 o DOM adicionando um novo elemento:
await page.evaluate(() => {
    const div = document.createElement('div');
    div.textContent = 'Added by Puppeteer';
    document.body.appendChild(div);
    return div.textContent;
});

Notas-chave para o desenvolvimento

  • As funções são executadas isoladamente do seu código Node.js.
  • Os argumentos passados ​​para a função devem ser JSON-serializável.
  • Os valores retornados são automaticamente encapsulados em um Promessa.
  • Manipular objetos complexos como nós DOM requer cuidado extra.

Dica de depuração: Use a seguinte configuração para habilitar a depuração durante o desenvolvimento:

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

Em seguida, veremos técnicas para troca de dados entre o Node.js e contextos de navegador.

Troca de dados entre contextos

Parâmetros de entrada

Ao transferir dados com page.evaluate, use valores serializáveis ​​em JSON para argumentos de entrada.

Aqui está uma rápida análise dos tipos de parâmetros suportados:

Tipo de Parâmetro Suportado? Exemplo
Primitivos ✓ Totalmente 'text', 42, true
Matrizes/Objetos ✓ Compatível com JSON { key: 'value' }, [1, 2, 3]
Funções ✗ Não diretamente Use page.exposeFunction
Elementos DOM ✓ Através do JSHandle Use page.evaluateHandle

Agora, vamos ver como esses valores são retornados do contexto do navegador.

Manipulação de saída

Ao usar page.evaluate, os valores retornados são serializados automaticamente para JSON. Veja 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 regra geral, se o valor de retorno da função fornecida for mais complicado do que um objeto JSON (por exemplo, a maioria das classes), então evaluate provavelmente retornará algum valor truncado (ou {}). Isso ocorre porque não estamos retornando o valor de retorno real, mas uma versão desserializada como resultado da transferência do valor de retorno por meio de um protocolo para o Puppeteer."

Após recuperar a saída, você pode encontrar desafios relacionados à serialização. Veja como lidar com eles.

Lidando com problemas de serialização

Alguns cenários comuns exigem soluções alternativas específicas:

  • Trabalhando com 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
  • Usando funções do 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');
});
  • Ajustando as configurações do Transpiler

Se você estiver trabalhando com TypeScript, certifique-se de que seu transpilador esteja configurado corretamente:

// tsconfig.json
{
    "compilerOptions": {
        "target": "es2018"
    }
}

Essas estratégias ajudarão você a lidar com a troca de dados de forma eficaz em vários contextos.

sbb-itb-23997f1

Exemplos Práticos

Veja como você pode usar page.evaluate em cenários do mundo real, completos com trechos de código práticos.

Extraindo dados

Exemplo: raspagem de detalhes do produto

Este script coleta detalhes como título, preço, classificação e status de estoque de cartões de produtos em uma página da 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')
  }));
});

Exemplo: Extraindo dados da tabela

Essa abordagem recupera dados de uma tabela iterando por suas linhas e colunas:

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

Automatizando Formulários

Automação básica de formulários

Veja como preencher campos de formulário, acionar eventos e enviar o formulário:

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

Manipulando formulários complexos

Para tarefas como selecionar opções suspensas ou verificar botões de opção:

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

Gerenciando Elementos Dinâmicos

Exemplo: rolagem infinita

Este script rola por uma página até coletar pelo menos 100 itens:

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

Exemplo: Manipulando conteúdo AJAX

Para carregar mais conteúdo dinamicamente, este script clica no botão "Carregar mais" e aguarda que novos elementos apareçam:

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

Esses exemplos mostram como lidar com cenários diversos, como scraping, automação de formulários e conteúdo dinâmico. Ajustes podem ser feitos com base na estrutura e no comportamento específicos da página da web com a qual você está trabalhando.

Usando page.evaluate em Nó latente

Nó latente

O Latenode incorpora os principais recursos do Puppeteer em seus fluxos de trabalho de automação, facilitando a execução de JavaScript diretamente no navegador. Com page.evaluate, os usuários podem manipular o DOM e extrair dados de forma eficiente. Essa abordagem permite integração perfeita de manipulação avançada de dados e operações DOM dentro do ambiente de automação do Latenode.

Scripts de navegador em Latenode

O módulo de automação do navegador do Latenode usa page.evaluate para lidar com tudo, desde tarefas simples de DOM até execuções mais complexas de JavaScript. Veja como funciona em diferentes cenários:

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

O Latenode também mantém um registro do histórico de execução, facilitando a depuração de scripts.

Exemplos de automação

O Latenode é bem equipado para lidar com conteúdo dinâmico e tarefas complexas de automação. Aqui está um exemplo de processamento de conteúdo dinâmico em uma 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 operações mais avançadas, page.exposeFunction permite interação perfeita entre o Node.js e o 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 manter referências aos elementos DOM em todas as etapas, o Latenode usa page.evaluateHandle:

const elementHandle = await page.evaluateHandle(() => {
  return document.querySelector('.dynamic-content');
});

await page.evaluate(element => {
  element.scrollIntoView();
}, elementHandle);

Essas técnicas garantem que o Latenode possa lidar com conteúdo dinâmico de forma eficaz, mantendo um desempenho confiável. Para usuários no plano Prime, a plataforma suporta até 1.5 milhão de execuções de cenário por mês, fornecendo amplos recursos de automação.

Guia de resolução de erros

Ao trabalhar com page.evaluate na automação do navegador, você pode encontrar vários problemas. Aqui estão soluções práticas para lidar com eles e garantir uma execução mais suave.

Corrigindo erros de contexto

Configure corretamente suas configurações de TypeScript para evitar problemas causados ​​pela transpilação. Por exemplo:

// Use direct, non-transpiled functions
await page.evaluate(() => {
  document.querySelector('#button').click();
});

await page.evaluate(`(async () => {
  document.querySelector('#button').click();
})()`);

Evite retornar elementos DOM diretamente de page.evaluate. Em vez disso, use ElementHandle para melhor manuseio:

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

Resolvendo problemas de tempo

Scripts podem ser executados antes que a página seja totalmente carregada, levando a erros de tempo. Use estas estratégias para lidar com tais 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 sites dinâmicos, adote mecanismos de espera mais direcionados:

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

Gerenciando referências DOM

Para evitar vazamentos de memória, gerencie cuidadosamente as referências DOM. Veja como:

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

Ao trabalhar com vários elementos, passe dados com segurança 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 ouvintes de eventos, garanta uma limpeza adequada para evitar manipuladores 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);
  });
});

Diretrizes de implementação

Para obter os melhores resultados com page.evaluate, você precisa se concentrar em melhorar o desempenho, reduzir a troca desnecessária de contexto e garantir a segurança. Veja como você pode ajustar seus fluxos de trabalho de automação do navegador.

Otimização de Desempenho

Executar código eficientemente dentro do contexto da página economiza tempo e recursos do sistema. Abaixo estão algumas técnicas para tornar seus scripts mais rápidos:

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

A escolha dos seletores certos também desempenha um papel importante no desempenho:

Tipo de seletor Velocidade Exemplo
ID Fastest #main-content
Aula pomposidade .product-item
etiqueta Moderado div > span
XPath complexo Mais lento //div[@class='wrapper']//span

Gerenciamento de troca de contexto

A troca de contexto entre o Node.js e o ambiente do navegador pode deixar as coisas lentas. Veja como minimizá-la:

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

Se você precisar processar dados no Node.js e passá-los de volta para o navegador, exponha funções em vez de alternar contextos 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
});

Diretrizes de segurança

Depois que o desempenho e a troca de contexto forem otimizados, concentre-se em manter seus scripts seguros. Aqui estão algumas práticas 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 fluxos de trabalho do Latenode, considere estas dicas adicionais:

  • Use userDataDir para armazenar recursos em cache e melhorar o desempenho entre sessões.
  • Feche páginas e instâncias do navegador não utilizadas para economizar memória.
  • Manipule capturas de tela com buffers em vez de depender de operações do sistema de arquivos.
  • Implemente tratamento de erros robusto e verificações de segurança completas.

Resumo

Revisão dos pontos-chave

A page.evaluate O método conecta o Node.js e os contextos do navegador enviando uma função JavaScript stringificada para executar no navegador. Essa função opera independentemente do ambiente do Node.js, então você precisa lidar com a transferência de dados com cuidado.

Aqui está um exemplo comum para extração de dados:

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

Coisas a ter em mente:

  • Os argumentos devem ser serializáveis ​​em JSON.
  • Os valores de retorno são desserializados automaticamente.
  • As APIs do navegador estão disponíveis apenas no evaluate contexto.
  • As variáveis ​​do Node.js não são acessíveis no contexto do navegador.

Esses princípios básicos estabelecem a base para usar o Puppeteer de forma eficaz. Ferramentas adicionais podem simplificar ainda mais suas tarefas de automação.

Ferramentas adicionais para marionetistas

O Puppeteer oferece diversas ferramentas para expandir as capacidades do page.evaluate:

ferramenta Propósito Melhor caso de uso
page.evaluateHandle Retorna referências de objeto Interagindo com elementos DOM diretamente
page.exposeFunction Torna as funções do Node.js utilizáveis ​​no navegador Gerenciando lógica complexa do lado do servidor
page.evaluateOnNewDocument Executa scripts antes do carregamento de uma página Preparando o ambiente do navegador com antecedência

Por exemplo, expor funções do Node.js ao navegador pode simplificar o processamento avançado de dados em fluxos de trabalho como aqueles no Latenode. Enquanto page.evaluate funciona bem para manipular tipos primitivos e objetos serializáveis ​​JSON, page.evaluateHandle é essencial para lidar com objetos complexos do navegador que não podem ser serializados.

Posts Relacionados do Blog

Blogs relacionados

Caso de uso

Apoiado por