Есть ли простой способ запросить 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.