Чи є простий спосіб запитати URL-адресу в python і НЕ слідувати за переспрямуваннями?


96

Дивлячись на джерело urllib2, здається, найпростішим способом було б зробити підклас HTTPRedirectHandler, а потім використовувати build_opener, щоб замінити HTTPRedirectHandler за замовчуванням, але це здається великою (порівняно складною) роботою, щоб зробити те, що здається, що повинно бути. досить просто.


2
Для гуглерів: використання бібліотеки запитів позбавить вас від головного болю: docs.python-requests.org і див. Відповідь Маріан нижче, вона дуже елегантна.
— Alojz Janez

Я згоден з тим, що прохання - це шлях у наші дні. Я підтримав цей коментар та відповідь Маріан, але я залишаю відповідь як присуджену, оскільки вона була найкращою на той час.
— Джон

1
Нагороди @John хороші, але час іде, і це сайт, відредагований спільнотою. Основна увага приділяється хорошим відповідям, а не людям. Він буде дотримуватися своїх очок підтримки. Ви вводите в оману багато інших програмістів у застарілі бібліотеки.
— mit

1
Гаразд, справедливо. Я прийняв відповідь на запити.
— Джон

Відповіді:


180

Ось спосіб запитів :

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

5
Тоді подивіться на те, r.headers['Location']куди б це вас відправило
— patricksurry

Зверніть увагу, що, схоже, запити нормалізуються Locationдо location.
— Хаміш,

2
@Hamish requestsдозволяє отримати доступ до заголовків як у канонічній формі, так і в нижньому регістрі. Див. Docs.python-requests.org/en/master/user/quickstart/…
— Маріан

1
Починаючи з 2019 року в Python 3, це більше не працює для мене. (Я отримую ключову помилку з
— Макс фон Гіппель

35

Dive Into Python має хороший розділ про обробку переспрямувань за допомогою urllib2. Іншим рішенням є 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
Кожен, хто приходить сюди з Google, зауважте, що сучасний шлях - це stackoverflow.com/a/14678220/362951 Бібліотека запитів позбавить вас від головного болю.
— mit

Посилання на "Занурення в Python" мертве.
— guettli

11

Це обробник urllib2, який не буде слідувати за переспрямуваннями:

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)

Я модульно тестую API і маю справу з методом входу, який перенаправляє на сторінку, яка мене не хвилює, але не надсилає бажаний сеансовий файл cookie з відповіддю на перенаправлення. Це саме те, що мені для цього було потрібно.
— Тім Уайлдер

9

Ключовим redirectionsсловом у httplib2методі запиту є червоний оселедець. Замість того, щоб повернути перший запит, він викличе RedirectLimitвиняток, якщо отримає код стану перенаправлення. Щоб повернути щіток відповідь вам потрібно встановити , follow_redirectsщоб Falseна Httpоб'єкті:

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

8

я думаю, це допомогло б

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

Я другий вказівник olt на Dive into Python . Ось реалізація з використанням обробників перенаправлення urllib2, більше роботи, ніж повинна бути? Може, знизати плечима.

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
Виглядає неправильно ... Цей код насправді слідує за перенаправленнями (викликаючи вихідний обробник, таким чином видаючи запит HTTP), а потім викликає виняток
— Carles Barrobés

5

Однак найкоротший шлях є

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

noredir_opener = urllib2.build_opener(NoRedirect())

1
Як це найкоротший шлях? Він навіть не містить імпорту або фактичного запиту.
— Маріан

Я вже збирався опублікувати це рішення і був дуже здивований, знайшовши цю відповідь внизу. Це дуже лаконічно і, на мій погляд, має бути головною відповіддю.
— користувач

Більше того, це дає вам більше свободи, таким чином, ви можете контролювати, які URL-адреси слід переходити .
— користувач

Підтверджую, це найпростіший спосіб. Коротке зауваження для тих, хто хоче налагодити. Не забувайте, що при встановленні сошника ви можете встановити декілька обробників, наприклад: opener = urllib.request.build_opener(debugHandler, NoRedirect())де debugHandler=urllib.request.HTTPHandler()і debugHandler.set_http_debuglevel (1). Врешті-решт:urllib.request.install_opener(opener)
— StashOfCode
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.