Existe-t-il un moyen simple de demander une URL en python et de NE PAS suivre les redirections?


96

En regardant la source de urllib2, il semble que le moyen le plus simple de le faire serait de sous-classer HTTPRedirectHandler, puis d'utiliser build_opener pour remplacer le HTTPRedirectHandler par défaut, mais cela semble être beaucoup de travail (relativement compliqué) pour faire ce qui semble devoir être assez simple.


2
Pour les googleurs: utiliser la bibliothèque de requêtes vous évitera beaucoup de maux de tête: docs.python-requests.org et voir la réponse de Marian ci-dessous, c'est très élégant.
Alojz Janez

Je conviens que les demandes sont la voie à suivre ces jours-ci. J'ai voté pour ce commentaire et la réponse de Marian, mais je laisse la réponse comme attribuée car c'était la meilleure à l'époque.
John

1
Les récompenses @John sont bonnes mais le temps passe et c'est un site édité par la communauté. L'accent est mis sur les bonnes réponses et non sur les personnes. Il conservera ses points de vote. Vous induisez en erreur des tonnes d'autres codeurs dans des bibliothèques obsolètes.
mit

1
OK très bien. J'ai accepté la réponse aux demandes.
John

Réponses:


180

Voici le chemin des demandes :

import requests
r = requests.get('http://github.com', allow_redirects=False)
print(r.status_code, r.headers['Location'])

5
Puis regardez r.headers['Location']pour voir où cela vous aurait envoyé
patricksurry

Notez qu'il semble que les requêtes se normaliseront Locationà location.
Hamish

2
@Hamish requestsvous permet d'accéder aux en-têtes à la fois sous forme canonique et en minuscules. Voir docs.python-requests.org/en/master/user/quickstart/…
Marian

1
À partir de 2019 dans Python 3, cela ne semble plus fonctionner pour moi. (Je reçois une erreur de dict clé.)
Max von Hippel

35

Dive Into Python a un bon chapitre sur la gestion des redirections avec urllib2. Une autre solution est httplib .

>>> import httplib
>>> conn = httplib.HTTPConnection("www.bogosoft.com")
>>> conn.request("GET", "")
>>> r1 = conn.getresponse()
>>> print r1.status, r1.reason
301 Moved Permanently
>>> print r1.getheader('Location')
http://www.bogosoft.com/new/location

7
Tous ceux qui viennent ici de google, veuillez noter que la méthode à jour est celle-ci: stackoverflow.com/a/14678220/362951 La bibliothèque de requêtes vous évitera beaucoup de maux de tête.
mit

Le lien vers "Dive Into Python" est mort.
guettli

11

Il s'agit d'un gestionnaire urllib2 qui ne suivra pas les redirections:

class NoRedirectHandler(urllib2.HTTPRedirectHandler):
    def http_error_302(self, req, fp, code, msg, headers):
        infourl = urllib.addinfourl(fp, headers, req.get_full_url())
        infourl.status = code
        infourl.code = code
        return infourl
    http_error_300 = http_error_302
    http_error_301 = http_error_302
    http_error_303 = http_error_302
    http_error_307 = http_error_302

opener = urllib2.build_opener(NoRedirectHandler())
urllib2.install_opener(opener)

Je teste une API unitaire et je gère une méthode de connexion qui redirige vers une page qui ne m'intéresse pas, mais qui n'envoie pas le cookie de session souhaité avec la réponse à la redirection. C'est exactement ce dont j'avais besoin pour cela.
Tim Wilder

9

Le redirectionsmot-clé de la httplib2méthode de demande est un hareng rouge. Plutôt que de renvoyer la première demande, il lèvera une RedirectLimitexception s'il reçoit un code d'état de redirection. Pour retourner la réponse inital vous devez définir follow_redirectspour Falsele Httpobjet:

import httplib2
h = httplib2.Http()
h.follow_redirects = False
(response, body) = h.request("http://example.com")

8

je suppose que cela aiderait

from httplib2 import Http
def get_html(uri,num_redirections=0): # put it as 0 for not to follow redirects
conn = Http()
return conn.request(uri,redirections=num_redirections)

5

Je seconde le pointeur de olt sur Dive into Python . Voici une implémentation utilisant les gestionnaires de redirection urllib2, plus de travail qu'il ne devrait l'être? Peut-être, hausser les épaules.

import sys
import urllib2

class RedirectHandler(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                                 
        raise Exception("Permanent Redirect: %s" % 301)

    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                                
        raise Exception("Temporary Redirect: %s" % 302)

def main(script_name, url):
   opener = urllib2.build_opener(RedirectHandler)
   urllib2.install_opener(opener)
   print urllib2.urlopen(url).read()

if __name__ == "__main__":
    main(*sys.argv) 

3
Ça a l'air faux ... Ce code suit en fait les redirections (en appelant le gestionnaire d'origine, émettant ainsi une requête HTTP), puis lève une exception
Carles Barrobés

5

Le moyen le plus court est cependant

class NoRedirect(urllib2.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, hdrs, newurl):
        pass

noredir_opener = urllib2.build_opener(NoRedirect())

1
Comment est-ce le chemin le plus court? Il ne contient même pas l'importation ni la demande réelle.
Marian

J'allais déjà poster cette solution et j'ai été assez surpris de trouver cette réponse en bas. Il est très concis et devrait être la meilleure réponse à mon avis.
utilisateur

De plus, cela vous donne plus de liberté, de cette façon, il est possible de contrôler les URL à suivre .
utilisateur

Je confirme, c'est la voie la plus simple. Une petite remarque pour ceux qui veulent déboguer. N'oubliez pas que vous pouvez définir plusieurs gestionnaires lors du bullding de l'ouvre-porte comme: opener = urllib.request.build_opener(debugHandler, NoRedirect())debugHandler=urllib.request.HTTPHandler()et debugHandler.set_http_debuglevel (1). En fin de compte:urllib.request.install_opener(opener)
StashOfCode
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.