Requests - это библиотека, которая помогает нам отправлять запросы к различным веб-сервисам и сайтам из нашего Python кода. Представьте, что вы открываете браузер и заходите на какой-то сайт - происходит HTTP запрос. Requests позволяет делать то же самое, но из кода
Давайте сделаем наш первый запрос. Мы попробуем получить информацию о бронированиях с тестового API:
# Делаем GET запрос к APIresponse = requests.get('https://restful-booker.herokuapp.com/booking')# Смотрим, что нам пришлоprint(f"Статус ответа: {response.status_code}")print(f"Тело ответа: {response.text}")
Разберём, что здесь происходит:
requests.get() - это функция, которая отправляет GET запрос по указанному адресу
Результат запроса сохраняется в переменную response по сути это объект, у которого есть различные атрибуты - ниже пару из них
У response есть разные свойства, которые мы можем использовать:
status_code - код ответа (например, 200 означает успех)
text - текст ответа
Работа с JSON данными
Note
Часто API возвращают данные в формате JSON. Requests умеет с ними работать:
import requestsresponse = requests.get('https://restful-booker.herokuapp.com/booking')data = response.json()# Тело ответа в словареprint(f"Тело ответа: {data}")print(f"можно обратиться по ключу, например к первому элементу: {data[0]}")
Note
Метод .json() для объекта response преобразует ответ от сервера в формате json в словарь пайтон.
Таким образом в переменной data будет словарь - json ответ от сервера.
Tip
Попробуем отправить другой запрос: Booking - GetBooking
https://restful-booker.herokuapp.com/booking/:id
Надо передать какой-то id - сделаем это через переменную!
import requestsbooking_id = 1response = requests.get(f'https://restful-booker.herokuapp.com/booking/{booking_id}')data = response.json()# Тело ответа в словареprint(f"Тело ответа: {data}")
Tip
Да, вот так просто можно пихать переменные в урл запроса, а значит и манипулировать ими как нам нужно. Данные которые мы получили в ответе нам понадобятся дальше.
Поэтому приведу их здесь (на момент написания. Это открытое Апи и в момент когда вы пробуете делать тоже самое - ответ может измениться)
Часто нам нужно передать дополнительные параметры в URL. Например, для поиска или фильтрации:
import requests"""response = requests.get(f'https://restful-booker.herokuapp.com/booking?firstname=Sally')"""response = requests.get(f'https://restful-booker.herokuapp.com/booking', params={'firstname': 'Sally'})data = response.json()# Тело ответа в словареprint(f"Тело ответа: {data}")
Можно это сделать это 2-мя путями:
?firstname=Sally просто написать в url - не очень красиво
передать в виде аргумента параметр params который будет содержать словарь параметров. Requests автоматически составит правильный URL
Заголовки запроса
Note
Иногда нам нужно передать дополнительную информацию серверу через заголовки:
import requests# Создаём словарь с заголовкамиheaders = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept': 'application/json'}# Передаём заголовки в запросresponse = requests.get( 'https://restful-booker.herokuapp.com/booking', headers=headers)
Tip
Здесь в requests.get в качестве аргумента headers мы передали переменную содержащую в себе словарь с заголовками
Обработка ошибок
Note
Очень важно правильно обрабатывать возможные ошибки при работе с запросами:
try:# Делаем запрос response = requests.get('https://restful-booker.herokuapp.com/booking')# Проверяем статус ответа response.raise_for_status() # Вызовет исключение, если статус не 2XX# Если всё хорошо, работаем с данными data = response.json() print(f"Получены данные: {data}")except requests.exceptions.ConnectionError: print("Не удалось подключиться к серверу")# Тут можно, например, повторить запрос позжеexcept requests.exceptions.Timeout: print("Сервер не отвечает слишком долго")# Тут можно увеличить время ожидания и повторитьexcept requests.exceptions.HTTPError as http_err: print(f"Произошла HTTP ошибка: {http_err}")# Например, можно проверить статус код и принять решение что делатьexcept requests.exceptions.RequestException as e: print(f"Произошла ошибка при выполнении запроса: {e}")# Это общий класс ошибок requests
POST запросы
Note
Когда нам нужно отправить данные на сервер, мы используем POST запрос:
При передаче в параметр json= словарь пайтон из переменной data преобразуется в json и запрос отправляется на сервер.
Так же обрати внимание, что у requests мы используем метод .post, а не .get
В этом плане все удобно и очевидно
🧪Практические задания
Example
Задание 1
Напишите тест, который создает бронирование (запрос который использовался в теме про POST запросы)
URL по которому обращаемся положить в переменную URL чтобы каждый раз не писать/копировать/вставлять его
Поскольку это тест, то нужно соответственно сделать asserts для проверки
Пусть это будет “ответ от сервера == 200”
Задание 2
Сделать апгрейд теста
После создания бронирования, из тела ответа от сервера нужно получить id бронирования
В тесте выполнить запрос get, где в пути будет указан id бронирования. Ассертами убедиться, что ответ успешен, а имя совпадает с тем, что было отправлено при пост запросе.
Request объект
Вводная информация
Tip
Каждый раз, когда вызывается requests.get() или аналогичные методы, выполняются два основных действия.
Создается объект Request, который отправляется на сервер для запроса или получения ресурса.
Генерируется объект Response, как только Requests получает ответ от сервера. Этот объект содержит всю информацию, возвращенную сервером, а также включает объект Request, который вы изначально создали.
Note
Пример простого запроса для получения важной информации с серверов Wikipedia:
r = requests.get('https://en.wikipedia.org/wiki/Monty_Python')
Note
Если нужно получить заголовки, которые сервер отправил в ответ, можно сделать следующее:
r.headers
Info
Пример вывода:
{ 'content-length': '56170', 'x-content-type-options': 'nosniff', 'x-cache': 'HIT from cp1006.eqiad.wmnet, MISS from cp1010.eqiad.wmnet', 'content-encoding': 'gzip', 'age': '3080', 'content-language': 'en', 'vary': 'Accept-Encoding,Cookie', 'server': 'Apache', 'last-modified': 'Wed, 13 Jun 2012 01:33:50 GMT', 'connection': 'close', 'cache-control': 'private, s-maxage=0, max-age=0, must-revalidate', 'date': 'Thu, 14 Jun 2012 12:59:39 GMT', 'content-type': 'text/html; charset=UTF-8', 'x-cache-lookup': 'HIT from cp1006.eqiad.wmnet:3128, MISS from cp1010.eqiad.wmnet:80'}
Tip
Чтобы получить заголовки, которые вы отправили серверу, можно обратиться к объекту request и затем к его заголовкам:
requests.head(): HEAD-запрос (получение только заголовков ответа).
requests.options(): OPTIONS-запрос (получение информации о доступных методах для ресурса).
Note
У библиотеки requests есть метод request(), который позволяет передавать HTTP-метод в виде параметра. Это более общий и гибкий способ отправки запросов, чем использование отдельных методов get(), post(), put()
Дополнительные параметры, такие же, как и у методов get(), post() и т.д. (например, params, data, json, headers, cookies, auth, timeout)
"""То есть абсолютно идентичны следующие варианты написания:"""base_url = 'https://restful-booker.herokuapp.com/booking'response = requests.get(url=base_url)response = requests.request(method="GET", url=base_url)
Файлы для отправки (multipart/form-data). Значения словаря должны быть файлоподобными объектами или кортежами (filename, fileobject).
{“file”: open(“my_file.txt”, “rb”)} или {“file”: (“my_file.txt”, open(“my_file.txt”, “rb”), “text/plain”)}
auth
tuple ((username, password)) или объект AuthBase
Аутентификация.
(“myuser”, “mypassword”)
payload или body
Note
Отправка пейлоада в запросе
Пейлоад — это данные, которые вы отправляете на сервер вместе с запросом (обычно в POST, PUT, PATCH). requests предоставляет несколько способов отправки пейлоада, в зависимости от формата данных
Параметр data
Tip
Параметр data используется для отправки данных в формате x-www-form-urlencoded (как обычная HTML-форма) или в виде произвольной строки (например, XML, plain text).
x-www-form-urlencoded (словарь или список кортежей):
import requestsurl = "https://httpbin.org/post"data = {"key1": "value1", "key2": "value2"}response = requests.post(url, data=data) # requests сам кодирует словарь в x-www-form-urlencodedprint(response.request.body) # Показывает закодированное тело запросаprint(response.text)
Tip
В этом случае requests автоматически кодирует словарь data в строку вида key1=value1&key2=value2.
Здесь данные отправляются как есть, без кодирования. Важно правильно установить заголовок Content-Type, чтобы сервер знал, как интерпретировать данные (например, Content-Type: application/xml или Content-Type: text/plain).
Параметр json
Tip
Параметр json используется для отправки данных в формате JSON. requests автоматически сериализует переданный объект Python (обычно словарь или список) в JSON
import requestsurl = "https://httpbin.org/post"data = {"key1": "value1", "key2": "value2"}response = requests.post(url, json=data) # requests автоматически сериализует в JSONprint(response.request.body) # Показывает JSON в теле запросаprint(response.json()) # Декодированный JSON ответ сервера
Tip
В этом случае requests преобразует словарь data в JSON-строку {"key1": "value1", "key2": "value2"} и устанавливает заголовок Content-Type: application/json
🧪Практическое задание
Example
Задание 1:
Отправить POST запрос, урл и дата ниже, передав payload в параметр json:
(ответ от сервера можно напечатать как print(response.text) )
(посмотреть тело отправки запроса print(response.request.body) )
response.text декодирует содержимое ответа в строку Unicode. requests автоматически декодирует байты, полученные от сервера, в строку Unicode, что позволяет легко работать с текстовыми данными
import requestsurl = "https://httpbin.org/get" # Простой эндпоинт, возвращающий информацию о запросеresponse = requests.get(url)if response.status_code == 200: # Проверяем успешность запроса print(f"Текст ответа:\n{response.text}") # Выводим текст ответаelse: print(f"Ошибка запроса: {response.status_code}") print(f"Текст ошибки:\n{response.text}") # Выводим текст ошибки, если она
Разъяснения:
response.text: Этот атрибут содержит декодированное текстовое содержимое ответа. requests пытается автоматически определить кодировку, используя заголовки Content-Type ответа
Unicode: Текст, полученный через response.text, представлен в кодировке Unicode, что позволяет корректно отображать символы различных языков
Пример с ошибкой: В примере добавлен вывод текста ошибки, если запрос не успешен. Это для отладки
Пустой ответ: Если сервер возвращает пустой ответ (например, с кодом 204 No Content или в результате ошибки), response.text будет содержать пустую строку ("")
Ошибка 500 (Internal Server Error): Если сервер возвращает ошибку 500, содержимое ответа может быть различным. Часто это HTML-страница с сообщением об ошибке, но может быть и пустой ответ, или даже JSON с описанием ошибки (хотя это менее распространено для 500).
Если ответ — HTML: response.text будет содержать HTML-код страницы ошибки
Если ответ пустой: response.text будет пустой строкой
Кодировка (Опционально)
Tip
Кодировки и response.encoding
Кодировка определяет, как символы представляются в виде байтов. Разные кодировки используют разные наборы символов и правила их преобразования в байты
requests пытается автоматически определить кодировку ответа. Эта определенная кодировка хранится в атрибуте response.encoding
В большинстве случаев автоматическое определение кодировки работает корректно, и вам не нужно ничего менять. Однако в редких случаях, когда автоматическое определение неверно, вы можете явно указать кодировку, изменив значение response.encodingперед обращением к response.text
Пример (демонстрационный):
import requestsurl = "https://httpbin.org/encoding/utf8" # Пример, где httpbin сообщает кодировку utf-8response = requests.get(url)print(f"Кодировка до изменения: {response.encoding}")print(f"Текст до изменения:\n{response.text}")response.encoding = 'utf-8' # Явно устанавливаем utf-8 (в данном случае это избыточно, так как httpbin уже указал эту кодировку)print(f"Кодировка после изменения: {response.encoding}")print(f"Текст после изменения:\n{response.text}")url_latin = "https://httpbin.org/encoding/utf8" # Пример, где мы *ошибочно* предполагаем latin1response_latin = requests.get(url_latin)response_latin.encoding = 'latin1' # *Неправильная* кодировка, приведет к искажению текстаprint(f"Текст с (неправильной) кодировкой latin1:\n{response_latin.text}")# Правильный подход:response_latin_correct = requests.get(url_latin)response_latin_correct.encoding = response_latin_correct.apparent_encoding # используем apparent_encodingprint(f"Текст с (автоматически определенной) кодировкой:\n{response_latin_correct.text}")
Разъяснения:
response.encoding: Содержит текущую кодировку
Изменение response.encoding: Изменение этого атрибута влияет на то, как response.text декодирует байты
apparent_encoding: Если сервер не указал кодировку явно, можно воспользоваться методом response.apparent_encoding, который пытается угадать кодировку по содержимому ответа
Важно: Изменять кодировку нужно только в случае необходимости, когда автоматическое определение неверно. В большинстве случаев это не требуется. Использование неправильной кодировки приведет к искажению текста (кракозябры)
Работа с JSON ответами
Note
Если ответ имеет формат JSON, используйте метод response.json() для его декодирования в объект Python (словарь или список):
Исключение requests.exceptions.JSONDecodeError. Это исключение возникает, если содержимое ответа не является валидным JSON. Например, если сервер вернул HTML-страницу с ошибкой или просто пустой ответ
Мы можем обрабатывать исключение requests.exceptions.JSONDecodeError, например:
try: data = response.json() # Пытаемся декодировать JSON print(type(data)) # Выведет <class 'dict'> print(data) # Выведет содержимое JSON print(data['slideshow']['author']) # Доступ к вложенным элементамexcept requests.exceptions.JSONDecodeError as e: print(f"Ошибка декодирования JSON: {e}") print(f"Текст ответа: {response.text}") # Выводим текст ответа для отладкиexcept Exception as e: print(f"Другая ошибка: {e}")
Info
Давайте попробуем на практике на это дело посмотреть:
import requestsurls = [ "https://httpbin.org/json", # Нормальный JSON "https://httpbin.org/status/204", # Пустой ответ "https://httpbin.org/status/500", # Ошибка 500 "https://httpbin.org/html", # HTML]for url in urls: print(f"URL: {url}") response = requests.get(url) print(f"Status code: {response.status_code}") try: data = response.json() print(f"JSON data: {data}") except requests.exceptions.JSONDecodeError: print(f"Ошибка декодирования JSON. Текст ответа: {response.text}") # Выводим первые 100 символов except Exception as e: print(f"Другая ошибка: {e}") print("-" * 20)
Tip
Скопируйте этот код и запустите его. В выводе надо обратить внимание, что в некоторых частях response.text ничего не выводит (пустая строка), но и исключение мы обработали
🧪Практическое задание:
Example
Скопировать код выше и запустить его
Написать запрос без обработки ошибок на url “https://httpbin.org/status/204” и попробовать преобразовать json.
Ознакомиться с результатом работы (исключением)
Обработка XML и HTML
Note
Данный контент для общего понимания. Вряд ли вы с ним столкнетесь, а если и столкнетесь - то документации или чат в помощь. Все же мы будем опираться в курсе на text или json
Note
Для обработки XML и HTML рекомендуется использовать сторонние библиотеки, такие как lxml или Beautiful Soup:
import requestsfrom bs4 import BeautifulSoup # Для HTMLimport lxml.etree as ET # Для XMLurl_html = "https://httpbin.org/html"response_html = requests.get(url_html)soup = BeautifulSoup(response_html.text, 'html.parser')print(soup.title)url_xml = "https://www.w3schools.com/xml/note.xml"response_xml = requests.get(url_xml)tree = ET.fromstring(response_xml.content)print(tree.find('to').text)
Сессии в requests
Tip
Сессия в requests представлена объектом requests.Session. Она позволяет сохранять состояние между несколькими запросами к одному и тому же серверу. Это особенно полезно для:
Сохранения cookies: Автоматическое управление cookies между запросами
Повторного использования соединений: Ускорение последующих запросов за счет повторного использования TCP-соединений (пулинг соединений)
Установки параметров по умолчанию: Установка заголовков, параметров аутентификации и других настроек, которые будут применяться ко всем запросам в рамках сессии
Механика Session объекта
Tip
Когда вы создаете объект Session, requests создает контейнер для хранения состояния. При каждом запросе, сделанном с помощью этого объекта, requests автоматически добавляет сохраненные cookies, заголовки и другие параметры к запросу. Ответ сервера также обрабатывается, и новые cookies сохраняются в сессии
Постоянные параметры
Tip
Вы можете установить параметры по умолчанию для всех запросов в рамках сессии. Это делается с помощью атрибутов объекта Session:
s = requests.Session(): Создаем экземпляр объекта Session и присваиваем его переменной s. Это создает контейнер для хранения состояния сессии, включая постоянные параметры
Note
3️⃣
s.headers.update({'User-Agent': 'My Custom Bot'}): Здесь мы устанавливаем постоянный заголовокUser-Agent. Метод update() объекта s.headers (который является словарем) добавляет или обновляет указанный заголовок. Теперь каждый запрос, сделанный с использованием этой сессии s, будет автоматически включать заголовок User-Agent: My Custom Bot
Note
4️⃣
s.auth = ('user', 'password'): Устанавливаем постоянную аутентификацию Basic Auth. Кортеж ('user', 'password') содержит имя пользователя и пароль. Теперь каждый запрос с этой сессией будет автоматически отправлять заголовок Authorization с закодированными учетными данными
Note
5️⃣
response = s.get('https://httpbin.org/headers'): Выполняем GET-запрос к URL https://httpbin.org/headers. Сервис httpbin.org/headers возвращает заголовки, которые были отправлены в запросе
Важно: Перед отправкой запроса сессия sавтоматически добавляет к нему постоянные параметры: заголовок User-Agent и заголовок Authorization (для аутентификации)
print(response.json()) выводит JSON-ответ, который содержит все заголовки, полученные сервером. Вы увидите, что User-Agent установлен в My Custom Bot, а также будет присутствовать заголовок Authorization
Note
6️⃣
response2 = s.post('https://httpbin.org/post', json={"data": "test"}): Выполняем POST-запрос к URL https://httpbin.org/post с JSON-данными {"data": "test"}
Важно: Как и в предыдущем случае, сессия sавтоматически добавляет к этому запросу те же самые постоянные параметры: заголовок User-Agent и заголовок Authorization. Кроме того, поскольку мы использовали параметр json=..., requests автоматически устанавливает заголовок Content-Type: application/json
print(response2.json()) выводит JSON-ответ сервера, который содержит информацию о запросе, включая отправленные данные и заголовки
Note
Ключевые моменты:
Параметры, установленные непосредственно в методах запроса (get(), post(), и т.д.), применяются только к этому конкретному запросу
Параметры, установленные на уровне сессии (с помощью s.headers, s.auth, s.proxies, s.cookies и т.д.), применяются ко всем запросам, сделанным с использованием этой же сессии
Постоянные параметры не перезаписывают параметры, указанные на уровне метода. Если вы укажете заголовок User-Agent как в сессии, так и в методе get(), значение, указанное в методе, будет иметь приоритет для этого конкретного запроса
Сохранение состояния между запросами
Note
Главное преимущество сессии — сохранение состояния. Рассмотрим пример с cookies:
import requestss = requests.Session()# Первый запрос (сервер устанавливает cookie)response1 = s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')print(response1.text)# Второй запрос (cookie автоматически отправляется)response2 = s.get('https://httpbin.org/cookies')print(response2.json()) # Видим, что cookie был отправлен
Параметры на уровне метода не сохраняются
Note
Параметры, указанные на уровне метода, не сохраняются между запросами, даже если используется сессия:
s = requests.Session()# Указываем cookie для первого запросаr = s.get('https://httpbin.org/cookies', cookies={'from-my': 'browser'})print(r.text)# Вывод: '{"cookies": {"from-my": "browser"}}'# Второй запрос не использует cookier = s.get('https://httpbin.org/cookies')print(r.text)# Вывод: '{"cookies": {}}'
Question
Почему? Разбираем:
Первый пример - почему кука сохранилась
s = requests.Session(): Создается объект сессии s. Этот объект будет хранить состояние между запросами, включая куки
response1 = s.get('https://httpbin.org/cookies/set/sessioncookie/123456789'): Выполняется GET-запрос к URL https://httpbin.org/cookies/set/sessioncookie/123456789. Этот URL на сервисе httpbin.org специально предназначен для установки куки. Сервер в ответ на этот запрос отправляет заголовок Set-Cookie, который указывает браузеру (в данном случае, requests) сохранить куку с именем sessioncookie и значением 123456789
Важно: Объект сессии sавтоматически обрабатывает заголовок Set-Cookie из ответаresponse1 и сохраняет полученную куку внутри себя
response2 = s.get('https://httpbin.org/cookies'): Выполняется второй GET-запрос, используя ту же самую сессию s
Ключевой момент:сервер устанавливает куку, а сессия requests автоматически ее сохраняет
Второй пример - почему кука не сохранилась в сессии
s = requests.Session(): Создается объект сессии s
r = s.get('https://httpbin.org/cookies', cookies={'from-my': 'browser'}): Выполняется GET-запрос, и при этом кука from-my=browser передается непосредственно в параметре cookies метода get()
Важно: Кука {'from-my': 'browser'} была отправлена только для этого конкретного запроса. Объект сессии sне сохраняет эту куку автоматически, потому что она была передана на уровне метода, а не установлена сервером с помощью заголовка Set-Cookie.
r = s.get('https://httpbin.org/cookies'): Выполняется второй GET-запрос, используя ту же самую сессию s
Ключевой момент: Так как сессия sне сохранила куку из предыдущего запроса (она была передана только для одного запроса), во втором запросе заголовок Cookie отсутствует
🧪Практическое задание
Example
Берем код из примера - повторяем, смотрим вывод
В идеале еще код и руками переписать
Конфигурация сессий
Основные настройки сессий:
headers: Постоянные заголовки.
auth: Постоянная аутентификация.
proxies: Постоянные прокси.
cookies: Куки, которые будут отправляться с каждым запросом.
verify: Проверка SSL-сертификата (по умолчанию True)
cert: Путь к файлу сертификата клиента (для клиентской аутентификации)
timeout: Таймаут по умолчанию для запросов
max_redirects: Максимальное количество перенаправлений
Настройка постоянных заголовков
Как показано в примере выше, заголовки можно установить с помощью s.headers.update()
Управление cookie
Куки можно получить из ответа с помощью response.cookies (это объект RequestsCookieJar) и установить в сессии с помощью s.cookies.update()
Сравниваем скорость
Info
Давайте взглянем на простую демонстрацию:
import requestsimport timeurl = "https://httpbin.org/get"num_requests = 10print("Запросы с использованием сессии:")start_time = time.time()session = requests.Session() # Создаем сессиюtry: for i in range(num_requests): response = session.get(url) response.raise_for_status()except Exception as e: print(f"ошибка: {e}")finally: session.close() # закрываем сессиюend_time = time.time()print(f"Время выполнения с сессией: {end_time - start_time:.4f} секунд\n")# Запросы БЕЗ использования сессии:print("Запросы БЕЗ использования сессии:")start_time = time.time()try: for i in range(num_requests): response = requests.get(url) response.raise_for_status()except Exception as e: print(f"Ошибка: {e}")end_time = time.time()print(f"Время выполнения без сессии: {end_time - start_time:.4f} секунд")
Разбор кода по шагам:
1. Импорт модулей:
import requests: Импортирует библиотеку requests для выполнения HTTP-запросов
import time: Импортирует модуль time для измерения времени выполнения
2. Определение параметров:
url = "https://httpbin.org/get": Определяет URL-адрес, к которому будут отправляться запросы. https://httpbin.org/get — это эндпоинт, который возвращает информацию о запросе (включая заголовки, IP-адрес и т. д.)
num_requests = 10: Определяет количество запросов, которые будут выполнены в каждом тесте (с сессией и без)
3. Запросы с использованием сессии:
print("Запросы с использованием сессии:"): Выводит сообщение о начале теста с сессией
start_time = time.time(): Записывает текущее время перед началом выполнения запросов
session = requests.Session(): Создает объект сессии. Это ключевой момент. Сессия будет использоваться для всех последующих запросов
try...except...finally: Блок обработки исключений
try: Внутри этого блока выполняются запросы.
for i in range(num_requests):: Цикл, выполняющий num_requests запросов
response = session.get(url): Выполняет GET-запрос к указанному URL, используя созданную сессию
response.raise_for_status(): Проверяет код статуса HTTP-ответа. Если код находится в диапазоне 4xx или 5xx (ошибки), выбрасывается исключение requests.exceptions.HTTPError. Это позволяет обрабатывать ошибки запросов
except Exception as e: Обрабатывает любые исключения, которые могут возникнуть во время выполнения запросов (например, ошибки соединения, таймауты и т. д.). Выводит сообщение об ошибке
finally: Блок, который выполняется всегда, независимо от того, произошло исключение или нет
session.close(): Закрывает сессию. Это очень важно для освобождения ресурсов
end_time = time.time(): Записывает текущее время после завершения выполнения запросов
print(f"Время выполнения с сессией: {end_time - start_time:.4f} секунд\n"): Выводит время, затраченное на выполнение всех запросов с использованием сессии
4. Запросы БЕЗ использования сессии:
print("Запросы БЕЗ использования сессии:"): Выводит сообщение о начале теста без сессии
start_time = time.time(): Записывает текущее время перед началом выполнения запросов
try...except: Блок обработки исключений (блок finally здесь не нужен, так как сессия не создается)
for i in range(num_requests):: Цикл, выполняющий num_requests запросов
response = requests.get(url): Выполняет GET-запрос к указанному URL. Каждый раз создается новое соединение
response.raise_for_status(): Проверяет код статуса ответа
except Exception as e: Обрабатывает возможные исключения
end_time = time.time(): Записывает текущее время после завершения выполнения запросов
print(f"Время выполнения без сессии: {end_time - start_time:.4f} секунд"): Выводит время, затраченное на выполнение всех запросов без использования сессии
Example
А вот на сами результаты я предлагаю вам посмотреть самостоятельно!
Скопируйте код и запустите его. Полагаю результаты произведут впечатление
Механизмы аутентификации
Базовая аутентификация (Basic Authentication)
Tip
Basic Auth — это простой метод аутентификации, где имя пользователя и пароль передаются серверу. requests предоставляет удобный способ использования Basic Auth с помощью параметра auth
from requests.auth import HTTPBasicAuth: Импортируем класс HTTPBasicAuth. Этот класс отвечает за форматирование учетных данных для Basic Auth
auth=HTTPBasicAuth('user', 'passwd'): Параметр auth принимает экземпляр класса HTTPBasicAuth, которому передаются имя пользователя и пароль в виде строк. requests автоматически выполняет кодирование учетных данных в Base64 и добавляет заголовок Authorization в запрос
response.status_code: Код статуса HTTP-ответа. 200 означает успешную аутентификацию
response.json(): Преобразует JSON-ответ в словарь Python. В данном случае, если аутентификация успешна, httpbin возвращает JSON с информацией об аутентифицированном пользователе
Question
Что происходит “под капотом” при использовании auth?
Когда вы используете auth=HTTPBasicAuth('user', 'passwd'), requests выполняет следующие действия:
Формирует строку username:password
Кодирует эту строку в Base64
Создает заголовок Authorization в формате Basic <encoded_credentials>, где <encoded_credentials> — это строка в Base64
Отправляет запрос с этим заголовком
Note
Вам не нужно беспокоиться о ручном кодировании, HTTPBasicAuth делает это за вас.
Пример с неправильными учетными данными:
import requestsfrom requests.auth import HTTPBasicAuthurl = "https://httpbin.org/basic-auth/user/passwd"response_wrong = requests.get(url, auth=HTTPBasicAuth('wrong_user', 'wrong_passwd'))print(f"Status code (wrong credentials): {response_wrong.status_code}") # Статус код будет 401 (Unauthorized)print(response_wrong.text) # Тело ответа будет содержать сообщение об ошибке
Tip
В этом случае сервер вернет код состояния 401 Unauthorized, показывая, что аутентификация не удалась.
Bearer Token
Note
Bearer token — это строка (токен), используемая для аутентификации. Обычно передается в заголовке Authorization с префиксом Bearer
headers = {'Authorization': f'Bearer {token}'}: Создаем словарь с заголовком Authorization, значение которого начинается с Bearer, за которым следует сам токен
API Key (ключ API)
Note
API key — это строка, идентифицирующая приложение или пользователя. API key может передаваться разными способами, но чаще всего в заголовке или параметре запроса
Все аналогично bearer
Пример (в заголовке X-API-Key):
import requestsurl = "https://httpbin.org/headers"api_key = "my_api_key"headers = {'X-API-Key': api_key}response = requests.get(url, headers=headers)print(f"Status code: {response.status_code}")print(response.json()) # В json будет информация о переданных заголовках, включая X-API-Key
Пример (в параметре запроса):
import requestsurl = "https://httpbin.org/get"api_key = "my_api_key"params = {'api_key': api_key}response = requests.get(url, params=params)print(f"Status code: {response.status_code}")print(response.json()) # В json будет информация о переданных параметрах, включая api_key
Refresh Token
Tip
Refresh Token - это специальный токен, который используется для обновления access токена (токена доступа). Access токен имеет ограниченный срок действия, и когда он истекает, пользователь должен снова авторизоваться. Чтобы избежать этого, используется refresh токен. Он имеет более длительный срок действия и позволяет получить новый access токен без повторной авторизации пользователя.
Процесс обновления access токена выглядит так:
Пользователь получает access токен и refresh токен при авторизации
Когда срок действия access токена истекает, приложение отправляет запрос на сервер с refresh токеном
Сервер проверяет refresh токен и, если он действителен, выдает новый access токен и, возможно, новый refresh токен - тут уже зависит от реализации
Приложение сохраняет новый access токен и refresh токен (если он был обновлен) и использует новый access токен для дальнейших запросов
Пример использования
import requestsREFRESH_TOKEN_URL = "https://example.com/api/token/refresh"refresh_token = "YOUR_REFRESH_TOKEN"def refresh_access_token(refresh_token): """Обновляет access токен с помощью refresh токена.""" data = {"refresh_token": refresh_token} response = requests.post(REFRESH_TOKEN_URL, json=data) if response.status_code == 200: new_access_token = response.json().get("access_token") new_refresh_token = response.json().get("refresh_token") return new_access_token, new_refresh_token else: print(f"Ошибка обновления токена: {response.status_code}") return None, None# Получаем оба токенаnew_access_token, new_refresh_token = refresh_access_token(refresh_token)if new_access_token: print(f"Новый access токен: {new_access_token}") if new_refresh_token: print(f"Новый refresh токен: {new_refresh_token}") # Дальше суем в заголовок/куки - в зависимости от реализации headers = {"Authorization": f"Bearer {new_access_token}"} response = requests.get("https://example.com/api/protected", headers=headers) # ...
OAuth2
Tip
OAuth2 (Open Authorization) - это протокол авторизации, который предоставляет сторонним приложениям ограниченный доступ к ресурсам пользователя на другом сервисе, не требуя передачи логина и пароля
Сравним чем отличается от просто авторизации по логин-паролю:
Note
1️⃣
OAuth2: Вместо передачи логина и пароля, приложение получает специальный токен доступа (access token), который используется для доступа к ресурсам пользователя. Даже в случае компрометации токена, пароль пользователя остается защищенным
Простая авторизация: Приложение получает доступ к логину и паролю пользователя, что создает риск их компрометации
Note
2️⃣
OAuth2: предоставляет приложению только те права доступа, которые необходимы для его работы. Например, приложение может получить доступ только к чтению профиля пользователя, но не к его электронной почте
Простая авторизация: Обычно предоставляет приложению полный доступ к ресурсам пользователя
Note
3️⃣
OAuth2: Пользователь может в любой момент отозвать доступ приложения к своим ресурсам
Простая авторизация: Для отзыва доступа часто требуется изменение пароля
Note
4️⃣
OAuth2: Позволяет пользователю делегировать доступ к своим ресурсам сторонним приложениям, сохраняя контроль над своими данными
Простая авторизация: Не предоставляет таких возможностей
Схема работы OAuth2
Note
1️⃣
Приложение запрашивает у пользователя разрешение на доступ к его ресурсам на сервере авторизации (например, Google, Facebook и т.д.)
Note
2️⃣
Пользователь предоставляет разрешение, и сервер авторизации выдает приложению токен доступа.
Note
3️⃣
Приложение использует токен для доступа к ресурсам пользователя на сервере ресурсов (это может быть тот же сервер авторизации или другой сервер)
Info
Выглядит это точно так же как и обычная авторизация, но все же: