C'è un modo semplice per richiedere un URL in Python e NON seguire i reindirizzamenti?


96

Guardando l'origine di urllib2 sembra che il modo più semplice per farlo sarebbe quello di sottoclassare HTTPRedirectHandler e quindi utilizzare build_opener per sovrascrivere il HTTPRedirectHandler predefinito, ma questo sembra un sacco di lavoro (relativamente complicato) per fare quello che sembra dovrebbe essere abbastanza semplice.


2
Per i googler: l'utilizzo della libreria delle richieste ti farà risparmiare un sacco di mal di testa: docs.python-requests.org e vedi la risposta di Marian di seguito, è molto elegante.
Alojz Janez

Sono d'accordo che le richieste siano la strada da percorrere in questi giorni. Ho votato positivamente questo commento e la risposta di Marian, ma lascio la risposta come premiata poiché era la migliore in quel momento.
Giovanni

1
I premi @John sono buoni ma il tempo passa e questo è un sito modificato dalla comunità. L'attenzione è sulle buone risposte e non sulle persone. Manterrà i suoi punti a favore. Stai fuorviando tonnellate di altri programmatori in librerie deprecate.
mit

1
Ok, abbastanza giusto. Ho accettato la risposta alle richieste.
Giovanni

Risposte:


180

Ecco il modo Richieste :

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

5
Quindi guarda r.headers['Location']per vedere dove ti avrebbe mandato
patricksurry

Nota che sembra che le richieste si normalizzeranno Locationin location.
Hamish

2
@Hamish requeststi consente di accedere alle intestazioni sia nella forma canonica che in minuscolo. Vedi docs.python-requests.org/en/master/user/quickstart/…
Marian

1
A partire dal 2019 in Python 3, questo non sembra più funzionare per me. (Ricevo un errore di comando chiave.)
Max von Hippel

35

Dive Into Python ha un buon capitolo sulla gestione dei reindirizzamenti con urllib2. Un'altra soluzione è 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
Tutti quelli che vengono qui da Google, si prega di notare che il modo più aggiornato da percorrere è questo: stackoverflow.com/a/14678220/362951 La libreria delle richieste ti farà risparmiare un sacco di mal di testa.
mit

Il collegamento a "Dive Into Python" è morto.
guettli

11

Questo è un gestore urllib2 che non seguirà i reindirizzamenti:

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)

Sto testando un'API e ho a che fare con un metodo di accesso che reindirizza a una pagina che non mi interessa, ma non invia il cookie di sessione desiderato con la risposta al reindirizzamento. Questo è esattamente ciò di cui avevo bisogno per questo.
Tim Wilder

9

La redirectionsparola chiave nel httplib2metodo di richiesta è una falsa pista. Invece di restituire la prima richiesta, solleverà RedirectLimitun'eccezione se riceve un codice di stato di reindirizzamento. Per restituire la risposta iniziale che è necessario impostare follow_redirectsper l'oggetto:FalseHttp

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

8

Suppongo che questo aiuterebbe

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

Secondo il puntatore di olt a Dive into Python . Ecco un'implementazione che utilizza i gestori di reindirizzamento urllib2, più lavoro di quanto dovrebbe essere? Forse alzare le spalle.

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
Sembra sbagliato ... Questo codice in realtà segue i reindirizzamenti (chiamando il gestore originale, emettendo così una richiesta HTTP), quindi solleva un'eccezione
Carles Barrobés

5

La via più breve comunque è

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

noredir_opener = urllib2.build_opener(NoRedirect())

1
Come è questa la via più breve? Non contiene nemmeno l'importazione o la richiesta effettiva.
Marian

Stavo già per pubblicare questa soluzione e sono rimasto piuttosto sorpreso di trovare questa risposta in fondo. È molto conciso e secondo me dovrebbe essere la risposta migliore.
utente

Inoltre, ti dà più libertà, in questo modo è possibile controllare quali URL seguire .
utente

Confermo, questo è il modo più semplice. Una breve osservazione per chi vuole fare il debug. Non dimenticare che puoi impostare gestori multipli quando ingrandisci l'apri come: opener = urllib.request.build_opener(debugHandler, NoRedirect())dove debugHandler=urllib.request.HTTPHandler()e debugHandler.set_http_debuglevel (1). Alla fine:urllib.request.install_opener(opener)
StashOfCode
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.