Latenode

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

Aprenda a usar com eficiência o método page.evaluate do Puppeteer para executar JavaScript no contexto do navegador em tarefas de automação web.

10 min de leitura
Código JavaScript sendo executado no DOM do navegador com Puppeteer

page.evaluate() é um método essencial do Puppeteer que permite executar JavaScript diretamente no contexto do navegador. Ele conecta o Node.js ao navegador, viabilizando tarefas como manipulação do DOM, extração de dados e automação de páginas web dinâmicas. Veja o que você precisa saber:

  • O que ele 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, textos, tabelas e JSON).
    • Automação de envios de formulários e interações de usuários.
    • Tratamento de conteúdo dinâmico, como rolagem infinita ou atualizações AJAX.
  • Limitações: As funções precisam ser serializáveis em JSON, e variáveis do Node.js não podem ser acessadas diretamente 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: contexto do Node.js vs. navegador

RecursoContexto do Node.jsContexto do navegador
Objetos globaisprocess, requirewindow, document
Local do scriptMáquina localPágina web de destino
Acesso a APIsAPIs do Node.jsAPIs Web do navegador

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

NodeJS: Nodejs/Puppeteer - Como usar page.evaluate

Explicação sobre o contexto da página

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

Comparação entre contextos do Node.js e do navegador

O Puppeteer opera em dois ambientes: o contexto do Node.js, no qual seu script principal é executado, e o contexto do navegador, no qual ocorrem as interações com a página web. Eles são processos separados, cada um com sua própria máquina virtual [3].

Veja uma comparação rápida das principais características:

RecursoContexto do Node.jsContexto do navegador
Objetos globaisprocess, require, __dirnamewindow, document, localStorage
Local do scriptMáquina localPágina web de destino
Escopo de variáveisEscopo do script PuppeteerEscopo do contexto da página
Acesso a APIsAPIs do Node.jsAPIs Web do navegador
Espaço de memóriaProcesso separadoProcesso do navegador

Como funciona a comunicação entre contextos

A troca de dados entre esses contextos envolve uma série de etapas e depende bastante da serialização:

  1. A função é convertida em uma string com Function.prototype.toString() [1].
  2. Essa string é enviada ao navegador pelo Chrome DevTools Protocol [1].
  3. O navegador avalia a função em seu ambiente.
  4. Os resultados são serializados em JSON e enviados de volta ao contexto do Node.js [1].

Principais limitações: Funções no contexto do navegador não podem acessar diretamente variáveis 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 [1].
  • page.exposeFunction(): Permite que o navegador chame funções do Node.js [1].
  • evaluateOnNewDocument(): Executa código antes do carregamento de qualquer script da página [1].

No entanto, a serialização em JSON pode remover determinadas propriedades, especialmente em objetos complexos como nós do DOM [2]. Para evitar problemas, passe dados como argumentos da função em vez de depender de variáveis do Node.js [3].

Dominar essas técnicas de comunicação garante que você consiga usar page.evaluate de forma eficaz em tarefas de automação. A seguir, vamos explorar exemplos práticos para ver esses conceitos em ação.

Primeiros passos com page.evaluate

Estrutura e parâmetros do método

Sintaxe:

await page.evaluate(pageFunction, ...args)
ParâmetroTipoDescrição
pageFunctionFunção ou stringCódigo JavaScript a ser executado no contexto do navegador
argsParâmetros opcionaisValores transmitidos do Node.js para o contexto do navegador
Valor de retornoPromiseResolvida com o valor retornado pela função

A pageFunction pode ser uma função ou uma string contendo código JavaScript. Em geral, usar uma função é melhor para depuração e compatibilidade com TypeScript. Veja abaixo alguns exemplos de funcionamento.

Exemplos básicos de código

Exemplos:

  • Extraia texto do primeiro <h1> diretamente do DOM:
const headingText = await page.evaluate(() => {
    return document.querySelector('h1').textContent;
});
  • Automatize o envio de formulário 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 = 'Adicionado pelo Puppeteer';
    document.body.appendChild(div);
    return div.textContent;
});

Pontos importantes para desenvolvimento

  • As funções são executadas isoladamente do seu código Node.js.
  • Os argumentos passados à função precisam ser serializáveis em JSON.
  • Os valores retornados são automaticamente encapsulados em uma Promise.
  • O tratamento de objetos complexos, como nós do DOM, exige atenção adicional.

Dica de depuração: Use a configuração abaixo para ativar a depuração durante o desenvolvimento:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 100 // Adiciona um atraso de 100 ms a cada operação
});

A seguir, veremos técnicas para trocar dados entre os contextos do Node.js e do navegador.

Troca de dados entre contextos

Parâmetros de entrada

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

Veja um resumo rápido dos tipos de parâmetros compatíveis:

Tipo de parâmetroCompatível?Exemplo
Primitivos✓ Totalmente'texto', 42, true
Arrays/objetos✓ Compatível com JSON{ key: 'value' }, [1, 2, 3]
Funções✗ Não diretamenteUse page.exposeFunction
Elementos DOM✓ Por meio de JSHandleUse page.evaluateHandle

Agora, veja como esses valores são retornados pelo contexto do navegador.

Tratamento de saída

Ao usar page.evaluate, os valores retornados são serializados automaticamente em JSON. Veja como funciona:

// Retornando um valor simples
const pageTitle = await page.evaluate(() => document.title);

// Retornando um objeto complexo
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 informada for mais complexo que um objeto JSON (por exemplo, a maioria das classes), evaluate provavelmente retornará algum valor truncado (ou {}). Isso acontece 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 um protocolo para o Puppeteer." [1]

Depois de recuperar a saída, você pode encontrar desafios relacionados à serialização. Veja como resolvê-los.

Tratamento de problemas de serialização

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

  • Trabalhando com elementos DOM
const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose(); // Sempre faça a limpeza para evitar vazamentos de memória
  • 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 configurações do transpilador

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

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

Essas estratégias ajudam você a realizar a troca de dados com eficiência em vários contextos.

sbb-itb-23997f1

Exemplos práticos

Veja como usar page.evaluate em situações reais, com trechos de código práticos.

Extração de dados

Exemplo: coleta de detalhes de produtos

Este script coleta informações como título, preço, avaliação e disponibilidade em estoque de cards de produtos em uma 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')
  }));
});

Exemplo: extração de dados de 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);
  });
});

Automação de 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(() => {
  // Preencha os campos do formulário
  document.querySelector('#username').value = 'testuser';
  document.querySelector('#password').value = 'secretpass';

  // Acione eventos de entrada para formulários dinâmicos
  const event = new Event('input', { bubbles: true });
  document.querySelector('#username').dispatchEvent(event);

  // Envie o formulário
  document.querySelector('form').submit();
});

Tratamento de formulários complexos

Para tarefas como selecionar opções em menus suspensos ou marcar botões de opção:

await page.evaluate(() => {
  // Selecione uma opção no menu suspenso
  const select = document.querySelector('#country');
  select.value = 'US';
  select.dispatchEvent(new Event('change', { bubbles: true }));

  // Marque o botão de opção
  const radio = document.querySelector('input[value="express"]');
  radio.checked = true;
  radio.dispatchEvent(new Event('change', { bubbles: true }));
});

Gerenciamento de elementos dinâmicos

Exemplo: rolagem infinita

Este script percorre 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) {
    // Role até o final
    window.scrollTo(0, document.body.scrollHeight);

    // Aguarde o novo conteúdo
    await delay(1000);

    // Colete os itens
    document.querySelectorAll('.item').forEach(item => 
      items.add(item.textContent.trim())
    );
  }

  return Array.from(items);
});

Exemplo: tratamento de conteúdo AJAX

Para carregar mais conteúdo dinamicamente, este script clica em um botão "Carregar mais" e aguarda o surgimento de novos elementos:

await page.evaluate(async () => {
  // Clique no botão para carregar mais
  document.querySelector('#loadMore').click();

  // Aguarde a atualização do conteúdo
  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 coleta de dados, automação de formulários e conteúdo dinâmico. Os ajustes podem ser feitos de acordo com a estrutura e o comportamento específicos da página web com a qual você está trabalhando.

Como usar page.evaluate no Latenode

A Latenode incorpora os principais recursos do Puppeteer aos seus fluxos 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 com eficiência. Essa abordagem permite integrar operações avançadas de tratamento de dados e DOM ao ambiente de automação da Latenode.

Scripts de navegador na Latenode

O módulo de automação de navegador da 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 situações:

// Interação básica com o DOM
await page.evaluate(() => {
  const loginButton = document.querySelector('#login');
  loginButton.click();

  // Acione um evento personalizado
  loginButton.dispatchEvent(new Event('customClick'));
});

// Processamento de dados com funções expostas
await page.exposeFunction('processData', async (data) => {
  // Processe dados no contexto do Node.js
  return transformedData;
});

await page.evaluate(async () => {
  const rawData = document.querySelector('#data').textContent;
  const processed = await window.processData(rawData);
  return processed;
});

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

Exemplos de automação

A Latenode está bem preparada para lidar com conteúdo dinâmico e tarefas complexas de automação. Veja um exemplo do 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));

  // Aguarde o carregamento do conteúdo dinâmico
  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 uma interação fluida 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 a elementos DOM entre etapas, a 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 a Latenode consiga lidar com conteúdo dinâmico de forma eficaz e, ao mesmo tempo, mantenha um desempenho confiável. Para usuários do plano Prime, a plataforma oferece suporte a até 1,5 milhão de execuções de fluxo por mês, disponibilizando amplos recursos de automação.

Guia de resolução de erros

Ao trabalhar com page.evaluate na automação de navegador, você pode encontrar vários problemas. Veja soluções práticas para resolvê-los e garantir uma execução mais fluida.

Correção de erros de contexto

Configure corretamente as definições do TypeScript para evitar problemas causados pela transpilação. Por exemplo:

// Use funções diretas, sem transpilação
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 um tratamento melhor:

// Incorreto: retorna um elemento DOM
const element = await page.evaluate(() => {
  return document.querySelector('.dynamic-element');
});

// Correto: usa ElementHandle
const element = await page.evaluateHandle(() => {
  return document.querySelector('.dynamic-element');
});

Solução de problemas de timing

Os scripts podem ser executados antes de a página carregar totalmente, gerando erros de timing. Use estas estratégias para lidar com esses casos:

// Aguarde a navegação após uma ação
await Promise.all([
  page.waitForNavigation(),
  page.click('#submit-button')
]);

// Aguarde uma condição específica
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:

// Aguarde solicitações de rede específicas
await page.waitForResponse(
  response => response.url().includes('/api/data')
);

// Garanta que os elementos estejam presentes e visíveis
await page.waitForSelector('.dynamic-content', {
  visible: true,
  timeout: 3000
});

Gerenciamento de referências do DOM

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

// Use e descarte ElementHandles
const handle = await page.evaluateHandle(() => {
  return document.querySelector('.temporary-element');
});
await handle.evaluate(element => {
  // Execute operações
});
await handle.dispose(); // Descarte o handle após o uso

Ao trabalhar com vários elementos, transmita dados com segurança entre os contextos:

// Extraia dados do DOM
const selector = '.product-price';
const price = await page.evaluate((sel) => {
  const element = document.querySelector(sel);
  return element ? element.textContent.trim() : null;
}, selector);

Para listeners de eventos, garanta uma limpeza adequada para evitar manipuladores persistentes:

await page.evaluate(() => {
  const handler = () => console.log('clicado');
  const button = document.querySelector('#button');
  button.addEventListener('click', handler);

  // Armazene referências de limpeza
  window._cleanupHandlers = window._cleanupHandlers || [];
  window._cleanupHandlers.push(() => {
    button.removeEventListener('click', handler);
  });
});

Diretrizes de implementação

Para obter os melhores resultados com page.evaluate, concentre-se em melhorar o desempenho, reduzir alternâncias desnecessárias de contexto e garantir a segurança. Veja como aprimorar seus fluxos de automação de navegador.

Otimização de desempenho

Executar código com eficiência no contexto da página economiza tempo e recursos do sistema. Veja algumas técnicas para tornar seus scripts mais rápidos:

// Bloqueie recursos desnecessários, como imagens e folhas de estilo
await page.setRequestInterception(true);
page.on('request', request => {
  if (['image', 'stylesheet'].includes(request.resourceType())) {
    request.abort();
  } else {
    request.continue();
  }
});

// Agrupe operações para reduzir a sobrecarga
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;
});

Escolher os seletores certos também tem um grande impacto no desempenho:

Tipo de seletorVelocidadeExemplo
IDMais rápido#main-content
ClasseRápido.product-item
TagModeradodiv > span
XPath complexoMais lento//div[@class='wrapper']//span

Gerenciamento de alternância de contexto

Alternar entre o Node.js e o ambiente do navegador pode deixar o processo mais lento. Veja como minimizar isso:

// Exemplo de alternância de contexto ineficiente
for (const item of items) {
  await page.evaluate((i) => {
    document.querySelector(`#item-${i}`).click();
  }, item);
}

// Melhor: agrupe operações em uma única alternância de contexto
await page.evaluate((itemsList) => {
  itemsList.forEach(i => {
    document.querySelector(`#item-${i}`).click();
  });
}, items);

Se você precisar processar dados no Node.js e enviá-los de volta ao navegador, exponha funções em vez de alternar repetidamente entre contextos:

await page.exposeFunction('processData', async (data) => {
  // Processe dados no Node.js
  return transformedData;
});

await page.evaluate(async () => {
  const result = await window.processData(documentData);
  // Use os dados processados no navegador
});

Diretrizes de segurança

Depois de otimizar o desempenho e a alternância de contexto, concentre-se em manter seus scripts seguros. Veja algumas boas práticas:

// Sempre higienize as entradas antes de usá-las
const sanitizedInput = sanitizeHtml(userInput);
await page.evaluate((input) => {
  document.querySelector('#search').value = input;
}, sanitizedInput);

// Use tratamento de erros em operações críticas
try {
  await page.evaluate(() => {
    if (!window.__securityCheck) {
      throw new Error('Falha na verificação de segurança');
    }
    // Continue com a operação
  });
} catch (error) {
  console.error('Violação de segurança:', error);
}

Para fluxos da 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 de navegador não utilizadas para economizar memória.
  • Trate capturas de tela com buffers em vez de depender de operações do sistema de arquivos.
  • Implemente tratamento robusto de erros e verificações de segurança completas.

Resumo

Revisão dos pontos principais

O método page.evaluate conecta os contextos do Node.js e do navegador enviando uma função JavaScript convertida em string para ser executada no navegador. Essa função opera de forma independente do ambiente Node.js, portanto você precisa lidar cuidadosamente com a transferência de dados.

Veja um exemplo comum de 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()
  }));
});

Pontos importantes:

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

Esses fundamentos criam a base para usar o Puppeteer de forma eficaz. Ferramentas adicionais podem simplificar ainda mais suas tarefas de automação.

Ferramentas adicionais do Puppeteer

O Puppeteer oferece várias ferramentas para ampliar os recursos de page.evaluate:

FerramentaFinalidadeMelhor caso de uso
page.evaluateHandleRetorna referências a objetosInteração direta com elementos DOM
page.exposeFunctionTorna funções do Node.js utilizáveis no navegadorGerenciamento de lógica complexa no lado do servidor
page.evaluateOnNewDocumentExecuta scripts antes do carregamento de uma páginaPreparação antecipada do ambiente do navegador

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

References

FAQ

Frequently Asked Questions

page.evaluate() executa JavaScript no contexto do navegador, serializa a função para a página por meio do Chrome DevTools Protocol, executa-a no DOM e retorna resultados serializáveis em JSON para o seu script Node.js.

Isso foi útil? Compartilhe →

Escrito por

Vasiliy Datsenko

Head of Customer Support

Vasiliy Datsenko é Head of Customer Support na Latenode e um escritor de automação focado em produto. Seu trabalho conecta conversas com clientes, pesquisa de automação de fluxos de trabalho, casos de uso de IA e educação prática sobre produtos para equipes que tentam automatizar processos de negócios reais.

Perfil do autor →

Verificado por

Oleg Zankov

CEO da Latenode, Especialista em No-code

Com uma filosofia enraizada em inovação, resolução de problemas e experiência do usuário, estou focado em capacitar equipes a criar integrações personalizadas e automatizar fluxos de trabalho com facilidade e eficiência. Trazendo uma vasta experiência em desenvolvimento de negócios, empreendedorismo tecnológico e desenvolvimento de software, reconheci a necessidade de uma solução de integração mais acessível, escalável e adaptável. Assim, nasceu a Latenode.com. Com nossa plataforma, as empresas podem aproveitar o poder da tecnologia sem a necessidade de conhecimentos extensos em programação. Apaixonado por promover um futuro onde a tecnologia nos serve, e não o contrário, minha missão é tornar processos complexos simples. Acredito em democratizar a tecnologia e equipar as equipes com as ferramentas para inovar, crescer e ter sucesso em um mundo cada vez mais digital.

Perfil do autor →

Continue lendo