Přesměrování (redirect) s modulem urllib2
Standardně je Pythonovský modul urllib2 naprogramován tak, že automaticky zajistí, aby se HTTP přesměrování provedlo, aniž by o tom uživatel (nebo spíše programátor) věděl. Někdy je ovšem dobré vědět, že bylo přesměrování provedeno a jaký je jeho typ. Například v případě, že potřebujete uložit novou URL stránky, protože ta se díky přesměrování změní. Při zjišťování přesměrování mohou ale nastat nečekané problémy.
Typy HTTP přesměrování
Nejdříve si něco řekněme o přesměrování samotném. Určitě se Vám někdy stalo, že jste zadali adresu do prohlížeče a po načtení webové stránky se ta adresa změnila. To je přesměrování. Jednoduché že?
Ne tak docela. Přestože to většinou nikoho nezajímá, existuje více typů přesměrování. Odlišeny jsou od sebe svým kódem (číslem), které Váš internetový prohlížeč dostane v HTTP hlavičce. U přesměrování se jedná o čísla 300 až 307, já se ovšem budu dále zabývat jen dvěmi z nich a to 301 - Moved Permanently (Trvale přesunuto) a 302 - Moved Temporarily (Dočasně přesunuto, někdy bývá uvedeno Found - Nalezeno). Rozdíl mezi trvalým a dočasným přesměrováním snad netřeba vysvětlovat :)
Rozlišení přesměrování v Pythonu
Teď už se snad dostanu k jádru pudla. V Pythonu při zjišťování stavového kódu přesměrování vznikne výjimka, která program shodí. Vyzkoušejte následující příkazy a uvidíte.
>>> import urllib2, httplib >>> httplib.HTTPConnection.debuglevel = 1 >>> request = urllib2.Request( ... 'http://www.mpower-project.eu') # URL s přeměrováním >>> opener = urllib2.build_opener() >>> f = opener.open(request)
Zatím nic. Ovšem jen do doby, kdy si nechám vypsat URL stránky v paměti.
>>> f.url 'http://www.sintef.no/Projectweb/MPOWER/'
Je jiná než jsem zadal. Ovšem bylo přesměrovnání dočasné nebo trvalé? Nevím.
>>> f.status Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: addinfourl instance has no attribute 'status'
Chytré hlavy ale vědí, jak to vyřešit. Stačí se podívat, jak funguje urllib2 a napsat si svůj redirect handler, pro tyto dva stavové kódy. Následující kód se může vyťukat do terminálu nebo uložit do samostatného souboru.
class SmartRedirectHandler(urllib2.HTTPRedirectHandler): def http_error_301(self, req, fp, code, msg, headers): result = urllib2.HTTPRedirectHandler.http_error_301( self, req, fp, code, msg, headers) result.status = code return result def http_error_302(self, req, fp, code, msg, headers): result = urllib2.HTTPRedirectHandler.http_error_302( self, req, fp, code, msg, headers) result.status = code return result
Nyní stačí malinko upravit původní kód a mám HTTP status z hlavičky jak na dlani, což potřebuji. Předpokládejme, že následující kód už třídu SmartRedirectHandler zná.
>>> import urllib2, httplib >>> httplib.HTTPConnection.debuglevel = 1 >>> request = urllib2.Request( ... 'http://www.mpower-project.eu') # URL s přeměrováním >>> opener = urllib2.build_opener( ... SmartRedirectHandler()) >>> f = opener.open(request) >>> f.url 'http://www.sintef.no/Projectweb/MPOWER/' >>> f.status 301
Bingo. Teď už mé programy umí rozlišovat dočasná a trvalá přesměrování.
Ale nemyslete si, že já jsem ta chytrá hlava, která na to došla. Musel jsem trochu zagooglit, abych našel hezkou stránku, kde bylo řešení uvedeno ;) Vy tu stránku můžete najít v odkazech pod článkem.