El web scraping es un método eficaz para extraer datos de la web. Muchos desarrolladores prefieren utilizar la biblioteca de peticiones de Python para llevar a cabo proyectos de web scraping, ya que es sencilla y eficaz. Sin embargo, por muy buena que sea, la biblioteca de peticiones tiene sus limitaciones. Un problema típico que podemos encontrar en el web scraping son las peticiones fallidas, que a menudo conducen a una extracción de datos inestable. En este artículo, recorreremos el proceso de implementación de reintentos de solicitudes en Python, para que puedas manejar los errores HTTP y mantener tus scripts de web scraping estables y confiables.
Primero vamos a configurar nuestro entorno. Asegúrate de tener Python instalado y cualquier IDE de tu elección. Luego instala la librería requests si no la tienes ya.
pip install requests
Una vez instalado, enviemos una petición a ejemplo.com utilizando el módulo requests de Python. Aquí hay una función simple que hace precisamente eso:
import requests
def send_request(url):
"""
Envía una petición HTTP GET a la URL especificada e imprime el código de estado de la respuesta.
Parameters:
url (str): La URL a la que enviar la solicitud.
"""
response = requests.get(url)
print('Response Status Code: ', response.status_code)
send_request('https://example.com')
A continuación se muestra el código de salida:
Echemos un vistazo más de cerca a los códigos de estado HTTP para entenderlos mejor.
El servidor responde a una petición HTTP con un código de estado que indica el resultado de la petición. He aquí un breve resumen:
En nuestro ejemplo, el código de estado 200 significa que la petición a https://example.com se ha completado. Es la forma que tiene el servidor de decir: "Todo va bien por aquí, tu petición ha sido un éxito".
Estos códigos de estado también pueden desempeñar un papel en la detección de bots e indicar cuándo se restringe el acceso debido a un comportamiento similar al de un bot.
A continuación se muestra un rápido resumen de los códigos de error HTTP que se producen principalmente debido a la detección de bots y problemas de autenticación.
Escribamos ahora un sencillo mecanismo de reintento en Python para realizar peticiones HTTP GET con la librería requests. Hay veces en que las peticiones de red fallan debido a algún problema de red o sobrecarga del servidor. Así que si nuestra petición falla, deberíamos reintentar estas peticiones.
La función send_request_with_basic_retry_mechanism realiza peticiones HTTP GET a una URL dada con un mecanismo de reintento básico que sólo reintentará si se encuentra una excepción de red o de petición, como un error de conexión. Se reintentará la petición max_retries veces como máximo. Si todos los intentos fallan con una excepción de este tipo, lanza la última excepción encontrada.
import requests
import time
def send_request_with_basic_retry_mechanism(url, max_retries=2):
"""
Envía una petición HTTP GET a una URL con un mecanismo de reintento básico.
Parameters:
url (str): La URL a la que enviar la solicitud.
max_retries (int): El número máximo de veces para reintentar la solicitud.
Raises:
requests.RequestException: Lanza la última excepción si fallan todos los reintentos.
"""
for attempt in range(max_retries):
try:
response = requests.get(url)
print('Response status: ', response.status_code)
break # Salir del bucle si la solicitud tiene éxito
except requests.RequestException as error:
print(f"Attempt {attempt+1} failed:", error)
if attempt < max_retries - 1:
print(f"Retrying...")
time.sleep(delay) # Esperar antes de reintentar
else:
print("Max retries exceeded.")
# Vuelve a lanzar la última excepción si se alcanza el máximo de reintentos
raise
send_request_with_basic_retry_mechanism('https://example.com')
Adaptemos ahora el mecanismo básico de reintento para manejar escenarios en los que el sitio web que estamos tratando de scrapear implementa mecanismos de detección de bots que pueden resultar en bloqueos. Para hacer frente a estos escenarios, tenemos que reintentar la solicitud con diligencia varias veces, ya que pueden no ser sólo los bloqueos de detección de bots, sino que también podría ser debido a problemas de red o del servidor.
La siguiente función send_request_with_advance_retry_mechanism envía una petición HTTP GET a la URL proporcionada con intentos de reintento y retardo de reintento opcionales. Intenta enviar la petición varias veces durante el número de intentos especificado e imprime el código de estado de la respuesta si la petición obtiene una respuesta satisfactoria. Si encuentra un error durante la operación de petición, imprime el mensaje de error y lo reintenta. Espera el retardo de reintento especificado entre cada intento. Si la petición falla incluso después del número especificado de reintentos, lanza la última excepción encontrada.
El parámetro de retardo es importante, ya que evita bombardear al servidor con múltiples peticiones en un intervalo cercano. En su lugar, espera a que el servidor tenga tiempo suficiente para procesar la petición, haciendo que el servidor piense que es un humano y no un bot el que realiza las peticiones. Por lo tanto, el mecanismo de reintento debe retrasarse para evitar la sobrecarga del servidor o una respuesta lenta del servidor que pueda activar los mecanismos anti-bot.
import requests
import time
def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1):
"""
Envía una petición HTTP GET a la URL especificada con un mecanismo de reintento avanzado.
Parameters:
url (str): La URL a la que enviar la solicitud.
max_retries (int): El número máximo de veces para reintentar la petición. Por defecto es 3.
delay (int): El retardo (en segundos) entre reintentos. Por defecto es 1.
Raises:
requests.RequestException: Lanza la última excepción si fallan todos los reintentos.
"""
for attempt in range(max_retries):
try:
response = requests.get(url)
# Lanza una excepción para los códigos de estado 4xx o 5xx
response.raise_for_status()
print('Response Status Code:', response.status_code)
except requests.RequestException as e:
# Imprimir mensaje de error y número de intento si la solicitud falla
print(f"Attempt {attempt+1} failed:", e)
if attempt < max_retries - 1:
# Imprime el mensaje de reintento y espera antes de reintentar
print(f"Retrying in {delay} seconds...")
time.sleep(delay)
else:
# Si se excede el máximo de reintentos, imprime el mensaje y vuelve a lanzar la excepción
print("Max retries exceeded.")
raise
# Ejemplo de uso
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')
Aquí está el código corregido junto con los comentarios que abordan los inconvenientes:
import requests
import time
def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
"""
Envía una petición HTTP GET a la URL especificada con un mecanismo de reintento avanzado.
Parameters:
url (str): La URL a la que enviar la solicitud.
max_retries (int): El número máximo de veces que se debe reintentar la petición. El valor predeterminado es 3.
delay (int): El retardo (en segundos) entre reintentos. Por defecto es 1.
min_content_length (int): La longitud mínima del contenido de la respuesta que se considerará válida. El valor predeterminado es 10.
Raises:
requests.RequestException: Lanza la última excepción si fallan todos los reintentos.
"""
for attempt in range(max_retries):
try:
response = requests.get(url)
# Lanza una excepción para los códigos de estado 4xx o 5xx
response.raise_for_status()
# Comprobar si el código de estado de la respuesta es 404
if response.status_code == 404:
print("404 Error: Not Found")
break # Salir del bucle para errores 404
# Comprobar si la longitud del texto de respuesta es inferior a la longitud mínima de contenido especificada.
if len(response.text) < min_content_length:
print("Response text length is less than specified minimum. Retrying...")
time.sleep(delay)
continue # Reintentar la petición
print('Response Status Code:', response.status_code)
# Si se cumplen las condiciones, salir del bucle
break
except requests.RequestException as e:
print(f"Attempt {attempt+1} failed:", e)
if attempt < max_retries - 1:
print(f"Retrying in {delay} seconds...")
time.sleep(delay)
else:
print("Max retries exceeded.")
# Vuelve a lanzar la última excepción si se alcanza el máximo de reintentos
raise
# Ejemplo de uso
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')
Para ciertos errores como 429 Demasiadas Peticiones, el uso de proxies rotatorios puede ayudar a distribuir sus peticiones y evitar la limitación de velocidad.
El siguiente código implementa una estrategia de reintento avanzada junto con el uso de proxies. De esta forma, podemos implementar un mecanismo de reintento de peticiones Python. También es importante utilizar proxies de alta calidad. Estos proxies deben tener un buen algoritmo para la rotación de proxies y un pool fiable.
import requests
import time
def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
"""
Envía una petición HTTP GET a la URL especificada con un mecanismo de reintento avanzado.
Parameters:
url (str): La URL a la que enviar la solicitud.
max_retries (int): El número máximo de veces para reintentar la petición. Por defecto es 3.
delay (int): El retardo (en segundos) entre reintentos. El valor predeterminado es 1.
Raises:
requests.RequestException: Lanza la última excepción si fallan todos los reintentos.
"""
proxies = {
"http": "http://USER:PASS@HOST:PORT",
"https": "https://USER:PASS@HOST:PORT"
}
for attempt in range(max_retries):
try:
response = requests.get(url, proxies=proxies, verify=False)
# Lanza una excepción para los códigos de estado 4xx o 5xx
response.raise_for_status()
# Comprobar si el código de estado de la respuesta es 404
if response.status_code == 404:
print("404 Error: Not Found")
break # Salir del bucle para errores 404
# Compruebe si la longitud del texto de respuesta es inferior a 10 caracteres
if len(response.text) < min_content_length:
print("Response text length is less than 10 characters. Retrying...")
time.sleep(delay)
continue # Reintentar la petición
print('Response Status Code:', response.status_code)
# Si se cumplen las condiciones, salir del bucle
break
except requests.RequestException as e:
print(f"Attempt {attempt+1} failed:", e)
if attempt < max_retries - 1:
print(f"Retrying in {delay} seconds...")
time.sleep(delay)
else:
print("Max retries exceeded.")
# Vuelve a lanzar la última excepción si se alcanza el máximo de reintentos
raise
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')
Los reintentos de petición en Python son cruciales para un raspado web eficaz. Los métodos que hemos discutido para gestionar los reintentos pueden ayudar a prevenir el bloqueo y mejorar la eficiencia y la fiabilidad de la recopilación de datos. Implementar estas técnicas hará que tus scripts de web scraping sean más robustos y menos susceptibles de ser detectados por sistemas de protección contra bots.
Мы получили вашу заявку!
Ответ будет отправлен на почту в ближайшее время.
С уважением proxy-seller.com!
Comentarios: 0