Подтвердить что ты не робот

Почему Python urllib2.urlopen() повышает HTTPError для успешных кодов состояния?

Согласно документации urllib2,

Поскольку обработчики по умолчанию обрабатывают перенаправления (коды в диапазоне 300), а коды в диапазоне 100-299 указывают на успех, вы обычно увидите только коды ошибок в диапазоне 400-599.

И все же следующий код

request = urllib2.Request(url, data, headers)
response = urllib2.urlopen(request)

вызывает HTTPError с кодом 201 (созданный):

ERROR    2011-08-11 20:40:17,318 __init__.py:463] HTTP Error 201: Created

Итак, почему urllib2 бросает HTTPErrors на этот успешный запрос?

Это не слишком большая боль; Я могу легко расширить код до:

try:
    request = urllib2.Request(url, data, headers)
    response = urllib2.urlopen(request)
except HTTPError, e:
    if e.code == 201:
        # success! :)
    else:
        # fail! :(
else:
    # when will this happen...?

Но это не похоже на предполагаемое поведение, основанное на документации и на то, что я не могу найти похожие вопросы об этом нечетном поведении.

Кроме того, что должен ожидать блок else? Если успешные коды состояния интерпретируются как HTTPError s, тогда, когда urllib2.urlopen() просто возвращает нормальный файл-подобный объект ответа как и вся документация urllib2, относится к?

4b9b3361

Ответ 1

Как указано в фактической документации библиотеки:

Для 200 кодов ошибок объект ответа немедленно возвращается.

Для кодов ошибок, отличных от 200, это просто передает задание методам обработчика протокола_error_code через OpenerDirector.error(). В конце концов, urllib2.HTTPDefaultErrorHandler поднимет HTTPError, если никакой другой обработчик не обработает ошибку.

http://docs.python.org/library/urllib2.html#httperrorprocessor-objects

Ответ 2

Вы можете написать собственный Handler класс для использования с urllib2, чтобы предотвратить появление определенных кодов ошибок в качестве HTTError. Здесь я использовал раньше:

class BetterHTTPErrorProcessor(urllib2.BaseHandler):
    # a substitute/supplement to urllib2.HTTPErrorProcessor
    # that doesn't raise exceptions on status codes 201,204,206
    def http_error_201(self, request, response, code, msg, hdrs):
        return response
    def http_error_204(self, request, response, code, msg, hdrs):
        return response
    def http_error_206(self, request, response, code, msg, hdrs):
        return response

Затем вы можете использовать его как:

opener = urllib2.build_opener(self.BetterHTTPErrorProcessor)
urllib2.install_opener(opener)

req = urllib2.Request(url, data, headers)
urllib2.urlopen(req)

Ответ 3

Лично я считаю, что это было ошибкой и очень не интуитивно понятно, что это поведение по умолчанию. Это правда, что не-2XX коды подразумевают ошибку уровня протокола, но превращать это в исключение слишком далеко (по моему мнению, по крайней мере).

В любом случае, я думаю, что самый элегантный способ избежать этого:

opener = urllib.request.build_opener()
for processor in opener.process_response['https']: # or http, depending on what you're using
   if isinstance(processor, urllib.request.HTTPErrorProcessor): # HTTPErrorProcessor also for https
       opener.process_response['https'].remove(processor)
       break # there only one such handler by default
response = opener.open('https://www.google.com')

Теперь у вас есть объект ответа. Вы можете проверить это код состояния, заголовки, тело и т.д.