Existe uma maneira fácil de solicitar um URL em python e NÃO seguir redirecionamentos?


96

Olhando para a fonte de urllib2, parece que a maneira mais fácil de fazer isso seria subclasse HTTPRedirectHandler e, em seguida, usar build_opener para substituir o HTTPRedirectHandler padrão, mas isso parece muito (relativamente complicado) de trabalho para fazer o que parece que deveria ser bem simples.


2
Para googlers: usar a biblioteca de solicitações poupará muitas dores de cabeça: docs.python-requests.org e veja a resposta de Marian abaixo, é muito elegante.
— Alojz Janez

Concordo que os pedidos são o caminho a percorrer nos dias de hoje. Votei positivamente neste comentário e na resposta de Marian, mas estou deixando a resposta como premiada, pois foi a melhor na época.
— João

1
Os prêmios @John são bons, mas o tempo passa e este é um site editado pela comunidade. O foco está nas boas respostas e não nas pessoas. Ele manterá seus pontos positivos. Você está enganando toneladas de outros programadores em bibliotecas obsoletas.
— mit

1
Ok, é justo. Aceitei a resposta dos pedidos.
— João

Respostas:


180

Esta é a forma de Solicitações :

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

5
Então olhe r.headers['Location']para ver para onde isso o teria levado
— patricksurry

Observe que parece que as solicitações serão normalizadas Locationpara location.
— Hamish

2
@Hamish requestspermite que você acesse os cabeçalhos tanto na forma canônica quanto em minúsculas. Veja docs.python-requests.org/en/master/user/quickstart/…
— Marian

1
A partir de 2019 em Python 3, isso parece não funcionar mais para mim. (Recebo um erro de ditado chave.)
— Max von Hippel

35

Dive Into Python tem um bom capítulo sobre como lidar com redirecionamentos com urllib2. Outra solução é 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
Todo mundo que vem do google, por favor, observe que o jeito mais atualizado de ir é este: stackoverflow.com/a/14678220/362951 A biblioteca de solicitações vai poupar muitas dores de cabeça.
— mit

O link para "Dive Into Python" está morto.
— guettli

11

Este é um manipulador urllib2 que não seguirá os redirecionamentos:

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)

Estou testando uma API de unidade e lidando com um método de login que redireciona para uma página que não interessa, mas não envia o cookie de sessão desejado com a resposta ao redirecionamento. Isso é exatamente o que eu precisava para isso.
— Tim Wilder

9

A redirectionspalavra-chave no httplib2método de solicitação é uma pista falsa. Em vez de retornar a primeira solicitação, ele gerará uma RedirectLimitexceção se receber um código de status de redirecionamento. Para retornar a resposta inicial, você precisa definir follow_redirectscomo Falseno Httpobjeto:

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

8

suponho que isso ajudaria

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

Segui a indicação de olt para Dive into Python . Aqui está uma implementação usando manipuladores de redirecionamento urllib2, mais trabalho do que deveria? Talvez, dê de ombros.

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
Parece errado ... Este código realmente segue os redirecionamentos (chamando o manipulador original, emitindo assim uma solicitação HTTP) e, em seguida,
— gera

5

O caminho mais curto, entretanto, é

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

noredir_opener = urllib2.build_opener(NoRedirect())

1
Como esse é o caminho mais curto? Ele nem mesmo contém a importação ou a solicitação real.
— Mariana

Eu já ia postar essa solução e fiquei bastante surpreso ao encontrar essa resposta no final. É muito conciso e deve ser a resposta principal na minha opinião.
— usuário

Além disso, dá mais liberdade, desta forma é possível controlar quais URLs seguir .
— usuário

Confirmo, esta é a forma mais fácil. Um breve comentário para quem deseja depurar. Não se esqueça de que você pode definir múltiplos manipuladores ao construir o abridor como: opener = urllib.request.build_opener(debugHandler, NoRedirect())onde debugHandler=urllib.request.HTTPHandler()e debugHandler.set_http_debuglevel (1). No final:urllib.request.install_opener(opener)
— StashOfCode
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.