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)