Python requests: GET и POST запросы, таймаут и ошибки
Библиотека requests отправляет HTTP-запросы одной строкой: requests.get(url, timeout=10) для получения данных и requests.post(url, json=data, timeout=10) для отправки JSON. Всегда указывайте timeout: без него запрос может зависнуть навсегда.
Установка и GET-запрос
pip install requestsimport requests
response = requests.get(
"https://api.example.com/users",
params={"page": 2},
timeout=10,
)
print(response.status_code) # 200
print(response.url) # https://api.example.com/users?page=2
print(response.json()["page"]) # 2Словарь params сам кодирует параметры и добавляет их к адресу. Метод response.json() разбирает тело ответа как JSON.
POST с JSON и с формой
created = requests.post(
"https://api.example.com/users",
json={"name": "Анна", "role": "admin"},
timeout=10,
)
print(created.status_code) # 201
print(created.json()["name"]) # Анна
form = requests.post("https://api.example.com/login", data={"user": "anna"}, timeout=10)
print(form.status_code) # 200Параметр json= преобразует словарь в JSON и ставит заголовок Content-Type: application/json. Параметр data= отправляет обычную форму application/x-www-form-urlencoded.
Заголовки и авторизация
token = "token123"
secured = requests.get(
"https://api.example.com/secure",
headers={"Authorization": f"Bearer {token}", "Accept": "application/json"},
timeout=10,
)
print(secured.status_code) # 200
denied = requests.get("https://api.example.com/secure", timeout=10)
print(denied.status_code) # 401Для базовой авторизации есть параметр auth=("логин", "пароль").
Ошибки и таймаут
Статус 4xx и 5xx сам по себе исключения не вызывает. Его бросает метод raise_for_status():
try:
bad = requests.get("https://api.example.com/fail", timeout=10)
bad.raise_for_status()
except requests.HTTPError as error:
print("ошибка сервера:", error.response.status_code)
try:
requests.get("https://api.example.com/slow", timeout=1)
except requests.Timeout:
print("таймаут")Исключение | Когда возникает |
|---|---|
| Сервер не ответил за указанное время |
| Нет соединения, неверный адрес, отказ сервера |
|
|
| Базовое исключение, перехватывает все перечисленные |
В timeout можно передать пару: timeout=(3, 10) задаёт отдельно время на соединение и на чтение ответа.
Session и автоматические повторы
Сессия переиспользует соединение и заголовки. С адаптером Retry запрос повторяется при временных сбоях:
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
session.headers.update({"User-Agent": "my-app/1.0"})
retry = Retry(total=3, backoff_factor=0.1, status_forcelist=[502, 503, 504])
session.mount("https://", HTTPAdapter(max_retries=retry))
session.mount("http://", HTTPAdapter(max_retries=retry))
flaky = session.get("https://api.example.com/flaky", timeout=10)
print(flaky.status_code) # 200Скачать большой файл
with requests.get("https://api.example.com/file", stream=True, timeout=10) as r:
r.raise_for_status()
with open("download.bin", "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)Частые вопросы
Почему нельзя отключать проверку сертификата через verify=False?
Запрос перестаёт защищаться от подмены сервера. Если сертификат внутренний, укажите путь к нему: verify="/path/ca.pem".
Как отправить файл?
Передайте открытый файл в files: requests.post(url, files={"file": open("a.txt", "rb")}, timeout=30).
Чем requests отличается от httpx?
httpx умеет асинхронные запросы и HTTP/2, интерфейс похож. Для простых скриптов requests по-прежнему достаточно.