Ir para o conteúdo

Como esperar o carregamento da página no Selenium? Guia de um especialista

Deixe-me adivinhar – você começou a raspar um site com Selenium e de repente está enfrentando erros de tempo limite, exceções de elementos obsoletos e localizadores instáveis. Soa familiar?

Muitos de nós já estivemos lá! Na web dinâmica de hoje, aguardar adequadamente o carregamento completo das páginas antes de interagir é fundamental para uma automação confiável.

Neste guia abrangente de mais de 3200 palavras, aproveitarei meus mais de 5 anos como especialista profissional em web scraping para explorar os vários métodos e práticas recomendadas para uma espera tranquila no Selenium.

Quer você esteja apenas começando ou seja um profissional experiente, a lógica de espera robusta é uma ferramenta indispensável para estabilidade. Vamos mergulhar!

Por que você não pode simplesmente entrar correndo

Nos primeiros dias da web, as páginas eram em sua maioria HTML simples renderizadas sequencialmente. Os raspadores podem começar a extrair imediatamente no carregamento da página.

Mas a web de hoje é altamente dinâmica. De acordo com Pesquisa do Google, o tempo médio para pintar pela primeira vez é de 1.7s, mas o tempo médio para totalmente interativo é impressionante 15 segundos. É muito tempo para o conteúdo carregar.

Como raspador, se você se apressar demais, aqui estão alguns problemas comuns que você enfrentará:

  • Erros de clique no botão porque o elemento ainda não foi renderizado
  • Tentando ler dados de uma tabela que não carregou o conteúdo do servidor
  • Enviando texto para uma entrada que não está visível na tela
  • Raspar elementos vazios que serão preenchidos após o carregamento da página

Esses tipos de exceções são sintomas de que você precisa esperar mais para que a página fique pronta antes de interagir.

Em números: tempos de carregamento da página

Para entender quanto tempo precisaremos esperar, vejamos algumas métricas do mundo real sobre o desempenho do carregamento da página do Relatório sobre o estado da web de 2020 por Akamai:

  • Tempo médio para interação: 15s
  • Peso médio da página: 2744KB
  • Número médio de solicitações: 105
  • Média de imagens por página: 53
  • Bytes JavaScript por página: 453KB

As páginas são maiores e mais complexas hoje, com muito mais trabalho acontecendo após a resposta inicial. É fundamental que os raspadores esperem pela interatividade, não apenas pela primeira pintura.

Exceções comuns causadas pela falta de espera

Aqui estão algumas exceções específicas que podem ocorrer quando os elementos ainda não estão prontos:

  • StaleElementReferenceException – Elemento removido do DOM após busca
  • ElementNotInteractableException – Tentando clicar em elemento invisível
  • NoSuchElementException – A pesquisa expirou porque o elemento ainda não existe

Cada um deles indica que mais espera é exigida pelo raspador.

Esperas explícitas são suas amigas

Para evitar esses erros, precisamos aguardar a renderização completa da página antes de interagir. Existem duas abordagens principais no Selenium:

Esperas implícitas – Defina um tempo de espera global no driver

Esperas explícitas – Aguarde que condições específicas ocorram

Uma espera explícita é muito preferível a uma espera implícita na maioria dos casos. Vamos entender o porquê.

Esperas implícitas: a abordagem da marreta

As esperas implícitas definem um tempo limite no driver para pesquisar o DOM ao encontrar elementos. Isso significa que sempre que você ligar:

driver.find_element_by_id(‘some-id‘)

O driver tentará novamente até a duração da espera implícita para localizar esse elemento antes de lançar uma NoSuchElementException.

Você pode usá-lo como:

driver = webdriver.Chrome()
driver.implicitly_wait(10) 

Agora todas as pesquisas serão repetidas por até 10 segundos para encontrar elementos se não estiverem presentes imediatamente.

A desvantagem é que ele espera por cada localizador, mesmo aqueles que não são necessários para determinar a disponibilidade da página. Isso pode realmente desacelerar o seu raspador.

Pense em esperas implícitas como adicionar um sono de 5 segundos a cada busca de elemento. Isso soma!

A precisão das esperas explícitas

As esperas explícitas nos permitem esperar com precisão por condições específicas que indiquem prontidão antes de prosseguir.

As ideias principais são:

  • Espere apenas quando necessário – Evite esperas desnecessárias não relacionadas à prontidão da página
  • Condições precisas – Aguarde por elementos ou estados exatos, não apenas pelo tempo geral
  • Flexibilidade – Personalize a lógica de espera por página com diferentes condições
  • legível – Intenção fácil de entender ao revisitar código antigo

Aqui está um exemplo típico de espera pelo aparecimento de um elemento:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait 

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "myDynamicElement"))
)

Isso pausa a execução até que o elemento com ID "myDynamicElement" seja carregado ou 10 segundos se passem.

Outras condições úteis esperadas fornecido por Selênio incluem:

  • title_contains() – Aguarde a atualização do título da página
  • staleness_of() – Aguarde até que o elemento não esteja mais anexado ao DOM
  • element_to_be_clickable() – Aguarde até que o elemento fique visível e habilitado

Explícito bate implícito: um exemplo do mundo real

Vamos comparar as duas esperas com um exemplo real.

Digamos que estou copiando um site que possui uma barra de navegação, painel lateral esquerdo e conteúdo principal.

O elemento-chave que preciso esperar é um ID "#main-content" onde meus dados são renderizados.

Com espera implícita:

  • 10 segundos adicionados a cada pesquisa de elemento, mesmo que não seja necessário
  • Ainda propenso a erros de elementos obsoletos se for muito rápido

Com espera explícita:

  • Aguarde apenas quando necessário pelo seletor #main-content
  • Evite esperas desnecessárias na navegação e no painel lateral
  • Aguarde especificamente até que os dados sejam carregados antes de continuar

Ao esperar seletivamente por uma única condição de prontidão como um elemento, evito atrasos desnecessários.

Padrões para esperas explícitas eficazes

Agora que você está convencido de que as esperas explícitas são a melhor opção, vamos explorar algumas práticas recomendadas para usá-las de maneira eficaz.

Esperas de carregamento de página

Aguardar o estado de prontidão do documento é uma técnica comum para determinar quando o carregamento está completo:

WebDriverWait(driver, 10).until(
   lambda d: d.execute_script(‘return document.readyState‘) == ‘complete‘
)

Isso pesquisa o navegador até que o estado pronto seja "concluído", indicando que todos os ativos estão carregados.

Um padrão mais leve está atento a elementos específicos de alto nível:

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "main-content"))
) 

Isso acontece quando a seção de conteúdo principal é carregada, sem esperar por todo o resto.

Esperas por ação

Você também pode esperar antes de realizar uma ação, como clicar em um elemento:

menu = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "top-menu"))
)

submenu = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, "submenu"))
)

submenu.click()

Isso garante que o menu superior e o submenu estejam prontos antes de clicar.

Esperas paralelas

Aguardar várias condições pode confirmar que a página está pronta:

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "header")),
    EC.presence_of_element_located((By.ID, "footer")), 
    EC.presence_of_element_located((By.ID, "main"))
)

Exigir o carregamento do cabeçalho, rodapé e conteúdo principal reduz falsos positivos.

Esperas encadeadas e aninhadas

Para cenários avançados, você também pode aninhar esperas:

element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "dropdown"))
)

menu = WebDriverWait(element, 10).until(
    EC.presence_of_element_located((By.ID, "menu"))  
)

Isso espera primeiro por um elemento pai e depois por um elemento filho dentro dele.

Esperas de votação AJAX

Alguns sites são carregados por meio de solicitações AJAX contínuas. Você pode fazer um loop aguardando alterações:

while True:

    current_count = driver.find_element_by_id(‘result-count‘).text

    # If count changed since last check, page is still loading
    if current_count != previous_count:
        previous_count = current_count
        continue 

    break # Page loaded!

Isso pesquisa um elemento em busca de alterações para detectar o carregamento.

Esperas assíncronas

Em frameworks assíncronos como o asyncio, você pode aguardar promessas:

await page.waitForSelector(‘#content‘)

A sintaxe é um pouco diferente, mas fornece espera assíncrona.

Combinação Implícita + Explícita

Você pode até combinar esperas implícitas e explícitas:

driver.implicitly_wait(10) 

my_element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "my-element"))
)

Desta forma você tem uma espera global e também específica. Apenas certifique-se de que eles usem durações razoáveis.

Escolhendo localizadores que sinalizam prontidão

Ao selecionar os localizadores pelos quais esperar, você deseja elementos que correspondam a estes critérios:

  • Aparecer tarde no processo de carregamento
  • Tenha IDs ou classes exclusivas que não serão alteradas
  • Localizado acima da dobra para verificações rápidas
  • É improvável que sejam realocados devido a mudanças no site
  • Não seja removido do DOM e fique obsoleto

Alguns exemplos comuns são:

  • Cabeçalho principal ou navegação carregada após os ativos
  • Contêineres ou widgets de conteúdo principal
  • Rodapé da página
  • Pequenos elementos dinâmicos da interface do usuário, como botões

Indicadores de carga, como giradores, também são ótimos gatilhos de espera quando desaparecem.

Ajustando tempos limite para espera ideal

Definir tempos limite muito longos pode realmente retardar o seu raspador – mas muito curtos podem causar falhas instáveis.

Aqui estão algumas práticas recomendadas sobre durações de ajuste:

  • Defina tempos limite de carregamento de página mais longos, em torno de 10 a 20 segundos.
  • Use tempos limite mais curtos, como 3 a 5 segundos para elementos individuais.
  • Considere o desempenho do navegador, móvel versus desktop.
  • Considere a latência da rede, banda larga versus 3G.
  • Monitore erros de tempo limite e ajuste mais alto, se necessário.
  • Analise a cascata de carregamento da página para tempos de carregamento típicos.
  • Reserve 1-2 segundos extras como buffer.
  • Padronize esperas semelhantes em sua base de código.

À medida que você raspa mais páginas, você terá uma melhor intuição sobre as esperas ideais pela confiabilidade.

Lidando com falhas de espera e tempo limite

Mesmo com esperas robustas, você ainda poderá encontrar tempos limite ocasionais. Aqui estão algumas maneiras de lidar com eles:

  • Detalhes de depuração de log – Adicionar impressões ajuda a diagnosticar onde as esperas falham.
  • Tentar novamente no tempo limite – Tentar novamente esperas explícitas curtas até 3 vezes em caso de falha.
  • Aumentar o tempo limite – Se ocorrerem muitos tempos limite, aumente gradativamente as esperas.
  • Use tentar/exceto – Capture exceções específicas como StaleElementReference.
  • Desativar em caso de falha – Você pode pular esperas após falhas repetidas para permitir que os testes continuem.

Com alguma resiliência incorporada, esses problemas esporádicos não quebrarão seu raspador.

Esperando em outros idiomas

Até agora, os exemplos foram em Python, mas esperas explícitas estão disponíveis em todas as linguagens:

  • Java - WebDriverWait e ExpectedConditions
  • C# - WebDriverWait e ExpectedConditions
  • Ruby - WebDriver::Wait e ExpectedConditions
  • JavaScript - browser.wait() e métodos utilitários

Os conceitos são muito semelhantes – apenas a sintaxe difere ligeiramente.

Além do Selenium: mais ferramentas de espera

Existem também algumas outras bibliotecas de espera úteis além do Selenium:

  • Horário - time.sleep() é simples, mas pausa toda a execução.
  • Tentar novamente - A Tentar novamente o pacote faz novas tentativas e espera com facilidade.
  • Aiohttp - await response.text() aguarda a conclusão das chamadas de rede.
  • Sopa linda - BeautifulSoup(page.content, features="lxml") esperará pela análise completa.
  • Escamoso - yield scrapy.Request(url, callback=self.parse) é assíncrono.

Misturá-los com Selenium fornece esperas robustas em seu código.

Em resumo: espere bem e descarte com segurança

Para encerrar, aqui estão cinco conclusões principais:

  1. Use esperas explícitas – Eles evitam tempos limite desnecessários e visam condições específicas.

  2. Aguarde vários sinais – Combine esperas por cabeçalho, corpo, rodapé, etc. para confirmar a disponibilidade da página.

  3. Ajuste os tempos limite com sabedoria – Defina valores com base em dados reais de carregamento de página para otimizar atrasos.

  4. Padronize as esperas – Reutilize padrões consistentes em sua base de código.

  5. Adicione resiliência – Implemente novas tentativas e tratamento de falhas para contabilizar páginas dinâmicas.

Esperar pode parecer tedioso no início. Mas investir em uma lógica de espera robusta irá recompensá-lo com scrapers confiáveis ​​e resilientes, preparados para a web moderna.

Esperançosamente, esses padrões e dicas extraídos de meus anos como especialista profissional em web scraping irão ajudá-lo a esperar com sucesso. Sucata!

Junte-se à conversa

O seu endereço de e-mail não será publicado. Os campos obrigatórios são marcados com *