CodeGym /Curso de Java /Python SELF ES /Manejo de errores en web scraping

Manejo de errores en web scraping

Python SELF ES
Nivel 32 , Lección 4
Disponible

Si llegaste hasta esta lección, significa que ya tienes una buena idea de cómo funciona el web scraping y cómo usar la fantástica librería BeautifulSoup para extraer los datos que necesitas de un HTML. Sin embargo, en el mundo del web scraping, no todo es tan perfecto como en los tutoriales. A veces, nuestro sueño de recolectar datos se convierte en una lucha contra los errores. Así que hablemos de cómo superar los obstáculos y hacer que nuestro scraper sea lo más resistente posible.

1. Errores comunes en web scraping

Error 404 y otros errores HTTP

El clásico problema: intentas acceder a una página y, en lugar del contenido, te devuelven un orgulloso "404 Not Found". Esto puede pasar porque la página fue eliminada o movida. Otros errores HTTP comunes incluyen 403 (Forbidden), 500 (Internal Server Error) y 503 (Service Unavailable).

Cambios en la estructura del HTML

Invertiste un montón de tiempo escribiendo código para extraer datos, y al día siguiente el sitio decidió "lucirse" y cambió su estructura HTML. ¡Ay, otra vez a reescribir todo!

Restricciones en la cantidad de solicitudes

Algunos sitios empiezan a sospechar algo raro cuando los scrapers les hacen demasiadas solicitudes durante todo el día. En el mejor de los casos, te bloquearán por un tiempo, y en el peor, para siempre.

Tiempos de espera y timeouts

A veces, las páginas tardan mucho en cargar, y tu script puede fallar si el tiempo de espera supera el timeout predeterminado.

2. Métodos para manejar errores

Uso de try-except

Tus scripts no deberían fallar ante cualquier sorpresa. Agregar bloques try-except te ayuda a capturar errores y hacer que tu web scraper no se detenga, sino que siga funcionando como si nada.

Python

    import requests
    from bs4 import BeautifulSoup
    
    url = 'http://example.com/some-nonexistent-page'
    
    try:
        response = requests.get(url)
        response.raise_for_status()  # Lanza HTTPError para respuestas malas
    except requests.exceptions.HTTPError as errh:
        print("Error HTTP:", errh)
    except requests.exceptions.ConnectionError as errc:
        print("Error de Conexión:", errc)
    except requests.exceptions.Timeout as errt:
        print("Error de Timeout:", errt)
    except requests.exceptions.RequestException as err:
        print("OOps: Algo más ocurrió", err)
        

Un buen script no solo captura la excepción, sino que también tiene una acción de respuesta para cada tipo de error. ¿Te bloquearon por IP? Cambias al siguiente proxy. ¿El sitio falló? Mientras tanto, extraes datos de otro sitio. Si no se encuentran algunos elementos en la página que deberían estar, puedes notificar al propietario del scraper para que actualice el script y enviarle un correo electrónico.

Logging

"¿Para qué los logs?" — preguntarás. Porque los logs son tus segundos ojos. Te ayudarán a entender qué salió mal y a corregir el error lo más rápido posible.

Python

import logging

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

try:
    # Tu código de web scraping
    pass
except Exception as e:
    logging.error("Ocurrió una excepción", exc_info=True)
    

Uso de timeouts y reintentos

A veces, lo único que necesitas es esperar un poco e intentar de nuevo. Para este propósito, los timeouts y los retries son ideales.

Python

try:
    response = requests.get(url, timeout=5)
    response.raise_for_status()
except requests.exceptions.Timeout:
    print("Timeout ocurrió. Reintentando...")
    # Reintentar la solicitud o realizar otra acción
    

3. Ejemplos de web scraping resistente

Un scraper simple con manejo de errores

Hagamos un pequeño pero confiable scraper que pueda manejar algunos errores comunes.

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("Error HTTP: %s", errh)
    except requests.exceptions.ConnectionError as errc:
        logging.error("Error de Conexión: %s", errc)
    except requests.exceptions.Timeout as errt:
        logging.warning("Timeout ocurrió. Reintentando...")
        time.sleep(1)  # Esperar un poco e intentar de nuevo
        return fetch_html(url)
    except requests.exceptions.RequestException as err:
        logging.error("OOps: Algo más ocurrió %s", err)
    return None

html_content = fetch_html(url)
if html_content:
    soup = BeautifulSoup(html_content, 'html.parser')
    # Tu código de extracción de datos
else:
    print("No se pudo obtener el contenido de la página.")
    

Guardar datos por partes

Para no perder los datos que ya has extraído en caso de un fallo, guárdalos por partes. Por ejemplo, si estás extrayendo información de una lista de páginas, al guardar los resultados a medida que avanzas, minimizas el riesgo de perder datos.

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)
    

De esta forma, aunque tu script falle a mitad del trabajo, no perderás todos los datos y podrás continuar desde el último estado guardado.

La página que estás scrapeando podría cambiar parcialmente y la mayor parte de los datos seguirían estando disponibles. Sería una pena cancelar el scraping y perder datos valiosos solo porque falta un pequeño porcentaje de ellos.

1
Опрос
Extracción de datos,  32 уровень,  4 лекция
недоступен
Extracción de datos
Extracción de datos
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION