Latenode

Condições de espera personalizadas com waitForFunction no Puppeteer

Aprimore seus scripts do Puppeteer com condições de espera personalizadas usando waitForFunction, garantindo interações confiáveis com conteúdo web dinâmico.

8 min de leitura
Código do Puppeteer configurando uma condição de espera personalizada

Quer que seus scripts do Puppeteer lidem melhor com sites dinâmicos? Aqui está o ponto-chave: waitForFunction permite definir regras de espera personalizadas para garantir que sua automação funcione perfeitamente com conteúdos que mudam.

Por que usar waitForFunction?

  • Controle de tempo: Aguarde até que condições específicas sejam atendidas (por exemplo, elementos serem carregados ou textos mudarem).
  • Lide com conteúdo dinâmico: Ideal para sites modernos e dinâmicos.
  • Evite erros: Elimine atrasos desnecessários ou interações prematuras.

Como funciona:

  • Escreva condições em JavaScript que retornem true quando estiverem prontas.
  • Use opções como frequência de polling (raf, mutation ou milissegundos) e timeouts para melhorar o desempenho.
  • Combine verificações do DOM com respostas de API para fluxos avançados.

Exemplo:

await page.waitForFunction(
  () => document.querySelector('.status').textContent === 'Ready'
);

Recursos principais:

  • Monitore visibilidade de elementos, conteúdo de texto ou propriedades personalizadas.
  • Combine várias condições para fluxos complexos.
  • Lide com timeouts e erros de forma eficiente.

Dica: Use waitForFunction para substituir chamadas sleep obsoletas e melhorar a eficiência.

Visão geral rápida:

RecursoO que faz
Modos de pollingVerifica condições por meio de 'raf', 'mutation' ou intervalos personalizados
Condições personalizadasAguarda estados específicos do DOM ou respostas de API
Gerenciamento de timeoutDefine timeouts específicos por operação ou globais

Esse método garante que seus scripts sejam confiáveis, eficientes e estejam prontos para qualquer desafio de conteúdo dinâmico.

Como esperar / pausar por N segundos no puppeteer?

Conceitos básicos de waitForFunction

O método waitForFunction no Puppeteer permite configurar condições personalizadas que seus scripts devem aguardar antes de continuar. Veja como usá-lo de forma eficiente.

Como escrever funções básicas de espera

Veja uma forma simples de criar uma função de espera:

// Wait until the input element has a specific value
await page.waitForFunction(
  'document.getElementById("loginUsername").value === "hello"'
);

// Using an arrow function for a condition
await page.waitForFunction(
  () => document.querySelector('.status').textContent === 'Ready'
);

O ponto principal é que sua função precisa retornar um valor truthy antes que o script possa avançar [1].

Agora, veja como configurá-lo para obter melhor desempenho.

Configurando parâmetros da função

Você pode ajustar waitForFunction passando um objeto de opções. Os principais parâmetros incluem:

ParâmetroDescriçãoValores comuns
pollingCom que frequência a condição é verificada'raf', 'mutation' ou milissegundos
timeoutTempo máximo de esperaPadrão: 30.000 ms (30 segundos)

Modos de polling [4]:

  1. RequestAnimationFrame ('raf')
    Ideal para monitorar mudanças de estilo, pois verifica condições em cada frame de animação.

  2. Mutation Observer ('mutation')
    Útil para acompanhar mudanças na estrutura do DOM. Ele aciona verificações sempre que o DOM é atualizado.

  3. Intervalo personalizado (milissegundos)
    Por exemplo, isto verifica a condição a cada segundo:

    await page.waitForFunction(
      () => document.readyState === 'complete',
      { polling: 1000, timeout: 5000 }
    );
    

Escolha o modo de polling com base nas suas necessidades:

  • Use 'raf' para animações ou atualizações de estilo.
  • Escolha 'mutation' para alterações relacionadas ao DOM.
  • Defina um intervalo personalizado (milissegundos) para casos de uso mais amplos.

Criando regras de espera personalizadas

Verificando o status de exibição de elementos

Para confirmar se um elemento está visível, você pode verificar sua presença e dimensões:

await page.waitForFunction(() => {
    const element = document.querySelector('.tv-lightweight-charts');
    return element && element.offsetHeight > 0 && element.offsetWidth > 0;
});

Isso garante que o elemento exista e tenha dimensões visíveis na página. É especialmente útil para conteúdo dinâmico que leva tempo para carregar corretamente [2].

Testando texto e propriedades de elementos

Além das verificações visuais, você pode monitorar o conteúdo de texto ou propriedades específicas dos elementos:

// Wait for specific text content
await page.waitForFunction(
    selector => {
        const element = document.querySelector(selector);
        return element && element.textContent.includes('Ready');
    },
    {},
    '.status-message'
);

Para verificações de propriedades mais detalhadas, passe argumentos adicionais:

const expectedValue = 'completed';
const selector = '.status';

await page.waitForFunction(
    (sel, val) => {
        const element = document.querySelector(sel);
        return element && element.getAttribute('data-state') === val;
    },
    {},
    selector,
    expectedValue
);

Combinando várias regras de espera

Depois de testar condições individuais, você pode combiná-las para fluxos mais complexos. Por exemplo:

await page.waitForFunction(() => {
    // Check multiple elements and conditions
    const button = document.querySelector('.donate-button');
    const searchBox = document.querySelector('.search-button');

    return button && 
           searchBox && 
           button.offsetHeight > 0 && 
           searchBox.offsetHeight > 0 &&
           !button.disabled;
});

Para lidar com vários elementos com condições independentes, use combinações de Promise [5]:

Padrão de esperaCaso de usoImplementação
Todos os elementosAguarda vários elementos necessáriosPromise.all()
Qualquer elementoContinua quando o primeiro elemento aparecePromise.race()
Lógica personalizadaLida com verificações condicionais complexasFunções de espera combinadas

Para operações assíncronas, você pode criar condições de espera avançadas:

await page.waitForFunction(
    async () => {
        const response = await fetch('/api/status');
        const data = await response.json();
        return data.isReady && document.querySelector('.content').offsetHeight > 0;
    },
    { polling: 'mutation' }
);

Esse método combina validação de resposta de API com verificações de elementos do DOM, garantindo que tanto os dados quanto o conteúdo visual estejam prontos [1].

sbb-itb-23997f1

Métodos avançados de waitForFunction

Escrevendo condições complexas em JavaScript

Para aplicações web mais dinâmicas, você pode usar waitForFunction para criar condições detalhadas em JavaScript. Veja um exemplo:

await page.waitForFunction(
    (threshold) => {
        const chart = document.querySelector('.tv-lightweight-charts');
        const dataPoints = chart?.querySelectorAll('.data-point');

        return chart && 
               dataPoints?.length > threshold && 
               Array.from(dataPoints).every(point => 
                   point.getBoundingClientRect().height > 0 &&
                   !point.classList.contains('loading')
               );
    },
    { polling: 'mutation' },
    5
);

Esse script garante que:

  • O contêiner do gráfico exista.
  • Haja uma quantidade mínima de pontos de dados.
  • Todos os pontos de dados estejam visíveis.
  • Nenhum dos pontos esteja em estado de carregamento.

Você também pode combinar verificações assíncronas com avaliações do DOM para fluxos mais complexos:

await page.waitForFunction(
    async () => {
        // Check if the container is ready
        const container = document.querySelector('.dynamic-content');
        if (!container || container.offsetHeight === 0) return false;

        // Validate API response
        try {
            const response = await fetch('/api/status');
            const data = await response.json();
            return data.isReady && container.children.length > 0;
        } catch {
            return false;
        }
    },
    { 
        polling: 'raf',
        timeout: 30000
    }
);

Essa abordagem combina verificações do DOM com uma chamada de API para garantir que tanto a interface quanto o backend estejam sincronizados.

Lidando com timeouts e erros

O gerenciamento de timeout é fundamental ao trabalhar com waitForFunction. Veja um exemplo de como lidar com timeouts de forma eficiente:

try {
    await page.setDefaultTimeout(60000); // Set a global timeout of 60 seconds

    await page.waitForFunction(
        () => {
            const element = document.querySelector('.dynamic-element');
            return element?.complete === true;
        },
        {
            timeout: 45000, // Specific timeout for this operation
            polling: 'mutation'
        }
    );
} catch (error) {
    if (error.name === 'TimeoutError') {
        console.error('Element state check timed out:', error.message);
        await page.reload(); // Reload page as a fallback
    }
    throw error;
}

Veja uma visão geral rápida das estratégias de timeout:

Estratégia de timeoutCaso de usoConfiguração
Timeout padrãoOperações geraispage.setDefaultTimeout()
Timeout de navegaçãoCarregamentos de páginapage.setDefaultNavigationTimeout()
Específico por operaçãoVerificações detalhadasUse a opção timeout no método
Espera infinitaAtrasos conhecidostimeout: 0

Para melhorar o tratamento de erros:

  • Ajuste as configurações de timeout com base na complexidade de cada operação.
  • Use blocos try-catch para se recuperar de erros de forma eficiente.
  • Monitore a atividade de rede para identificar gargalos.
  • Implemente ações de contingência, como recarregar a página, quando ocorrerem timeouts.
  • Verifique novamente os seletores para evitar atrasos desnecessários.

Essas práticas ajudam a garantir que seus scripts sejam confiáveis e eficientes.

Como fazer waitForFunction executar mais rápido

Dicas de velocidade e recursos

Para fazer o waitForFunction operar com mais eficiência, concentre-se em estratégias inteligentes de espera e no gerenciamento adequado de recursos. Use as ferramentas de desenvolvedor do navegador para medir tempos de carregamento e definir timeouts precisos.

// Optimize waiting with a networkidle strategy
await page.goto('https://example.com', {
    waitUntil: 'networkidle2',
    timeout: 30000
});

// Combine checks in a single evaluate call
await page.evaluate(() => {
    const element = document.querySelector('.dynamic-content');
    const isVisible = element?.offsetHeight > 0;
    const hasData = element?.children.length > 0;
    return isVisible && hasData;
});

Para reduzir o uso de recursos:

  • Bloqueie recursos desnecessários, como imagens ou fontes.
  • Use waitForSelector ou waitForFunction em vez do waitForTimeout obsoleto.
  • Combine várias verificações em uma única chamada evaluate para reduzir a comunicação entre o navegador e o Node.js.
EstratégiaImpacto no desempenhoMelhor caso de uso
networkidle2ModeradoNavegação de página
waitForSelectorRápidoVerificações de um único elemento
waitForFunctionVariávelCondições complexas
evaluate combinadoMais rápidoVerificações de vários elementos

Esses métodos podem ajudar a resolver gargalos comuns, abordados na próxima seção.

Corrigindo problemas comuns

Problemas de desempenho geralmente vêm de padrões de espera ineficientes. Veja como lidar com eles:

Problemas com seletores
Seletores excessivamente rígidos podem causar falhas. Simplifique-os para obter mais confiabilidade:

// Avoid rigid selectors like this
await page.waitForSelector('div.container > div:nth-child(2) > span.text-red');

// Use a more flexible approach
await page.waitForFunction(
    () => document.querySelector('.text-red')?.offsetParent !== null
);

Gerenciamento de recursos
Gerencie recursos e evite atrasos desnecessários:

try {
    await page.waitForFunction(
        () => document.readyState === 'complete' &&
              performance.now() > 1000
    );
} catch (error) {
    console.error('Page load timeout:', error.message);
}

"O Puppeteer tem uma arquitetura orientada a eventos, o que elimina boa parte da potencial instabilidade. Não há necessidade de chamadas malignas de sleep[undefined] em scripts do puppeteer." — readme do Puppeteer [6]

Sempre envolva métodos de espera em blocos try...catch para lidar com erros de forma eficiente e oferecer opções de contingência. Essa abordagem garante que seus scripts permaneçam robustos e confiáveis.

Usos comuns de regras de espera personalizadas

Carregamento de produtos em lojas online

Garantir que os produtos sejam carregados corretamente é essencial para coletar dados precisos. Use uma regra de espera personalizada para pausar a execução até que os itens dos produtos estejam totalmente carregados:

await page.waitForFunction(() => {
    const products = document.querySelectorAll('.product-card');
    return products.length > 0 && all images and prices fully load;
});

Para obter mais precisão, você pode usar esta abordagem:

await page.waitForFunction(() => {
    const productDetails = document.querySelector('.product-details');
    return productDetails && 
           productDetails.offsetHeight > 0 && 
           productDetails.querySelector('.inventory-status') !== null;
}, {timeout: 30000});

Isso garante que seu script aguarde o carregamento de todos os elementos necessários, melhorando a confiabilidade da coleta de dados em fluxos de e-commerce.

Carregando conteúdo em aplicações web modernas

Aplicações web dinâmicas geralmente exigem condições de espera específicas para lidar com o carregamento de conteúdo. Por exemplo, você pode aguardar até que um elemento específico se torne totalmente visível:

await page.waitForFunction(() => {
    const element = document.querySelector('.tv-lightweight-charts');
    return element && element.offsetHeight > 0 && element.offsetWidth > 0;
});

Se várias seções precisarem ser carregadas, combine as condições desta forma:

await page.waitForFunction(() => {
    const contentLoaded = document.querySelector('.content').children.length > 0;
    const dataUpdated = document.body.textContent.includes('Last updated:');
    return contentLoaded && dataUpdated;
}, {polling: 1000});

Esse método ajuda a garantir que seus scripts de automação interajam perfeitamente com conteúdo dinâmico.

Detecção de mensagens de erro em formulários

A detecção de erros em formulários usa uma lógica semelhante às verificações de visibilidade de elementos. Veja como monitorar mensagens de erro:

await page.waitForFunction(() => {
    const errorContainer = document.querySelector('.error-messages');
    const hasErrors = errorContainer?.children.length > 0;
    const isVisible = errorContainer?.offsetParent !== null;
    return hasErrors && isVisible;
});

Você também pode acompanhar vários estados de validação de formulários usando condições de espera específicas:

Tipo de validaçãoCondição de esperaCaso de uso
Erros de campoVerifica a presença de uma classe de erroValidação de campo individual
Erros gerais do formulárioMonitora o contêiner de errosStatus geral do formulário
Mensagens de sucessoObserva a exibição de confirmaçõesConclusão do envio
Estados de carregamentoAcompanha o estado do botão de envioIndicação de processamento

Conclusão

Principais conclusões

O método waitForFunction no Puppeteer avalia condições em JavaScript até que retornem true, oferecendo controle preciso sobre interações em páginas dinâmicas [3].

Estes são alguns dos principais benefícios de usar waitForFunction:

  • Avaliação flexível: Lida com funções assíncronas para monitorar estados complexos da página [3].
  • Integração de contexto: Permite passar argumentos do Node.js diretamente para o contexto do navegador [3].
  • Lógica personalizada: Possibilita uma automação adaptada a condições específicas da página [2].

Essa abordagem é particularmente útil em casos nos quais os métodos de espera padrão não são suficientes. Por exemplo, em aplicações avançadas de página única, vários elementos podem carregar simultaneamente ou estados específicos de JavaScript podem precisar ser confirmados antes de avançar.

Puppeteer e Latenode em ação

A Latenode aproveita o waitForFunction para aprimorar a automação de fluxos. Ao integrar esse método, a Latenode criou um nó de monitoramento personalizado que verifica os status de sites e captura screenshots quando determinadas condições não são atendidas [7].

Veja um exemplo de como a Latenode usa waitForFunction para garantir que elementos críticos sejam totalmente renderizados antes de continuar:

await page.waitForFunction(() => {
    const element = document.querySelector('.tv-lightweight-charts');
    return element && element.offsetHeight > 0 && element.offsetWidth > 0;
});

Esse trecho aguarda que um elemento com a classe .tv-lightweight-charts não apenas apareça no DOM, mas também seja totalmente renderizado [2].

Para obter os melhores resultados ao usar Latenode com Puppeteer:

  • Defina valores de timeout adequados usando page.setDefaultTimeout().
  • Use blocos try-catch para um tratamento de erros robusto.
  • Acompanhe os tempos de execução para ajustar suas condições de espera.

References

FAQ

Frequently Asked Questions

waitForFunction verifica repetidamente uma condição JavaScript no contexto do navegador até que ela retorne um valor verdadeiro e, então, é concluída. Use-o quando o waitForSelector padrão não for suficiente para conteúdo dinâmico, estados personalizados do DOM ou verificações combinadas de API e DOM.

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