Dzisiaj dla odmiany od Rubiego, krótki poradnik dot. sprawdzania dostępności strony WWW z wykorzystaniem Pythona i biblioteki urllib2.
Wstęp
Zdarza się, że potrzebujemy wiedzieć czy url jaki wprowadza użytkownik jest poprawny i czy taka strona w ogóle istnieje. Może się to przydać chociażby do walidacji pola url w modelu usera. Dzięki temu użytkownik nie będzie mógł wprowadzić przez pomyłkę adresu który nie istnieje.
Metoda
Metoda jest całkiem prosta - wystarczy odpytać żądaniem HEAD nasz url, sprawdzić co zostanie zwrócone i ewentualnie przechwycić wyjątki. Warto zauważyć, że w poniższym kodzie dokonałem pewnego uproszczenia. Mianowicie, przechwytuję część błędów nadając im ręcznie wartość 404. Tak naprawdę te błędy należałoby obsłużyć w inny sposób, ponieważ niekoniecznie oznaczają to, że podana strona nie istnieje. Poniżej opis tego co który wyjątek oznacza:
- urllib2.HTTPError - błędy z serwera (404, 500, 403, itd)
- urllib2.URLError - nieprawidłowy URL (nie istnieje taki adres lub błąd w składni)
- Exception - całe inne zło tego świata :)
Najpierw zaimportujmy sobie co nam potrzeba i ustalmy jaki URL sprawdzamy:
import urllib2 from urllib2 import URLError uri = "http://onet.pl"
No i sprawdzamy:
def uri_status( uri): if len(uri) == 0: return '404' try: request = urllib2.Request(uri, None, {'User-agent': 'Mozilla/5.0'}) request.get_method = lambda : 'HEAD' response = urllib2.urlopen(request) return '200' except urllib2.HTTPError, e: return e.code except urllib2.URLError, e: return '404' except Exception, e: return '404' print uri_status(uri)
Kod metody i jej wywołanie:
def uri_status( uri): if len(uri) == 0: return False try: request = urllib2.Request(uri, None, {'User-agent': 'Mozilla/5.0'}) request.get_method = lambda : 'HEAD' response = urllib2.urlopen(request) return '200' except urllib2.HTTPError, e: return e.code except urllib2.URLError, e: return '404' except Exception, e: return '404' print uri_status(uri)
Podajemy user_agenta (przeglądarkę), ponieważ niektóre serwisy nie chcą (lub robią to błędnie) odpowiadają na żądania.
UPDATE
Warto ustawić także timeout dla połączeń - ponieważ połączenia bez ustalonego timeoutu mogą trwać w nieskończoność. Nie można tego jednak zrobić z poziomu urllib2 a jedynie dla socketów:
import socket import urllib2 # timeout w sekundach timeout = 10 socket.setdefaulttimeout(timeout)