import requests import time from requests.exceptions import RequestException def fetch_with_retry(url, max_retries=5, initial_delay=1): """ Fetches data from a URL with exponential backoff and retries for specific HTTP errors. """ delay = initial_delay for i in range(max_retries): try: response = requests.get(url) response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx) return response.json() except requests.exceptions.HTTPError as e: if 400 <= e.response.status_code < 500 and e.response.status_code != 429: # Client error (not 429 Too Many Requests), re-raise immediately raise elif e.response.status_code == 429 or 500 <= e.response.status_code < 600: # Rate limit (429) or Server error (5xx), retry after delay print(f"Request failed with status {e.response.status_code}. Retrying in {delay} seconds...") time.sleep(delay) delay *= 2 # Exponential backoff else: # Other HTTP errors, re-raise raise except RequestException as e: # Catch all other requests-related exceptions (e.g., connection errors) print(f"Request failed due to network error: {e}. Retrying in {delay} seconds...") time.sleep(delay) delay *= 2 raise Exception(f"Failed to fetch data from {url} after {max_retries} attempts.") # Example Usage: # try: # data = fetch_with_retry("https://api.example.com/data") # print("Fetched data:", data) # except Exception as e: # print("Error:", e) # Example with a URL that might fail (e.g., for testing 429 or 500) # This example will likely fail unless you have a real API to test against # print(" Attempting to fetch from a potentially failing URL:") # try: # data_failing = fetch_with_retry("https://httpbin.org/status/429") # print("Fetched failing data (should not happen):", data_failing) # except Exception as e: # print("Expected error for failing URL:", e)