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

101

Глядя на источник urllib2, кажется, что самый простой способ сделать это - создать подкласс HTTPRedirectHandler, а затем использовать build_opener для переопределения HTTPRedirectHandler по умолчанию, но это похоже на много (относительно сложную) работу, чтобы сделать то, что кажется, должно быть довольно просто.

Джон
источник
2
Для гуглеров: использование библиотеки запросов избавит вас от много головной боли: docs.python-requests.org и см. Ответ Мэриан ниже, он очень элегантен.
Alojz Janez
Я согласен, что запросы - это то, что нужно в наши дни. Я поддержал этот комментарий и ответ Мэриан, но оставляю ответ награжденным, поскольку он был лучшим на то время.
Джон
1
Награды @John хороши, но время идет, и это сайт, редактируемый сообществом. Акцент делается на хороших ответах, а не на людях. Он сохранит свои очки поддержки. Вы вводите в заблуждение множество коллег-программистов в устаревшие библиотеки.
mit
1
Хорошо, достаточно честно. Я принял ответ на запрос.
Джон

Ответы:

186

Вот способ запросов :

import requests
r = requests.get('http://github.com', allow_redirects=False)
print(r.status_code, r.headers['Location'])
Мариан
источник
6
Тогда посмотрите на , r.headers['Location']чтобы увидеть , где он послал бы вам
patricksurry
Обратите внимание, что похоже, что запросы будут нормализованы Locationдо location.
Хэмиш
2
@Hamish requestsпозволяет получить доступ к заголовкам как в канонической форме, так и в нижнем регистре. См. Docs.python-requests.org/en/master/user/quickstart/…
Мэриан,
1
По состоянию на 2019 год в Python 3 это больше не работает для меня. (Я получаю ключевую ошибку
Макс фон Хиппель
36

В 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
Ссылка на "Dive Into Python" мертва.
guettli 05
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-запрос), а затем
вызывает
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())where debugHandler=urllib.request.HTTPHandler()и debugHandler.set_http_debuglevel (1). В итоге:urllib.request.install_opener(opener)
StashOfCode