Основы работы с requests: от простого к сложному

Раздел: Сетевое программирование -> HTTP-запросы

Библиотека requests: основы HTTP-запросов на Python

Библиотека requests является стандартным инструментом для выполнения HTTP-запросов в Python. Она предоставляет простой интерфейс, позволяющий отправлять GET и POST запросы, управлять заголовками, куками, параметрами и обрабатывать ответы. Рассмотрим наиболее эффективные подходы и альтернативные варианты.

Наиболее эффективное решение - использование встроенных методов requests с автоматическим управлением соединениями и обработкой ответов. Установка библиотеки выполняется командой:

pip install requests

запрос страницы python (запрос веб-страницы в python)

После установки можно отправлять базовый GET-запрос:

import requests
response = requests.get('https://api.example.com/data')
print(response.status_code)  # 200
print(response.text)         # содержимое ответа

Python requests (библиотека requests в python)

200
{"key": "value"}

Ответ (объект Response) содержит статус, заголовки, тело. Для JSON данных удобно использовать response.json().

Типичная ошибка: забыть обработать статус ответа (например, 404). Рекомендуется вызывать raise_for_status() для автоматического выброса исключения при ошибках HTTP.

Как отправить GET-запрос с параметрами?

Параметры URL передаются через словарь params:

params = {'key1': 'value1', 'key2': 'value2'}
response = requests.get('https://api.example.com/search', params=params)
print(response.url)  # https://api.example.com/search?key1=value1&key2=value2
https://api.example.com/search?key1=value1&key2=value2

Этот метод автоматически кодирует параметры, избавляя от ручной работы.

Проблема: если параметр имеет значение None, он будет пропущен. Для пустых значений используется пустая строка.

Как отправить POST-запрос с данными?

Для отправки формы используется аргумент data:

data = {'username': 'user', 'password': 'pass'}
response = requests.post('https://httpbin.org/post', data=data)
print(response.json())
{
  "form": {
    "password": "pass",
    "username": "user"
  }
}

Для отправки JSON-данных используйте json:

import json
data = {'key': 'value'}
response = requests.post('https://httpbin.org/post', json=data)
print(response.json()['json'])
{'key': 'value'}

json автоматически устанавливает заголовок Content-Type: application/json.

Ошибка: передача одновременно data и json может привести к игнорированию одного из них. Следует использовать только один вариант.

Как добавить заголовки и куки?

Заголовки передаются через словарь headers:

headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'session_id': 'abc123'}
response = requests.get('https://httpbin.org/cookies', headers=headers, cookies=cookies)
print(response.json())
{
  "cookies": {
    "session_id": "abc123"
  }
}

Проблема: если передать куки через cookies и одновременно через заголовок Cookie, requests использует аргумент cookies. Не стоит дублировать.

Как использовать сессии для сохранения состояния?

Объект Session сохраняет куки и заголовки между запросами:

session = requests.Session()
session.headers.update({'User-Agent': 'my-app'})
session.get('https://httpbin.org/cookies/set?name=value')
response = session.get('https://httpbin.org/cookies')
print(response.json()['cookies'])
{"name": "value"}

Сессии также улучшают производительность за счет повторного использования TCP-соединений.

Ошибка: использование разных сессий для каждого запроса может привести к потере кук. Рекомендуется создавать одну сессию для группы взаимосвязанных запросов.

Как обрабатывать ошибки и таймауты?

Для обработки ошибок HTTP используется raise_for_status():

try:
    response = requests.get('https://httpbin.org/status/404')
    response.raise_for_status()
except requests.exceptions.HTTPError as err:
    print(f"HTTP ошибка: {err}")
HTTP ошибка: 404 Client Error: NOT FOUND for url: https://httpbin.org/status/404

Таймаут задается аргументом timeout:

try:
    response = requests.get('https://httpbin.org/delay/5', timeout=3)
except requests.exceptions.Timeout:
    print("Запрос превысил время ожидания")
Запрос превысил время ожидания

Типичная ошибка: не устанавливать timeout, что может привести к зависанию программы. Всегда указывайте разумное значение (например, 10 секунд).

Как работать с прокси и SSL?

Прокси передаются словарем с ключами 'http' и 'https':

proxies = {
    'http': 'http://proxy.example.com:8080',
    'https': 'https://proxy.example.com:8080'
}
response = requests.get('https://httpbin.org/ip', proxies=proxies)

Для отключения проверки SSL (не рекомендуется для продакшена) используйте verify=False:

response = requests.get('https://self-signed.badssl.com', verify=False)

Проблема: отключение SSL делает соединение уязвимым. Для самоподписанных сертификатов лучше указать путь к CA-файлу через verify='/path/to/cert.pem'.

Как загружать и скачивать файлы?

Для скачивания файла используйте потоковую передачу с stream=True:

response = requests.get('https://httpbin.org/image/png', stream=True)
with open('image.png', 'wb') as f:
    for chunk in response.iter_content(chunk_size=8192):
        f.write(chunk)

Для отправки файла используйте аргумент files:

files = {'file': open('report.pdf', 'rb')}
response = requests.post('https://httpbin.org/post', files=files)

При больших файлах рекомендуется открывать их в бинарном режиме.

Ошибка: забыть закрыть файл. Лучше использовать менеджер контекста with open().

Как использовать авторизацию (Basic, Bearer)?

Для Basic-авторизации передается кортеж (логин, пароль):

response = requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))
print(response.status_code)
200

Для Bearer-токена используется заголовок Authorization:

headers = {'Authorization': 'Bearer token123'}
response = requests.get('https://api.example.com/protected', headers=headers)

Существует также класс HTTPDigestAuth для Digest-аутентификации.

Проблема: передача пароля в открытом виде при использовании HTTP (не HTTPS). Всегда используйте шифрование.

Расширенные примеры использования requests

Данный раздел содержит более сложные и редко встречающиеся сценарии работы с библиотекой requests.

1. Управление перенаправлениями (redirects)

По умолчанию requests автоматически следует редиректам. Для запрета используется параметр allow_redirects=False:

Пример
response = requests.get('https://httpbin.org/redirect/3', allow_redirects=False)
print(response.status_code)  # 302
302

Можно отслеживать историю редиректов через response.history:

Пример
response = requests.get('https://httpbin.org/redirect/2')
for hist in response.history:
    print(hist.status_code, hist.url)
302 https://httpbin.org/redirect/2
302 https://httpbin.org/relative-redirect/1

2. Использование адаптеров для настройки пула соединений

Адаптеры позволяют управлять количеством соединений. Например, для HTTP можно настроить пул:

Пример
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[502, 503])
adapter = HTTPAdapter(max_retries=retries, pool_connections=100, pool_maxsize=100)
session.mount('http://', adapter)
session.mount('https://', adapter)
response = session.get('https://httpbin.org/status/502')
print(response.status_code)
200  # после повторных попыток (в примере httpbin вернет 200 при третьей попытке)

3. Загрузка больших файлов с прогресс-баром

Можно отображать прогресс с помощью tqdm:

Пример
import requests
from tqdm import tqdm

url = 'https://speed.hetzner.de/100MB.bin'
response = requests.get(url, stream=True)
total = int(response.headers.get('content-length', 0))
with open('100MB.bin', 'wb') as f, tqdm(desc='Download', total=total, unit='B', unit_scale=True) as pbar:
    for chunk in response.iter_content(chunk_size=8192):
        f.write(chunk)
        pbar.update(len(chunk))
Download: 100%|██████████| 100M/100M [00:10<00:00, 9.8MB/s]

4. Отправка Multipart-форм с файлами и данными

Для отправки формы, включающей файл и текстовые поля, используется словарь с кортежами:

Пример
files = {
    'file': ('report.pdf', open('report.pdf', 'rb'), 'application/pdf'),
    'note': (None, 'some text')
}
response = requests.post('https://httpbin.org/post', files=files)
print(response.json()['files']['file'])
data:application/pdf;base64,JVBERi0xL... (содержимое файла в base64)

5. Использование custom User-Agent и Referer для имитации браузера

Некоторые API требуют специфических заголовков:

Пример
session = requests.Session()
session.headers.update({
    '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',
    'Accept': 'text/html,application/xhtml+xml',
    'Accept-Language': 'ru-RU,ru;q=0.9',
    'Referer': 'https://www.google.com/'
})
response = session.get('https://httpbin.org/headers')
print(response.json()['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

6. Аутентификация через OAuth2 с использованием requests-oauthlib

Для работы с OAuth2 требуется дополнительная библиотека:

Пример
from requests_oauthlib import OAuth2Session
import os

oauth = OAuth2Session(os.environ['CLIENT_ID'], redirect_uri='https://localhost/callback')
authorization_url, state = oauth.authorization_url('https://provider.com/oauth/authorize')
print('Перейдите по URL:', authorization_url)
# После редиректа извлекаем код
redirect_response = input('Вставьте полный URL редиректа: ')
token = oauth.fetch_token('https://provider.com/oauth/token', authorization_response=redirect_response, client_secret=os.environ['CLIENT_SECRET'])
response = oauth.get('https://api.provider.com/user')
print(response.json())
{'id': 123, 'name': 'John Doe'}

7. Проверка SSL сертификата и настройка CA bundle

Для использования собственного сертификата:

Пример
response = requests.get('https://example.com', verify='/path/to/custom_ca.pem')

Если не требуется проверка сертификата (только для тестов):

Пример
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get('https://self-signed.badssl.com', verify=False)

8. Использование параметра hooks для изменения поведения запроса

Хуки позволяют выполнять действия до или после запроса:

Пример
def print_url(r, *args, **kwargs):
    print(f"Запрос к {r.url}")

response = requests.get('https://httpbin.org/get', hooks={'response': print_url})
Запрос к https://httpbin.org/get

9. Работа с временем выполнения (elapsed)

response.elapsed возвращает время, затраченное на запрос:

Пример
response = requests.get('https://httpbin.org/delay/1')
print(f"Время: {response.elapsed.total_seconds()} с")
Время: 1.002 с

10. Отправка запросов с HTTP-методами PUT, DELETE, PATCH

Аналогично GET и POST:

Пример
response_put = requests.put('https://httpbin.org/put', data={'key': 'value'})
response_del = requests.delete('https://httpbin.org/delete')
response_patch = requests.patch('https://httpbin.org/patch', data={'field': 'new'})

Библиотека requests в Python - comments

En
Python requests (python)