Python Requests: современное HTTP в несколько строк кода
Для кого эта статья:
- Разработчики, работающие с Python и API
- Специалисты по автоматизации тестирования и QA-инженеры
Ученики и студенты, изучающие программирование и взаимодействие с веб-сервисами
Когда я впервые столкнулся с необходимостью отправлять HTTP-запросы из Python-скрипта, стандартная библиотека urllib показалась мне излишне сложной и многословной. Всё изменилось, когда я открыл для себя модуль Requests — он произвел революцию в моем подходе к работе с веб-сервисами. Этот инструмент позволяет отправлять HTTP-запросы с элегантной простотой, заворачивая мощный функционал в интуитивно понятный интерфейс. Даже сложные операции, требующие десятков строк с использованием стандартной библиотеки, с Requests выполняются в несколько строк кода. Если вам нужно взаимодействовать с API, парсить веб-страницы или автоматизировать работу с веб-сервисами — этот модуль станет вашим надежным помощником. 🐍
Установка и настройка модуля Requests в Python
Прежде чем погрузиться в мир HTTP-запросов, необходимо правильно установить и настроить модуль Requests. В отличие от многих других библиотек, процесс установки Requests предельно прост и занимает буквально несколько минут.
Начнем с установки. Самый распространенный способ — использование менеджера пакетов pip:
pip install requests
Если вы предпочитаете использовать conda (например, в окружении Anaconda), то команда будет следующей:
conda install -c anaconda requests
После установки рекомендуется проверить корректность процесса. Для этого запустите Python и попробуйте импортировать модуль:
import requests
Если импорт прошел без ошибок, поздравляю — вы готовы к работе! 🎉
Однако перед тем, как начать использовать Requests для отправки HTTP-запросов, стоит обратить внимание на несколько важных аспектов настройки:
- Виртуальное окружение: Рекомендую устанавливать Requests (как и любые другие сторонние пакеты) в виртуальное окружение Python. Это позволит изолировать зависимости вашего проекта.
- Версия: Убедитесь, что вы используете актуальную версию. Проверить установленную версию можно с помощью команды
pip show requests. - SSL-сертификаты: При работе с HTTPS-соединениями важно иметь корректно настроенные сертификаты на вашей системе.
Для удобства сравнения различных методов установки Requests, привожу сводную таблицу:
| Метод установки | Команда | Преимущества | Недостатки |
|---|---|---|---|
| pip | pip install requests | Простота, универсальность, последняя стабильная версия | Требует доступа в интернет |
| conda | conda install -c anaconda requests | Хорошо работает в экосистеме Anaconda | Требует установленной Anaconda |
| pipenv | pipenv install requests | Автоматическое управление виртуальным окружением | Дополнительная сложность в сравнении с pip |
| requirements.txt | pip install -r requirements.txt | Удобно для проектов с несколькими зависимостями | Требует подготовки отдельного файла |
Михаил Орлов, технический архитектор
Помню случай, когда наша команда разрабатывала систему мониторинга для десятков серверов. Мы столкнулись с проблемой: скрипт, использующий Requests, внезапно перестал работать на одном из серверов. Ошибка была крайне неочевидной – выяснилось, что на проблемном сервере была установлена устаревшая версия библиотеки, которая не поддерживала нужные нам функции.
После этого случая я взял за правило всегда указывать конкретную версию Requests в requirements.txt:
requests==2.28.1. Также мы внедрили практику проверки версий всех критических библиотек при запуске системы. Это простое решение сэкономило нам десятки часов на диагностике подобных проблем в будущем.

Основные методы HTTP-запросов в Python Requests
Модуль Requests предоставляет интуитивный интерфейс для работы с основными HTTP-методами. Давайте рассмотрим каждый из них подробно, поскольку они формируют фундамент для взаимодействия с веб-ресурсами. 🔄
GET-запросы
GET-запросы используются для получения данных с сервера. Это наиболее часто используемый тип запроса:
import requests
# Простой GET-запрос
response = requests.get('https://api.github.com/events')
# Проверка статуса ответа
if response.status_code == 200:
print('Успешный запрос!')
# Получаем содержимое ответа в формате JSON
data = response.json()
print(f"Получено {len(data)} событий")
else:
print(f"Ошибка: код {response.status_code}")
POST-запросы
POST-запросы используются для отправки данных на сервер:
# Отправка данных в формате JSON
payload = {'key1': 'value1', 'key2': 'value2'}
response = requests.post('https://httpbin.org/post', json=payload)
# Отправка данных в формате form-data
response = requests.post('https://httpbin.org/post', data={'key': 'value'})
PUT и DELETE
PUT-запросы обычно используются для обновления существующих ресурсов, а DELETE — для их удаления:
# PUT-запрос
response = requests.put('https://httpbin.org/put', data={'key': 'updated_value'})
# DELETE-запрос
response = requests.delete('https://httpbin.org/delete')
Другие HTTP-методы
Requests также поддерживает менее распространенные HTTP-методы, такие как PATCH, OPTIONS и HEAD:
# PATCH-запрос (частичное обновление ресурса)
response = requests.patch('https://httpbin.org/patch', data={'key': 'partial_update'})
# HEAD-запрос (получение только заголовков)
response = requests.head('https://httpbin.org/get')
Для удобства сравнения различных HTTP-методов, рассмотрим следующую таблицу:
| HTTP-метод | Функция в Requests | Типичное применение | Идемпотентность |
|---|---|---|---|
| GET | requests.get() | Получение данных | Да |
| POST | requests.post() | Создание новых ресурсов | Нет |
| PUT | requests.put() | Полное обновление ресурсов | Да |
| PATCH | requests.patch() | Частичное обновление ресурсов | Нет |
| DELETE | requests.delete() | Удаление ресурсов | Да |
| HEAD | requests.head() | Получение только заголовков | Да |
| OPTIONS | requests.options() | Определение возможностей сервера | Да |
Обработка ответов является критически важной частью работы с HTTP-запросами. Requests предоставляет несколько удобных способов анализа полученных данных:
response = requests.get('https://api.github.com/events')
# Статус-код ответа
print(response.status_code) # 200
# Содержимое ответа в виде текста
print(response.text)
# Содержимое ответа в виде байтов
print(response.content)
# Автоматическое декодирование JSON
print(response.json())
# Заголовки ответа
print(response.headers)
# Кодировка ответа
print(response.encoding)
При работе с HTTP-запросами важно также правильно обрабатывать ошибки. Модуль Requests предоставляет специальный метод для автоматического вызова исключения в случае ошибки:
try:
response = requests.get('https://nonexistentwebsite.abc')
response.raise_for_status() # Вызовет исключение при статус-кодах 4xx/5xx
except requests.exceptions.RequestException as err:
print(f"Произошла ошибка: {err}")
Параметры и заголовки запросов: практическое применение
Умение правильно настраивать параметры и заголовки HTTP-запросов — это то, что отличает новичка от профессионала. Грамотное использование этих элементов позволяет существенно расширить возможности вашего кода. 📝
Начнем с URL-параметров. В Requests их можно передавать несколькими способами:
# Способ 1: Передача параметров через params
payload = {'key1': 'value1', 'key2': 'value2'}
response = requests.get('https://httpbin.org/get', params=payload)
print(response.url) # https://httpbin.org/get?key1=value1&key2=value2
# Способ 2: Передача списка значений
payload = {'key1': 'value1', 'key2': ['value2', 'value3']}
response = requests.get('https://httpbin.org/get', params=payload)
print(response.url) # https://httpbin.org/get?key1=value1&key2=value2&key2=value3
Заголовки запросов играют важнейшую роль при взаимодействии с веб-сервисами. Они могут использоваться для передачи метаданных, аутентификации, указания формата содержимого и многого другого:
headers = {
'User-Agent': 'Python Requests App',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
response = requests.get('https://api.github.com/events', headers=headers)
Особое внимание стоит уделить заголовку User-Agent. Многие сервисы блокируют или ограничивают запросы с дефолтным User-Agent из Requests:
# Использование кастомного User-Agent
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
response = requests.get('https://www.example.com', headers=headers)
При работе с файлами Requests предоставляет удобный механизм для загрузки:
files = {'file': ('report.csv', open('report.csv', 'rb'), 'text/csv')}
response = requests.post('https://httpbin.org/post', files=files)
Для обработки куки (cookies) можно использовать как автоматические механизмы, так и ручную настройку:
# Отправка запроса с куки
cookies = {'session_id': '12345', 'user_id': '54321'}
response = requests.get('https://httpbin.org/cookies', cookies=cookies)
# Получение куки из ответа
cookies_received = response.cookies
print(cookies_received.get_dict())
Анна Соколова, QA-инженер автоматизации
В прошлом году я работала над автоматизацией тестирования REST API крупной платформы онлайн-образования. Мы столкнулись с неожиданной проблемой: наши тесты стабильно проходили на локальных машинах, но регулярно падали на CI-сервере.
После долгих часов отладки мы обнаружили, что проблема заключалась в таймаутах — на CI-сервере сеть была менее стабильной. Решение оказалось простым: добавление параметров timeout и retries в наши запросы:
PythonСкопировать кодfrom requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session = requests.Session() retry = Retry(total=5, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504]) adapter = HTTPAdapter(max_retries=retry) session.mount('http://', adapter) session.mount('https://', adapter) # Теперь все запросы будут автоматически повторяться при ошибках response = session.get('https://api.example.com/endpoint', timeout=(3.05, 27))Это небольшое изменение увеличило стабильность наших тестов с 76% до 99.5%. Теперь мы всегда включаем настройку таймаутов и повторов в наши базовые классы для работы с API.
Таймауты и повторные попытки — важнейшие аспекты надежного кода при работе с сетью:
# Установка таймаута (первое число – таймаут соединения, второе – таймаут чтения)
response = requests.get('https://api.github.com', timeout=(3.05, 27))
# Только общий таймаут
response = requests.get('https://api.github.com', timeout=5)
Вот еще несколько полезных параметров для работы с запросами:
- stream=True — позволяет загружать большие файлы частями, без загрузки всего содержимого в память
- verify=False — отключает проверку SSL-сертификата (не рекомендуется для production-кода)
- allow_redirects=False — отключает автоматическое следование по редиректам
- proxies — позволяет настроить прокси-сервер для запросов
# Пример использования прокси
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
response = requests.get('https://example.org', proxies=proxies)
# Потоковая загрузка большого файла
response = requests.get('https://example.com/large_file.zip', stream=True)
with open('large_file.zip', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
Работа с API: аутентификация и обработка ответов
Взаимодействие с API через модуль Requests — это отдельное искусство, требующее понимания не только самой библиотеки, но и принципов работы с различными механизмами аутентификации. 🔐
Начнем с базовой HTTP-аутентификации, которая остается популярной для многих API:
# Базовая HTTP-аутентификация
response = requests.get('https://api.github.com/user', auth=('username', 'password'))
# Альтернативный способ
from requests.auth import HTTPBasicAuth
response = requests.get('https://api.github.com/user', auth=HTTPBasicAuth('username', 'password'))
Для работы с более сложными схемами аутентификации, такими как OAuth, Requests также предлагает элегантные решения:
# OAuth 2.0 аутентификация с использованием токена
headers = {'Authorization': 'Bearer YOUR_ACCESS_TOKEN'}
response = requests.get('https://api.service.com/endpoint', headers=headers)
# Использование OAuth 1.0 аутентификации
from requests_oauthlib import OAuth1
auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET',
'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')
response = requests.get('https://api.twitter.com/1.1/account/verify_credentials.json', auth=auth)
При работе с API критически важно правильно обрабатывать различные форматы ответов. Requests предоставляет удобные инструменты для работы с наиболее распространенными форматами:
# Обработка JSON-ответа
response = requests.get('https://api.github.com/events')
json_data = response.json()
for event in json_data:
print(f"Event ID: {event.get('id')}, Type: {event.get('type')}")
# Обработка XML-ответа
response = requests.get('https://www.w3schools.com/xml/note.xml')
import xml.etree.ElementTree as ET
root = ET.fromstring(response.content)
for child in root:
print(f"{child.tag}: {child.text}")
Одним из ключевых аспектов при работе с API является обработка ошибок и статус-кодов. Умение корректно интерпретировать эти сигналы и реагировать на них позволит вашему коду быть более устойчивым:
response = requests.get('https://api.github.com/repos/invalid/repo')
# Проверка статус-кода
if response.status_code == 200:
print("Успешный запрос")
elif response.status_code == 404:
print("Ресурс не найден")
elif response.status_code == 401:
print("Требуется аутентификация")
elif 500 <= response.status_code < 600:
print("Ошибка на стороне сервера")
Многие API используют пагинацию для возврата больших наборов данных. Вот пример, как можно обработать пагинированные ответы:
# Обработка пагинации в API GitHub
all_events = []
url = 'https://api.github.com/events'
while url:
response = requests.get(url)
all_events.extend(response.json())
# Проверяем наличие ссылки на следующую страницу в заголовках
if 'next' in response.links.keys():
url = response.links['next']['url']
else:
url = None
print(f"Всего собрано {len(all_events)} событий")
Ограничение скорости запросов (rate limiting) — это еще одна важная тема при работе с API. Многие сервисы ограничивают количество запросов, которые вы можете отправить в определенный период времени:
import time
# Простая реализация с контролем скорости запросов
for i in range(10):
response = requests.get('https://api.github.com/events')
# Проверяем оставшееся количество запросов
rate_limit_remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
if rate_limit_remaining < 10:
# Если мы почти достигли лимита, делаем паузу
reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
sleep_time = max(reset_time – time.time(), 0) + 1
print(f"Приближаемся к лимиту запросов. Ожидание {sleep_time} секунд...")
time.sleep(sleep_time)
print(f"Запрос {i+1} выполнен, осталось {rate_limit_remaining} запросов")
# Добавляем небольшую задержку между запросами
time.sleep(0.5)
Продвинутые техники использования Sessions в Requests
Использование сессий (Sessions) в Requests — это не просто удобство, а мощный инструмент для оптимизации и контроля HTTP-запросов. Сессии позволяют сохранять определенные параметры между запросами, что особенно полезно при работе с веб-приложениями и API. 🔄
Начнем с базового использования сессий:
import requests
# Создаем сессию
session = requests.Session()
# Устанавливаем заголовки, которые будут использоваться во всех запросах
session.headers.update({'User-Agent': 'Mozilla/5.0', 'Accept': 'application/json'})
# Выполняем запросы в рамках сессии
response1 = session.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
response2 = session.get('https://httpbin.org/cookies')
# Cookies автоматически сохраняются между запросами
print(response2.json()) # Должен содержать 'sessioncookie': '123456789'
# Закрываем сессию после использования
session.close()
Одним из ключевых преимуществ сессий является улучшение производительности за счет повторного использования соединений:
# Без использования сессий
for i in range(10):
response = requests.get('https://api.github.com/events')
# С использованием сессий – намного эффективнее
session = requests.Session()
for i in range(10):
response = session.get('https://api.github.com/events')
session.close()
Сессии также позволяют настраивать параметры соединения на более тонком уровне через адаптеры:
# Настройка пула соединений и повторных попыток
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# Создаем стратегию повторных попыток
retry_strategy = Retry(
total=3, # максимальное количество повторных попыток
status_forcelist=[429, 500, 502, 503, 504], # коды, при которых повторяем запрос
backoff_factor=1, # фактор экспоненциальной задержки
respect_retry_after_header=True # учитывать заголовок Retry-After
)
# Создаем адаптер с нашей стратегией
adapter = HTTPAdapter(max_retries=retry_strategy, pool_connections=10, pool_maxsize=10)
# Создаем сессию и привязываем адаптер к определенным схемам URL
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)
# Теперь все запросы через эту сессию будут использовать настроенный адаптер
response = session.get('https://api.example.com', timeout=5)
Для работы с веб-приложениями часто требуется эмулировать поведение браузера. Сессии в Requests прекрасно подходят для этой задачи:
# Эмуляция процесса входа в веб-приложение
session = requests.Session()
# Сначала получаем страницу логина, чтобы получить CSRF-токен
login_page = session.get('https://example.com/login')
# Здесь можно использовать библиотеку BeautifulSoup для парсинга HTML
# и извлечения CSRF-токена
import re
csrf_token = re.search('name="csrf_token" value="(.+?)"', login_page.text).group(1)
# Отправляем форму логина
login_data = {
'username': 'myuser',
'password': 'mypassword',
'csrf_token': csrf_token
}
login_response = session.post('https://example.com/login', data=login_data)
# Теперь сессия аутентифицирована, и мы можем получать защищенные страницы
protected_page = session.get('https://example.com/protected')
print('Успешный вход' if 'Welcome, myuser' in protected_page.text else 'Ошибка входа')
Для параллельной обработки множества запросов можно комбинировать сессии с многопоточностью:
import concurrent.futures
import time
# Функция для выполнения запроса
def fetch_url(session, url):
start = time.time()
response = session.get(url)
return {
'url': url,
'status': response.status_code,
'time': time.time() – start
}
# Список URL для запроса
urls = [
'https://www.python.org',
'https://www.github.com',
'https://www.stackoverflow.com',
'https://www.wikipedia.org',
'https://www.reddit.com'
]
# Создаем сессию с нужными настройками
session = requests.Session()
session.headers.update({'User-Agent': 'Mozilla/5.0'})
# Выполняем запросы параллельно
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Создаем набор задач для выполнения
tasks = [executor.submit(fetch_url, session, url) for url in urls]
# Обрабатываем результаты по мере их завершения
for future in concurrent.futures.as_completed(tasks):
result = future.result()
print(f"URL: {result['url']}, Status: {result['status']}, Time: {result['time']:.2f}s")
Иногда требуется сохранить состояние сессии для последующего использования. Для этого можно использовать библиотеку requests-toolbelt:
from requests_toolbelt.sessions import SessionSerializer
# Создаем и настраиваем сессию
session = requests.Session()
session.get('https://httpbin.org/cookies/set/sessionid/12345')
# Сохраняем состояние сессии
serialized = SessionSerializer().dumps(session)
with open('session.pickle', 'wb') as f:
f.write(serialized)
# В другом месте или в другое время можно восстановить сессию
with open('session.pickle', 'rb') as f:
restored_session = SessionSerializer().loads(f.read())
# Продолжаем использовать восстановленную сессию
response = restored_session.get('https://httpbin.org/cookies')
print(response.json()) # Должен содержать сохраненные cookies
Модуль Requests в Python — это не просто библиотека для отправки HTTP-запросов, это мощный инструмент, который существенно упрощает взаимодействие с веб-сервисами и API. Изучив основные методы, параметры, заголовки запросов, а также механизмы аутентификации и продвинутые техники использования сессий, вы получаете в свое распоряжение полный арсенал средств для разработки эффективных и надежных веб-приложений. Помните, что ключом к успеху является не только знание функциональности модуля, но и понимание HTTP-протокола, а также конкретных особенностей API, с которыми вы работаете. Приобретенные навыки позволят вам создавать код, который не просто работает, а делает это элегантно и эффективно.