Czy istnieje łatwy sposób, aby zażądać adresu URL w pythonie i NIE podążać za przekierowaniami?


101

Patrząc na źródło urllib2, wygląda na to, że najłatwiejszym sposobem byłoby utworzenie podklasy HTTPRedirectHandler, a następnie użycie build_opener do zastąpienia domyślnego HTTPRedirectHandler, ale wydaje się, że jest to dużo (stosunkowo skomplikowanej) pracy, aby wykonać to, co wygląda na to, że powinno być dość proste.


2
Dla pracowników Google: korzystanie z biblioteki żądań pozwoli Ci zaoszczędzić wiele bólu głowy: docs.python-requests.org i zobacz odpowiedź Mariana poniżej, jest bardzo elegancka.
— Alojz Janez

Zgadzam się, że prośby są obecnie drogą. Głosowałem za tym komentarzem i odpowiedzią Mariana, ale pozostawiam odpowiedź jako przyznaną, ponieważ była wtedy najlepsza.
— John

1
Nagrody @John są dobre, ale czas mija i jest to witryna redagowana przez społeczność. Skupiamy się na dobrych odpowiedziach, a nie na ludziach. Zachowa swoje punkty upvote. Wprowadzasz w błąd mnóstwo innych programistów do przestarzałych bibliotek.
— mit

1
Ok, w porządku. Przyjąłem odpowiedzi na prośby.
— John

Odpowiedzi:


187

Oto sposób Żądania :

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

6
Następnie spójrz, r.headers['Location']dokąd by cię to wysłało
— patricksurry

Zwróć uwagę, że wygląda na to, że Request będzie normalizować się Locationdo location.
— Hamish

2
@Hamish requestsumożliwia dostęp do nagłówków zarówno w formie kanonicznej, jak i małych liter. Zobacz docs.python-requests.org/en/master/user/quickstart/…
— Marian

1
Od 2019 roku w Pythonie 3 wydaje mi się, że to już nie działa. (Dostaję kluczowy błąd dyktowania.)
— Max von Hippel

36

Dive Into Python ma dobry rozdział na temat obsługi przekierowań za pomocą urllib2. Innym rozwiązaniem jest 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
Każdy, kto przychodzi tutaj z Google, pamiętaj, że aktualna droga jest następująca: stackoverflow.com/a/14678220/362951 Biblioteka żądań pozwoli Ci zaoszczędzić wiele bólu głowy.
— mit

Link do „Dive Into Python” nie działa.
— guettli

11

To jest moduł obsługi urllib2, który nie będzie podążał za przekierowaniami:

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)

Testuję jednostkowo interfejs API i mam do czynienia z metodą logowania, która przekierowuje na stronę, na której mi nie zależy, ale nie wysyła żądanego pliku cookie sesji z odpowiedzią na przekierowanie. Właśnie tego potrzebowałem.
— Tim Wilder,

9

Słowo redirectionskluczowe w httplib2metodzie request to czerwony śledź. Zamiast zwracać pierwsze żądanie, zgłosi RedirectLimitwyjątek, jeśli otrzyma kod stanu przekierowania. Aby przywrócić inital odpowiedź trzeba ustawić follow_redirectssię Falsena Httpobiekcie:

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

8

przypuszczam, że to by pomogło

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

Drugi wskaźnik olta do Dive into Python . Oto implementacja wykorzystująca programy obsługi przekierowań urllib2, więcej pracy niż powinno? Może wzruszysz ramionami.

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
Wygląda źle ... Ten kod faktycznie podąża za przekierowaniami (wywołując oryginalną procedurę obsługi,
— wysyłając w

5

Jednak najkrótsza droga jest

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

noredir_opener = urllib2.build_opener(NoRedirect())

1
Jak to jest najkrótsza? Nie zawiera nawet importu ani rzeczywistego żądania.
— Marian

Miałem już zamiar opublikować to rozwiązanie i byłem dość zaskoczony, gdy znalazłem tę odpowiedź na dole. Jest bardzo zwięzła i moim zdaniem powinna być najlepszą odpowiedzią.
— użytkownik

Ponadto zapewnia większą swobodę, w ten sposób można kontrolować, które adresy URL należy śledzić .
— użytkownik

Potwierdzam, to najłatwiejszy sposób. Krótka uwaga dla tych, którzy chcą debugować. Nie zapominaj, że możesz ustawić obsługę wielokrotności podczas buldowania otwieracza, takich jak: opener = urllib.request.build_opener(debugHandler, NoRedirect())gdzie debugHandler=urllib.request.HTTPHandler()i debugHandler.set_http_debuglevel (1). Na koniec:urllib.request.install_opener(opener)
— StashOfCode
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.