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áginastaleness_of()
– Aguarde até que o elemento não esteja mais anexado ao DOMelement_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
eExpectedConditions
- C# -
WebDriverWait
eExpectedConditions
- Ruby -
WebDriver::Wait
eExpectedConditions
- 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:
Use esperas explícitas – Eles evitam tempos limite desnecessários e visam condições específicas.
Aguarde vários sinais – Combine esperas por cabeçalho, corpo, rodapé, etc. para confirmar a disponibilidade da página.
Ajuste os tempos limite com sabedoria – Defina valores com base em dados reais de carregamento de página para otimizar atrasos.
Padronize as esperas – Reutilize padrões consistentes em sua base de código.
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!