Uma plataforma de baixo código que combina a simplicidade sem código com o poder do código completo 🚀
Comece gratuitamente
Otimizando estratégias de espera no Puppeteer: um guia completo para métodos de espera
20 de março de 2025
.
9
min ler

Otimizando estratégias de espera no Puppeteer: um guia completo para métodos de espera

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

Lutando com Marionetista scripts com tempo limite esgotado ou falhando? Veja como consertar.

Marionetista, um Node.js biblioteca para controle Chrome, é poderoso para automação web. Mas conteúdo dinâmico e páginas orientadas por API podem tornar o tempo complicado. Estratégias de espera adequadas garantem que seus scripts funcionem de forma confiável e eficiente.

Key Takeaways:

  • waitForSelector(): Aguarda que elementos apareçam (por exemplo, botões ou formulários).
  • waitForNavigation(): Lida com transições de página e garante carregamentos completos da página.
  • waitForNetworkIdle(): Ideal para páginas com uso intenso de API, aguarda a conclusão de todas as solicitações de rede.
  • Condições Personalizadas: Usar waitForFunction() para cenários complexos como conteúdo dinâmico ou animações.

Dicas rápidas:

  • Ajuste os tempos limite usando page.setDefaultTimeout() para lidar com páginas de carregamento lento.
  • Combine vários métodos de espera com Promise.all() para maior confiabilidade.
  • Depure erros de espera monitorando solicitações de rede ou verificando a visibilidade dos elementos.

Comece com essas estratégias para tornar seus scripts do Puppeteer mais rápidos, confiáveis ​​e mais adequados para aplicativos web modernos.

Como esperar / dormir por N segundos em titereiro?

titereiro

Como o marionetista lida com a espera

Ao usar o Puppeteer para automação, entender como ele lida com a espera é essencial para criar scripts que funcionem de forma confiável. O Puppeteer inclui configurações de tempo limite padrão para evitar que os scripts parem indefinidamente, mas essas configurações podem precisar ser ajustadas ou suplementadas com estratégias personalizadas para cenários mais complexos.

Configurações de tempo limite integradas

O Puppeteer define tempos limite padrão para gerenciar tarefas como navegação, seleção de elementos, solicitações de rede, consultas XPath e funções personalizadas. Isso garante que seus scripts não travem indefinidamente se algo der errado ou demorar muito.

Você pode modificar esses padrões com page.setDefaultTimeout(timeout). Por exemplo, se seu aplicativo levar mais tempo para carregar recursos complexos, aumentar o tempo limite pode ajudar seu script a evitar sair muito cedo. Embora convenientes, essas configurações padrão podem nem sempre se alinhar ao comportamento de aplicativos dinâmicos.

Desafios com configurações padrão

Os aplicativos da web modernos geralmente dependem do carregamento dinâmico de conteúdo, o que pode tornar os mecanismos de espera padrão do Puppeteer insuficientes. O Puppeteer oferece duas condições de ociosidade de rede para ajudar a gerenciar isso:

  • networkidle0: Aguarda até que não haja conexões de rede por 500 ms.
  • networkidle2: Aguarda até que não haja mais de 2 conexões de rede por 500 ms.

No entanto, essas condições nem sempre correspondem ao comportamento dos aplicativos da web. Problemas comuns incluem:

  • Carregamento de conteúdo por meio de JavaScript após o DOM estar pronto
  • Elementos atualizando em resposta a chamadas de API
  • Rolagem infinita carregando conteúdo adicional
  • Aplicativos de página única atualizando visualizações dinamicamente

Para lidar com esses desafios, tente usar um try-catch bloco para gerenciar erros de tempo limite. Isso permite que seu script evite falhas abruptas e aplique estratégias de fallback quando necessário. Em vez de depender de atrasos fixos, considere criar condições de espera com base no status real da página. Essa abordagem é mais flexível e mais adequada para ambientes dinâmicos.

Principais métodos de espera no Puppeteer

O Puppeteer oferece três métodos principais para lidar com detecção de elementos, navegação de página e atividade de rede. Esses métodos ajudam a gerenciar interações de forma eficaz, especialmente em ambientes web dinâmicos.

utilização waitForSelector()

A waitForSelector() método pausa a execução até que um elemento específico apareça na página. Isso é especialmente útil para conteúdo carregado dinamicamente em Single Page Applications (SPAs).

Veja como você pode usá-lo:

// Wait for an element to appear
await page.waitForSelector('.button-class');

// Wait for the element to be visible
await page.waitForSelector('.button-class', { visible: true });

// Set a custom timeout
await page.waitForSelector('.button-class', { timeout: 5000 });

Este método garante que seu script interaja com elementos somente quando eles estiverem prontos.

utilização waitForNavigation()

A waitForNavigation() O método é projetado para lidar com transições de página. Ele espera que a página carregue completamente após eventos como clicar em um link ou enviar um formulário.

await Promise.all([
  page.waitForNavigation(),
  page.click('.navigation-link')
]);

Você pode personalizar seu comportamento com opções:

Opção Descrição melhor para
waitUntil: 'load' Aguarda o evento de carregamento da página ser disparado Páginas estáticas
waitUntil: 'domcontentloaded' Aguarda que o DOM seja totalmente carregado Interações rápidas
waitUntil: 'networkidle0' Aguarda até que nenhuma solicitação de rede esteja ativa Aplicações complexas

Essa flexibilidade garante um manuseio de navegação suave para diferentes cenários.

utilização waitForNetworkIdle()

A waitForNetworkIdle() opção é ideal para monitorar a atividade da rede. Ela espera até que a rede esteja completamente ociosa ou quase ociosa.

// Wait for all network requests to finish
await page.goto(url, { waitUntil: 'networkidle0' });

// Allow up to 2 active connections (e.g., WebSockets)
await page.goto(url, { waitUntil: 'networkidle2' });

Por exemplo:

try {
  await page.waitForNavigation({ waitUntil: 'networkidle0', timeout: 30000 });
  await page.waitForSelector('.dynamic-content', { visible: true });
} catch (error) {
  console.error('Loading timeout occurred');
}

Use networkidle0 para conclusão completa da solicitação ou networkidle2 nos casos em que as conexões em segundo plano podem permanecer ativas.

Esses métodos são essenciais para criar scripts de automação web confiáveis, garantindo que suas interações com páginas web sejam consistentes e eficientes.

sbb-itb-23997f1

Técnicas de espera complexas

Às vezes, métodos básicos de espera simplesmente não funcionam. Para cenários mais intrincados, técnicas avançadas são o caminho a seguir.

Condições de espera personalizadas

Quando os seletores padrão não forem suficientes, você pode usar waitForFunction() para definir condições de espera personalizadas com base no estado da página ou em expressões JavaScript.

// Wait for a specific number of elements to load
await page.waitForFunction(() => {
  return document.querySelectorAll('.product-card').length > 5;
});

// Wait for dynamic content and validate its state
await page.waitForFunction(
  (expectedText) => {
    const element = document.querySelector('.status');
    return element && element.innerText.includes(expectedText);
  },
  {},
  'Ready'
);

Você também pode combinar várias condições para cenários mais complexos:

await page.waitForFunction(() => {
  const isLoaded = document.readyState === 'complete';
  const hasContent = document.querySelector('.content')?.innerHTML.length > 0;
  const noSpinner = !document.querySelector('.loading-spinner');
  return isLoaded && hasContent && noSpinner;
});

Agora vamos dar um passo adiante e lidar com diversas condições simultaneamente.

Vários métodos de espera

Para aplicações complexas, muitas vezes você precisa esperar por várias condições ao mesmo tempo. Usando Promise.all() pode ajudar a gerenciá-los de forma eficiente.

Exemplo de envio de formulário dinâmico:

// Handle form submission with multiple conditions
const submitForm = async () => {
  await Promise.all([
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
    page.waitForFunction(() => !document.querySelector('.processing')),
    page.click('#submit-button')
  ]);
};

Lidando com as condições da corrida:

Às vezes, você precisa prosseguir assim que a primeira condição for atendida. Para isso, você pode usar Promise.race():

// Wait for either a success or error message
const waitForResponse = async () => {
  await Promise.race([
    page.waitForSelector('.success-message'),
    page.waitForSelector('.error-message')
  ]);
};

Cenários de carregamento complexos:

Veja um exemplo de gerenciamento de carregamento de conteúdo dinâmico com múltiplas condições:

const loadDynamicContent = async () => {
  await page.click('.load-more');
  await Promise.all([
    page.waitForFunction(() => {
      return window.scrollY + window.innerHeight >= document.documentElement.scrollHeight;
    }),
    page.waitForSelector('.new-items', { visible: true }),
    page.waitForFunction(() => {
      return document.querySelectorAll('.item').length > 10;
    })
  ]);
};

Essas técnicas ajudam você a criar scripts de automação mais fortes, capazes de lidar com aplicativos web complexos com operações assíncronas e conteúdo dinâmico.

Tornando os métodos de espera mais rápidos

Melhorar os métodos de espera pode aumentar significativamente a velocidade e a confiabilidade dos scripts de automação. Ao combinar técnicas manuais mais inteligentes com estratégias orientadas por IA, você pode obter uma execução mais rápida sem sacrificar a estabilidade.

Velocidade vs. Estabilidade

Um fator-chave na otimização de métodos de espera é entender como sua página carrega. Adaptar os tempos de espera para corresponder ao comportamento da página no mundo real é essencial.

// Set a default timeout for all operations
page.setDefaultTimeout(30000);

// Use efficient wait conditions
const waitForContent = async () => {
  try {
    await page.waitForSelector('.content', {
      visible: true,
      timeout: 5000 // Shorter timeout for specific elements
    });
  } catch (error) {
    console.error('Content load timeout');
    throw error;
  }
};

Para carregamentos de página completos, use 'networkidle0', e para conteúdo dinâmico, use 'networkidle2'. Isso equilibra velocidade com confiabilidade.

"Embora esperar um período fixo de tempo seja uma prática ruim, no mundo real é difícil encontrar uma solução que funcione bem em todos os casos." - Dmytro Krasun

Outra maneira de aumentar o desempenho é desabilitando recursos não essenciais. No entanto, para uma eficiência ainda maior, considere soluções alimentadas por IA.

Lógica de espera com tecnologia de IA

A IA pode levar a otimização de espera para o próximo nível, analisando o comportamento da página e ajustando as condições dinamicamente. Ferramentas como Nó latente use IA para ajustar estratégias de espera.

// AI-enhanced wait logic example
const smartWait = async () => {
  await page.waitForFunction(() => {
    const contentReady = document.querySelector('.content')?.offsetHeight > 0;
    const apiLoaded = window._apiData && Object.keys(window._apiData).length > 0;
    const animationsComplete = !document.querySelector('.loading-animation');

    return contentReady && apiLoaded && animationsComplete;
  }, {
    timeout: 15000,
    polling: 'mutation' // Optimized polling strategy
  });
};

Para cenários mais complexos, a espera paralela com tempos limite otimizados pode mudar o jogo:

// Parallel waiting with timeout optimization
const optimizedLoad = async () => {
  const timeoutPromise = new Promise((_, reject) => 
    setTimeout(() => reject(new Error('Operation timed out')), 10000)
  );

  try {
    await Promise.race([
      Promise.all([
        page.waitForSelector('.content'),
        page.waitForFunction(() => window.dataLoaded === true),
        page.waitForNetworkIdle({
          idleTime: 500,
          timeout: 8000
        })
      ]),
      timeoutPromise
    ]);
  } catch (error) {
    console.error('Loading failed:', error.message);
    throw error;
  }
};

Esses métodos ajudam seus scripts a se adaptarem a diversas condições de rede e tempos de carregamento de página, garantindo velocidade e confiabilidade.

Corrigindo problemas de espera

Para garantir que seus scripts de automação sejam executados sem problemas, é importante corrigir erros de tempo limite após otimizar os métodos de espera.

Gerenciando Tempos Limites

Erros de tempo limite acontecem quando uma página demora mais para carregar do que o esperado. Por padrão, o Puppeteer define um tempo limite de 30 segundos, o que pode não ser suficiente para conexões de internet mais lentas ou páginas pesadas.

Veja como você pode ajustar as configurações de tempo limite:

// Set a global timeout for all operations
await page.setDefaultTimeout(60000); // 60 seconds

// Set a specific timeout for navigation
await page.setDefaultNavigationTimeout(60000); // 60 seconds

try {
  await page.waitForSelector('.dynamic-content', {
    visible: true,
    timeout: 10000 // 10 seconds
  });
} catch (error) {
  console.error('Element wait timeout:', error.message);
  // Consider adding a fallback strategy here
}

Para cenários mais complexos, tente timeouts incrementais. Esta abordagem tenta novamente a operação com intervalos de tempo crescentes:

const waitWithRetry = async (selector, maxAttempts = 3) => {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      await page.waitForSelector(selector, {
        timeout: 5000 * attempt // Increase timeout with each attempt
      });
      return true;
    } catch (error) {
      if (attempt === maxAttempts) throw error;
      console.warn(`Attempt ${attempt} failed, retrying...`);
    }
  }
};

Encontrando erros de espera

Para depurar erros de espera, use técnicas de monitoramento sistemático. Por exemplo:

// Monitor network requests for potential timing issues
await page.setRequestInterception(true);
page.on('request', request => {
  console.log(`${request.method()} ${request.url()}`);
  request.continue();
});

// Check if an element is visible on the page
const elementVisibilityCheck = async (selector) => {
  const isVisible = await page.evaluate((sel) => {
    const element = document.querySelector(sel);
    if (!element) return false;

    const style = window.getComputedStyle(element);
    return style.display !== 'none' && 
           style.visibility !== 'hidden' && 
           style.opacity !== '0';
  }, selector);

  return isVisible;
};

Erros comuns de espera e suas soluções:

Tipo de Erro Causar Solução
Tempo limite de navegação Carregamento de página pesado Aumentar o tempo limite para 60000 ms
Elemento não encontrado Conteúdo dinâmico Use waitForFunction com um observador de mutação
Tempo limite de inatividade da rede Várias chamadas de API Use o networkidle2 estratégia
Falha na interação Estado do elemento Adicionar verificações para interatividade do elemento

Aqui está um exemplo robusto para lidar com erros de espera de forma eficaz:

const robustWait = async (page, selector) => {
  try {
    const element = await page.waitForSelector(selector, {
      visible: true,
      timeout: 15000 // 15 seconds
    });

    // Ensure the element is interactive
    await page.waitForFunction(
      (sel) => {
        const el = document.querySelector(sel);
        return el && !el.disabled && el.getBoundingClientRect().height > 0;
      },
      { timeout: 5000 }, // Additional check timeout
      selector
    );

    return element;
  } catch (error) {
    console.error(`Wait error: ${error.message}`);
    throw new Error(`Element ${selector} isn't ready`);
  }
};

Essas estratégias podem ajudar você a resolver e depurar problemas de tempo limite de forma eficaz, garantindo que seus scripts lidem com cenários variados com elegância.

Conclusão

Obter o equilíbrio certo entre velocidade e estabilidade é essencial ao usar estratégias de espera no Puppeteer. Escolher o método de espera certo garante que suas interações automatizadas na web sejam executadas sem problemas e forneçam resultados confiáveis.

Aqui está uma rápida visão geral das estratégias comuns de espera e quando usá-las:

Estratégia de espera Melhor caso de uso Benefício principal
waitForSelector() Elementos dinâmicos da IU Confirma que o elemento está presente antes do uso
waitForNavigation() Transições de página Mantém seu script sincronizado com as alterações de página
waitForNetworkIdle() Páginas com API pesada Confirma que todas as solicitações de rede foram concluídas
Condições de espera personalizadas Cenários complexos Oferece controle preciso sobre o tempo

Para conteúdo dinâmico, combinando waitForSelector() com condições de espera personalizadas geralmente funciona melhor do que ficar preso a timeouts padrão. Essa abordagem dá a você mais controle e reduz as chances de erros.

Usar ferramentas como o Latenode pode simplificar o processo de configuração de estratégias de espera eficazes, ajudando você a melhorar a velocidade e a confiabilidade. Além disso, definir tempos limite com page.setDefaultTimeout() pode ajudar a evitar falhas de script e, ao mesmo tempo, manter sua automação eficiente.

Posts Relacionados do Blog

Blogs relacionados

Caso de uso

Apoiado por