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)