Web scraping to skuteczna metoda pozyskiwania danych z sieci. Wielu programistów woli korzystać z biblioteki żądań Pythona do realizacji projektów skrobania stron internetowych, ponieważ jest ona prosta i skuteczna. Jednakże, biblioteka requestów ma swoje ograniczenia. Jednym z typowych problemów, które możemy napotkać podczas skrobania stron internetowych, są nieudane żądania, które często prowadzą do niestabilnej ekstrakcji danych. W tym artykule przejdziemy przez proces implementacji ponawiania żądań w Pythonie, abyś mógł poradzić sobie z błędami HTTP i utrzymać stabilność i niezawodność skryptów skrobania stron internetowych.
Najpierw skonfigurujmy nasze środowisko. Upewnij się, że masz zainstalowany Python i dowolne IDE. Następnie zainstaluj bibliotekę requests, jeśli jeszcze jej nie masz.
pip install requests
Po zainstalowaniu, wyślijmy żądanie do example.com za pomocą modułu requests Pythona. Oto prosta funkcja, która właśnie to robi:
import requests
def send_request(url):
"""
Wysyła żądanie HTTP GET do określonego adresu URL i drukuje kod statusu odpowiedzi.
Parameters:
url (str): Adres URL, na który ma zostać wysłane żądanie.
"""
response = requests.get(url)
print('Response Status Code: ', response.status_code)
send_request('https://example.com')
Dane wyjściowe kodu pokazano poniżej:
Przyjrzyjmy się bliżej kodom statusu HTTP, aby lepiej je zrozumieć.
Serwer odpowiada na żądanie HTTP kodem stanu wskazującym wynik żądania. Oto krótkie podsumowanie:
W naszym przykładzie kod statusu 200 oznacza, że żądanie do https://example.com zostało zakończone. Jest to sposób serwera na powiedzenie: "Wszystko jest w porządku, twoje żądanie zakończyło się sukcesem".
Te kody stanu mogą również odgrywać rolę w wykrywaniu botów i wskazywaniu, kiedy dostęp jest ograniczony z powodu zachowania podobnego do botów.
Poniżej znajduje się krótki przegląd kodów błędów HTTP, które występują głównie z powodu wykrywania botów i problemów z uwierzytelnianiem.
Napiszmy teraz prosty mechanizm ponawiania w Pythonie, aby wykonać żądanie HTTP GET za pomocą biblioteki requests. Zdarza się, że żądania sieciowe kończą się niepowodzeniem z powodu problemów z siecią lub przeciążenia serwera. Jeśli więc nasze żądanie nie powiedzie się, powinniśmy ponowić próbę.
Funkcja send_request_with_basic_retry_mechanism wykonuje żądania HTTP GET do danego adresu URL z podstawowym mechanizmem ponawiania, który ponawia próbę tylko w przypadku napotkania wyjątku sieci lub żądania, takiego jak błąd połączenia. Żądanie będzie ponawiane maksimum razy. Jeśli wszystkie próby zakończą się niepowodzeniem z takim wyjątkiem, zgłaszany jest ostatni napotkany wyjątek.
import requests
import time
def send_request_with_basic_retry_mechanism(url, max_retries=2):
"""
Wysyła żądanie HTTP GET do adresu URL z podstawowym mechanizmem ponawiania.
Parameters:
url (str): Adres URL, na który ma zostać wysłane żądanie.
max_retries (int): Maksymalna liczba ponownych prób wykonania żądania.
Raises:
requests.RequestException: Podnosi ostatni wyjątek, jeśli wszystkie próby nie powiodą się.
"""
for attempt in range(max_retries):
try:
response = requests.get(url)
print('Response status: ', response.status_code)
break # Wyjście z pętli, jeśli żądanie się powiedzie
except requests.RequestException as error:
print(f"Attempt {attempt+1} failed:", error)
if attempt < max_retries - 1:
print(f"Retrying...")
time.sleep(delay) # Poczekaj przed ponowieniem próby
else:
print("Max retries exceeded.")
# Ponowne podniesienie ostatniego wyjątku, jeśli osiągnięto maksymalną liczbę ponownych prób
raise
send_request_with_basic_retry_mechanism('https://example.com')
Dostosujmy teraz podstawowy mechanizm ponawiania prób, aby obsłużyć scenariusze, w których witryna, którą próbujemy zeskrobać, wdraża mechanizmy wykrywania botów, które mogą skutkować blokowaniem. Aby poradzić sobie z takimi scenariuszami, musimy wielokrotnie ponawiać żądanie, ponieważ mogą to być nie tylko blokady wykrywania botów, ale także problemy z siecią lub serwerem.
Poniższa funkcja send_request_with_advance_retry_mechanism wysyła żądanie HTTP GET na podany adres URL z opcjonalnymi próbami ponowienia i opóźnieniem ponowienia. Próbuje wysłać żądanie wiele razy przez określoną liczbę prób i drukuje kod statusu odpowiedzi, jeśli żądanie pomyślnie otrzyma odpowiedź. Jeśli napotka błąd podczas operacji żądania, drukuje komunikat o błędzie i ponawia próbę. Odczekuje określone opóźnienie ponowienia między każdą próbą. Jeśli żądanie nie powiedzie się nawet po określonej liczbie ponownych prób, zgłasza ostatnio napotkany wyjątek.
Parametr opóźnienia jest ważny, ponieważ pozwala uniknąć bombardowania serwera wieloma żądaniami w krótkim odstępie czasu. Zamiast tego czeka, aż serwer będzie miał wystarczająco dużo czasu na przetworzenie żądania, dzięki czemu serwer myśli, że żądania składa człowiek, a nie bot. Tak więc mechanizm ponawiania powinien być opóźniony, aby uniknąć przeciążenia serwera lub powolnej odpowiedzi serwera, co może uruchomić mechanizmy anty-botowe.
import requests
import time
def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1):
"""
Wysyła żądanie HTTP GET do określonego adresu URL z zaawansowanym mechanizmem ponawiania.
Parameters:
url (str): Adres URL, na który ma zostać wysłane żądanie.
max_retries (int): Maksymalna liczba ponownych prób wykonania żądania. Wartość domyślna to 3.
delay (int): Opóźnienie (w sekundach) między ponownymi próbami. Domyślnie 1.
Raises:
requests.RequestException: Podnosi ostatni wyjątek, jeśli wszystkie próby nie powiodą się.
"""
for attempt in range(max_retries):
try:
response = requests.get(url)
# Zgłasza wyjątek dla kodów statusu 4xx lub 5xx
response.raise_for_status()
print('Response Status Code:', response.status_code)
except requests.RequestException as e:
# Wyświetla komunikat o błędzie i numer próby, jeśli żądanie nie powiedzie się.
print(f"Attempt {attempt+1} failed:", e)
if attempt < max_retries - 1:
# Wydruk komunikatu ponownej próby i odczekanie przed ponowieniem próby
print(f"Retrying in {delay} seconds...")
time.sleep(delay)
else:
# Jeśli maksymalna liczba prób została przekroczona, wypisuje komunikat i ponownie zgłasza wyjątek
print("Max retries exceeded.")
raise
# Przykład użycia
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')
Oto poprawiony kod wraz z komentarzami dotyczącymi wad:
import requests
import time
def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
"""
Wysyła żądanie HTTP GET do określonego adresu URL z zaawansowanym mechanizmem ponawiania.
Parameters:
url (str): Adres URL, na który ma zostać wysłane żądanie.
max_retries (int): The maximum number of times to retry the request. The default is 3.
delay (int): Opóźnienie (w sekundach) między ponownymi próbami. Domyślnie 1.
min_content_length (int): Minimalna długość treści odpowiedzi, którą należy uznać za prawidłową. Domyślnie jest to 10.
Raises:
requests.RequestException: Podnosi ostatni wyjątek, jeśli wszystkie próby nie powiodą się.
"""
for attempt in range(max_retries):
try:
response = requests.get(url)
# Zgłasza wyjątek dla kodów statusu 4xx lub 5xx
response.raise_for_status()
# Sprawdź, czy kod statusu odpowiedzi to 404
if response.status_code == 404:
print("404 Error: Not Found")
break # Wyjście z pętli dla błędów 404
# Sprawdź, czy długość tekstu odpowiedzi jest mniejsza niż określona minimalna długość treści.
if len(response.text) < min_content_length:
print("Response text length is less than specified minimum. Retrying...")
time.sleep(delay)
continue # Ponów żądanie
print('Response Status Code:', response.status_code)
# Jeśli warunki są spełnione, wyjdź z pętli
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.")
# Ponowne podniesienie ostatniego wyjątku, jeśli osiągnięto maksymalną liczbę ponownych prób
raise
# Przykład użycia
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')
W przypadku niektórych błędów, takich jak 429 Too Many Requests, korzystanie z obrotowych serwerów proxy może pomóc w dystrybucji żądań i uniknięciu ograniczenia szybkości.
Poniższy kod implementuje zaawansowaną strategię ponawiania żądań wraz z wykorzystaniem serwerów proxy. W ten sposób możemy zaimplementować mechanizm ponawiania żądań Pythona. Ważne jest również korzystanie z wysokiej jakości serwerów proxy do skrobania stron internetowych. Te serwery proxy powinny mieć dobry algorytm rotacji proxy i niezawodną pulę.
import requests
import time
def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
"""
Wysyła żądanie HTTP GET do określonego adresu URL z zaawansowanym mechanizmem ponawiania.
Parameters:
url (str): Adres URL, na który ma zostać wysłane żądanie.
max_retries (int): Maksymalna liczba ponownych prób wykonania żądania. Wartość domyślna to 3.
delay (int): Opóźnienie (w sekundach) między ponownymi próbami. Domyślnie jest to 1.
Raises:
requests.RequestException: Podnosi ostatni wyjątek, jeśli wszystkie próby nie powiodą się.
"""
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)
# Zgłasza wyjątek dla kodów statusu 4xx lub 5xx
response.raise_for_status()
# Sprawdź, czy kod statusu odpowiedzi to 404.
if response.status_code == 404:
print("404 Error: Not Found")
break # Exit loop for 404 errors
# Sprawdź, czy długość tekstu odpowiedzi jest mniejsza niż 10 znaków.
if len(response.text) < min_content_length:
print("Response text length is less than 10 characters. Retrying...")
time.sleep(delay)
continue # Ponów żądanie
print('Response Status Code:', response.status_code)
# Jeśli warunki są spełnione, wyjdź z pętli
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.")
# Ponowne podniesienie ostatniego wyjątku, jeśli osiągnięto maksymalną liczbę ponownych prób
raise
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')
Ponawianie żądań w Pythonie ma kluczowe znaczenie dla efektywnego skrobania stron internetowych. Omówione przez nas metody zarządzania ponawianiem żądań mogą pomóc w zapobieganiu blokadom oraz zwiększeniu wydajności i niezawodności gromadzenia danych. Wdrożenie tych technik sprawi, że skrypty web scrapingu będą bardziej niezawodne i mniej podatne na wykrycie przez systemy ochrony przed botami.
Komentarze: 0