CodeGym /Cursos /Python SELF PT /Tratamento de erros no web scraping

Tratamento de erros no web scraping

Python SELF PT
Nível 32 , Lição 4
Disponível

Se você chegou nessa aula, significa que já entende bem como o web scraping funciona e como usar o incrível BeautifulSoup para extrair os dados necessários do HTML. Mas, no mundo do web scraping, nem tudo é simples como nos livros. Às vezes, nosso sonho de coletar dados vira uma batalha com erros. Então, bora falar sobre como contornar esses desafios e deixar nosso scraper o mais resistente possível.

1. Erros comuns no web scraping

Erro 404 e outros erros HTTP

Problema clássico: você tenta acessar uma página e recebe um orgulhoso "404 Not Found" no lugar do conteúdo. Isso pode acontecer porque a página foi removida ou movida. Outros erros HTTP comuns incluem 403 (Forbidden), 500 (Internal Server Error) e 503 (Service Unavailable).

Mudança na estrutura do HTML

Você gastou um tempão escrevendo o código para extrair os dados, e no dia seguinte o site resolve "se exibir" e muda a estrutura do HTML. Ixi, lá vamos nós ter que reescrever tudo!

Limites de requisições

Alguns sites começam a desconfiar quando ficam sendo "acariciados" o dia todo por scrapers. No melhor cenário, você será bloqueado por um tempo; no pior, para sempre.

Tempo de espera e timeouts

Às vezes, as páginas demoram para carregar, e seu script pode quebrar se o tempo de espera ultrapassar o timeout padrão.

2. Métodos para lidar com erros

Uso de try-except

Seus scripts não devem quebrar com qualquer imprevisto. Adicionar blocos try-except ajuda a capturar os erros e fazer com que seu scraper continue funcionando como se nada tivesse acontecido.

Python

    import requests
    from bs4 import BeautifulSoup
    
    url = 'http://example.com/some-nonexistent-page'
    
    try:
        response = requests.get(url)
        response.raise_for_status()  # Lança HTTPError para respostas ruins
    except requests.exceptions.HTTPError as errh:
        print("Erro HTTP:", errh)
    except requests.exceptions.ConnectionError as errc:
        print("Erro de Conexão:", errc)
    except requests.exceptions.Timeout as errt:
        print("Erro de Timeout:", errt)
    except requests.exceptions.RequestException as err:
        print("OOps: Algo mais aconteceu", err)
        

Um bom script não apenas captura uma exceção - ele tem uma ação correspondente para cada tipo de erro. Foi banido por IP? Muda para o próximo proxy. O site caiu? Enquanto isso, você trabalha em outro. Se algum elemento esperado não for encontrado na página, você pode notificar o proprietário do scraper sobre a necessidade de atualizar o código e enviar um email para ele.

Log de eventos

"Pra que servem esses logs?" — você pode perguntar. Eles são como sua segunda visão. Os logs ajudam a entender o que deu errado e corrigir o problema o mais rápido possível.

Python

import logging

logging.basicConfig(filename='scraper.log', level=logging.INFO)

try:
    # Seu código de scraping
    pass
except Exception as e:
    logging.error("Exceção ocorrida", exc_info=True)
    

Uso de timeouts e retries

Às vezes, tudo o que precisa é esperar um pouquinho e tentar novamente. Para isso, timeouts e retries são bem úteis.

Python

try:
    response = requests.get(url, timeout=5)
    response.raise_for_status()
except requests.exceptions.Timeout:
    print("Timeout ocorrido. Tentando novamente...")
    # Refazer a requisição ou tomar outra ação
    

3. Exemplos de scraping resiliente

Scraper simples com tratamento de erros

Vamos criar um pequeno, mas confiável scraper que sabe lidar com alguns erros comuns.

Python

import requests
from bs4 import BeautifulSoup
import time
import logging

logging.basicConfig(filename='scraper.log', level=logging.INFO)

url = 'http://example.com/some-nonexistent-page'

def fetch_html(url):
    try:
        response = requests.get(url, timeout=5)
        response.raise_for_status()
        return response.text
    except requests.exceptions.HTTPError as errh:
        logging.error("Erro HTTP: %s", errh)
    except requests.exceptions.ConnectionError as errc:
        logging.error("Erro de Conexão: %s", errc)
    except requests.exceptions.Timeout as errt:
        logging.warning("Timeout ocorrido. Tentando novamente...")
        time.sleep(1)  # Espera um pouco e tenta de novo
        return fetch_html(url)
    except requests.exceptions.RequestException as err:
        logging.error("OOps: Algo mais aconteceu %s", err)
    return None

html_content = fetch_html(url)
if html_content:
    soup = BeautifulSoup(html_content, 'html.parser')
    # Seu código para extrair os dados
else:
    print("Falha ao recuperar o conteúdo da página.")
    

Salvamento de dados em partes

Para não perder os dados já extraídos em caso de falha, salve-os em partes. Por exemplo, se você está extraindo informações de uma lista de páginas, salve os resultados conforme avança, para minimizar o risco de perda de dados.

Python

import csv

def save_to_csv(data, filename='data.csv'):
    with open(filename, mode='a', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(data)
    

Assim, mesmo que seu script quebre no meio do trabalho, você não perde todos os dados e pode continuar de onde parou.

A página que você está parseando pode mudar parcialmente, mas a maior parte dos dados ainda estará disponível. Não seria legal cancelar o parsing e perder dados valiosos por causa de uma pequena porcentagem de informações faltantes.

1
Pesquisa/teste
Extração de Dados, nível 32, lição 4
Indisponível
Extração de Dados
Extração de Dados
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION