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
| Recurso | Contexto do Node.js | Contexto do navegador |
|---|---|---|
| Objetos globais | process, require | window, document |
| Local do script | Máquina local | Página web de destino |
| Acesso a APIs | APIs do Node.js | APIs 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:
| Recurso | Contexto do Node.js | Contexto do navegador |
|---|---|---|
| Objetos globais | process, require, __dirname | window, document, localStorage |
| Local do script | Máquina local | Página web de destino |
| Escopo de variáveis | Escopo do script Puppeteer | Escopo do contexto da página |
| Acesso a APIs | APIs do Node.js | APIs Web do navegador |
| Espaço de memória | Processo separado | Processo 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:
- A função é convertida em uma string com
Function.prototype.toString()[1]. - Essa string é enviada ao navegador pelo Chrome DevTools Protocol [1].
- O navegador avalia a função em seu ambiente.
- 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âmetro | Tipo | Descrição |
|---|---|---|
| pageFunction | Função ou string | Código JavaScript a ser executado no contexto do navegador |
| args | Parâmetros opcionais | Valores transmitidos do Node.js para o contexto do navegador |
| Valor de retorno | Promise | Resolvida 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âmetro | Compatível? | Exemplo |
|---|---|---|
| Primitivos | ✓ Totalmente | 'texto', 42, true |
| Arrays/objetos | ✓ Compatível com JSON | { key: 'value' }, [1, 2, 3] |
| Funções | ✗ Não diretamente | Use page.exposeFunction |
| Elementos DOM | ✓ Por meio de JSHandle | Use 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),
evaluateprovavelmente 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 seletor | Velocidade | Exemplo |
|---|---|---|
| ID | Mais rápido | #main-content |
| Classe | Rápido | .product-item |
| Tag | Moderado | div > span |
| XPath complexo | Mais 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
userDataDirpara 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:
| Ferramenta | Finalidade | Melhor caso de uso |
|---|---|---|
| page.evaluateHandle | Retorna referências a objetos | Interação direta com elementos DOM |
| page.exposeFunction | Torna funções do Node.js utilizáveis no navegador | Gerenciamento de lógica complexa no lado do servidor |
| page.evaluateOnNewDocument | Executa scripts antes do carregamento de uma página | Preparaçã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.


