¿Existe una manera fácil de solicitar una URL en Python y NO seguir las redirecciones?

96

Mirando la fuente de urllib2, parece que la forma más fácil de hacerlo sería subclase HTTPRedirectHandler y luego usar build_opener para anular el HTTPRedirectHandler predeterminado, pero esto parece una gran cantidad de trabajo (relativamente complicado) para hacer lo que parece que debería ser bastante simple.

Juan
fuente
2
Para los usuarios de Google: usar la biblioteca de solicitudes le ahorrará muchos dolores de cabeza: docs.python-requests.org y vea la respuesta de Marian a continuación, es muy elegante.
Alojz Janez
Estoy de acuerdo en que las solicitudes son el camino a seguir en estos días. He votado a favor de este comentario y la respuesta de Marian, pero dejo la respuesta como otorgada, ya que fue la mejor en ese momento.
John
1
Los premios @John son buenos, pero el tiempo pasa y este es un sitio editado por la comunidad. La atención se centra en las buenas respuestas y no en las personas. Mantendrá sus puntos de voto a favor. Estás engañando a muchos otros programadores para que utilicen bibliotecas obsoletas.
mit
1
OK bastante justo. He aceptado la respuesta de las solicitudes.
Juan

Respuestas:

180

Aquí está la forma de Solicitudes :

import requests
r = requests.get('http://github.com', allow_redirects=False)
print(r.status_code, r.headers['Location'])
Mariana
fuente
5
Luego mira r.headers['Location']para ver a dónde te habría enviado
patricksurry
Tenga en cuenta que parece que las solicitudes se normalizarán Locationa location.
Hamish
2
@Hamish requestste permite acceder a los encabezados tanto en forma canónica como en minúsculas. Ver docs.python-requests.org/en/master/user/quickstart/…
Marian
1
A partir de 2019 en Python 3, esto ya no parece funcionar para mí. (Recibo un error de dictado clave.)
Max von Hippel
35

Dive Into Python tiene un buen capítulo sobre el manejo de redireccionamientos con urllib2. Otra solución es 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
olt
fuente
7
Todos los que vienen aquí desde Google, tengan en cuenta que la forma actualizada es esta: stackoverflow.com/a/14678220/362951 La biblioteca de solicitudes le ahorrará muchos dolores de cabeza.
mit
El enlace a "Dive Into Python" está muerto.
guettli
11

Este es un controlador urllib2 que no seguirá las redirecciones:

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)
Carles Barrobés
fuente
Estoy probando una API y lidiando con un método de inicio de sesión que redirige a una página que no me importa, pero no envía la cookie de sesión deseada con la respuesta a la redirección. Esto es exactamente lo que necesitaba para eso.
Tim Wilder
9

La redirectionspalabra clave en el httplib2método de solicitud es una pista falsa. En lugar de devolver la primera solicitud, generará una RedirectLimitexcepción si recibe un código de estado de redirección. Para devolver la respuesta inital Es necesario que ajuste follow_redirectsa Falsela Httpdel objeto:

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

supongo que esto ayudaría

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)
Ashish
fuente
5

En segundo lugar, el puntero de olt es Dive into Python . Aquí hay una implementación que usa controladores de redireccionamiento urllib2, ¿más trabajo del que debería ser? Quizás, encogerse de hombros.

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) 
Aaron Maenpaa
fuente
3
Parece mal ... Este código en realidad sigue las redirecciones (llamando al controlador original, emitiendo así una solicitud HTTP), y luego genera una excepción
Carles Barrobés
5

Sin embargo, el camino más corto es

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

noredir_opener = urllib2.build_opener(NoRedirect())
Tzury Bar Yochay
fuente
1
¿Cómo es este el camino más corto? Ni siquiera contiene la importación o la solicitud real.
Marian
Ya iba a publicar esta solución y me sorprendió bastante encontrar esta respuesta en la parte inferior. Es muy conciso y debería ser la mejor respuesta en mi opinión.
usuario
Además, te da más libertad, de esta forma es posible controlar qué URLs seguir .
usuario
Lo confirmo, esta es la forma más fácil. Un breve comentario para aquellos que quieran depurar. No olvide que puede establecer múltiples manejadores al armar el abridor como: opener = urllib.request.build_opener(debugHandler, NoRedirect())dónde debugHandler=urllib.request.HTTPHandler()y debugHandler.set_http_debuglevel (1). Al final:urllib.request.install_opener(opener)
StashOfCode