Python requests module exceptions

Руководство по работе с HTTP в Python. Библиотека requests

Стандартная библиотека Python имеет ряд готовых модулей по работе с HTTP.

Если уж совсем хочется хардкора, то можно и сразу с socket поработать. Но у всех этих модулей есть один большой недостатокнеудобство работы.

Во-первых, большое обилие классов и функций. Во-вторых, код получается вовсе не pythonic. Многие программисты любят Python за его элегантность и простоту, поэтому и был создан модуль, призванный решать проблему существующих и имя ему requests или HTTP For Humans. На момент написания данной заметки, последняя версия библиотеки — 2.9.1. С момента выхода Python версии 3.5 я дал себе негласное обещание писать новый код только на Py >= 3.5. Пора бы уже полностью перебираться на 3-ю ветку змеюки, поэтому в моих примерах print отныне является функцией, а не оператором 🙂

Что же умеет requests?

Для начала хочется показать как выглядит код работы с http, используя модули из стандартной библиотеки Python и код при работе с requests. В качестве мишени для стрельбы http запросами будет использоваться очень удобный сервис httpbin.org

 >>> import urllib.request >>> response = urllib.request.urlopen('https://httpbin.org/get') >>> print(response.read()) b', \n "headers": , \n "origin": "95.56.82.136", \n "url": "https://httpbin.org/get"\n>\n' >>> print(response.getheader('Server')) nginx >>> print(response.getcode()) 200 >>> 

Кстати, urllib.request это надстройка над «низкоуровневой» библиотекой httplib о которой я писал выше.

>>> import requests >>> response = requests.get('https://httpbin.org/get') >>> print(response.content) b', \n "headers": , \n "origin": "95.56.82.136", \n "url": "https://httpbin.org/get"\n>\n' >>> response.json() , 'args': <>, 'origin': '95.56.82.136', 'url': 'https://httpbin.org/get'> >>> response.headers >>> response.headers.get('Server') 'nginx' 

В простых методах запросов значительных отличий у них не имеется. Но давайте взглянем на работы с Basic Auth:

 >>> import urllib.request >>> password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() >>> top_level_url = 'https://httpbin.org/basic-auth/user/passwd' >>> password_mgr.add_password(None, top_level_url, 'user', 'passwd') >>> handler = urllib.request.HTTPBasicAuthHandler(password_mgr) >>> opener = urllib.request.build_opener(handler) >>> response = opener.open(top_level_url) >>> response.getcode() 200 >>> response.read() b'\n' 
 >>> import requests >>> response = requests.get('https://httpbin.org/basic-auth/user/passwd', auth=('user', 'passwd')) >>> print(response.content) b'\n' >>> print(response.json())

А теперь чувствуется разница между pythonic и non-pythonic? Я думаю разница на лицо. И несмотря на тот факт, что requests ничто иное как обёртка над urllib3, а последняя является надстройкой над стандартными средствами Python, удобство написания кода в большинстве случаев является приоритетом номер один.

  • Множество методов http аутентификации
  • Сессии с куками
  • Полноценная поддержка SSL
  • Различные методы-плюшки вроде .json(), которые вернут данные в нужном формате
  • Проксирование
  • Грамотная и логичная работа с исключениями
Читайте также:  Нужно ли учить html перед javascript

О последнем пункте мне бы хотелось поговорить чуточку подробнее.

Обработка исключений в requests

При работе с внешними сервисами никогда не стоит полагаться на их отказоустойчивость. Всё упадёт рано или поздно, поэтому нам, программистам, необходимо быть всегда к этому готовыми, желательно заранее и в спокойной обстановке.

Итак, как у requests дела обстоят с различными факапами в момент сетевых соединений? Для начала определим ряд проблем, которые могут возникнуть:

  • Хост недоступен. Обычно такого рода ошибка происходит из-за проблем конфигурирования DNS. (DNS lookup failure)
  • «Вылет» соединения по таймауту
  • Ошибки HTTP. Подробнее о HTTP кодах можно посмотреть здесь.
  • Ошибки SSL соединений (обычно при наличии проблем с SSL сертификатом: просрочен, не является доверенным и т.д.)

Базовым классом-исключением в requests является RequestException. От него наследуются все остальные

И так далее. Полный список всех исключений можно посмотреть в requests.exceptions.

Timeout

В requests имеется 2 вида таймаут-исключений:

  • ConnectTimeout — таймаут на соединения
  • ReadTimeout — таймаут на чтение
>>> import requests >>> try: . response = requests.get('https://httpbin.org/user-agent', timeout=(0.00001, 10)) . except requests.exceptions.ConnectTimeout: . print('Oops. Connection timeout occured!') . Oops. Connection timeout occured! >>> try: . response = requests.get('https://httpbin.org/user-agent', timeout=(10, 0.0001)) . except requests.exceptions.ReadTimeout: . print('Oops. Read timeout occured') . except requests.exceptions.ConnectTimeout: . print('Oops. Connection timeout occured!') . Oops. Read timeout occured 

ConnectionError

 >>> import requests >>> try: . response = requests.get('http://urldoesnotexistforsure.bom') . except requests.exceptions.ConnectionError: . print('Seems like dns lookup failed..') . Seems like dns lookup failed..

HTTPError

 >>> import requests >>> try: . response = requests.get('https://httpbin.org/status/500') . response.raise_for_status() . except requests.exceptions.HTTPError as err: . print('Oops. HTTP Error occured') . print('Response is: '.format(content=err.response.content)) . Oops. HTTP Error occured Response is: b'' 

Я перечислил основные виды исключений, которые покрывают, пожалуй, 90% всех проблем, возникающих при работе с http. Главное помнить, что если мы действительно намерены отловить что-то и обработать, то это необходимо явно запрограммировать, если же нам неважен тип конкретного исключения, то можно отлавливать общий базовый класс RequestException и действовать уже от конкретного случая, например, залоггировать исключение и выкинуть его дальше наверх. Кстати, о логгировании я напишу отдельный подробный пост.

У блога появился свой Telegram канал, где я стараюсь делиться интересными находками из сети на тему разработки программного обеспечения. Велком, как говорится 🙂

Полезные «плюшки»

  • httpbin.org очень полезный сервис для тестирования http клиентов, в частности удобен для тестирования нестандартного поведения сервиса
  • httpie консольный http клиент (замена curl) написанный на Python
  • responses mock библиотека для работы с requests
  • HTTPretty mock библиотека для работы с http модулями

💌 Присоединяйтесь к рассылке

Понравился контент? Пожалуйста, подпишись на рассылку.

Интересные записи:

  • Обзор Python 3.9
  • Почему Python?
  • FastAPI, asyncio и multiprocessing
  • Django Channels: работа с WebSocket и не только
  • Работа с MySQL в Python
  • Введение в logging на Python
  • Pyenv: удобный менеджер версий python
  • Celery: начинаем правильно
  • Что нового появилось в Django Channels?
  • Авторизация через Telegram в Django и Python
  • Итоги первой встречи Python программистов в Алматы
  • Введение в pandas: анализ данных на Python
  • Работа с PostgreSQL в Python
  • Как написать Telegram бота: практическое руководство
  • Разворачиваем Django приложение в production на примере Telegram бота
  • Python-RQ: очередь задач на базе Redis
  • Участие в подкасте TalkPython
  • Обзор Python 3.8
  • Строим Data Pipeline на Python и Luigi
  • Видео презентации ETL на Python

Источник

Оцените статью