Перейти к содержанию
Educora
Продвинутый18 мин26 / 42

Веб-API и библиотека requests

Как работает HTTP: методы, коды состояния, заголовки и JSON. GET- и POST-запросы через `requests`, `params`, `headers`, `timeout`, `raise_for_status`, обработка ошибок и безопасное хранение API-ключей.

Проверь себя
В этом уроке ты узнаешь
  • Объяснять части HTTP-запроса и ответа, основные методы и коды состояния
  • Отправлять GET-запросы с параметрами и POST-запросы с JSON-телом через requests
  • Писать надёжный код с тайм-аутами, raise_for_status и исключениями и хранить API-ключи в секрете

Прогноз погоды в телефоне, курсы валют банка, маршрут на карте — все эти данные программы получают с серверов через API (Application Programming Interface). Приложения Educora тоже загружают уроки через API сайта. Веб-API — это простая договорённость: ты отправляешь HTTP-запрос по определённому адресу, а сервер обычно возвращает ответ в JSON. Самый популярный инструмент для этого в Python — библиотека requests.

Коротко об HTTP

Запрос состоит из четырёх частей: метод (что сделать), URL (куда), заголовки (дополнительные сведения: формат, ключ) и тело (отправляемые данные, например JSON). Ответ состоит из кода состояния, заголовков и тела. Часть URL после знака ? — это параметры запроса (query string): ?city=Baku&units=metric.

Text
GET /v1/weather?city=Baku&units=metric HTTP/1.1
Host: api.example.com
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json

{"city": "Baku", "temp": 24.5, "wind": 7.2, "description": "sunny"}
Так запрос и ответ выглядят «изнутри». api.example.com — адрес, зарезервированный для примеров в документации; все ответы в уроке иллюстративные.
МетодСмыслПример
GETполучить данныеGET /v1/tasks
POSTсоздать новый объектPOST /v1/tasks
PUT / PATCHзаменить / частично обновить объектPATCH /v1/tasks/42
DELETEудалить объектDELETE /v1/tasks/42
КодСмысл
200, 201, 204успех: OK, создано, нет содержимого
301, 302перенаправление — смотри другой адрес
400, 401, 403, 404ошибка клиента: неверный запрос, нет входа, нет доступа, не найдено
429слишком много запросов — лимит превышен, подожди
500, 503ошибка сервера, сервис недоступен

Запросы с requests

Установи библиотеку на компьютер: pip install requests. Python в браузере не может отправлять сетевые запросы, поэтому код этого урока здесь не запускается — попробуй его на своём компьютере. requests.get возвращает объект ответа: status_code, headers, text, json(). Не склеивай параметры с URL вручную: словарь params правильно их кодирует, например «Sumqayıt» превращается в Sumqay%C4%B1t.

Python
import requests

url = 'https://api.example.com/v1/weather'
params = {'city': 'Baku', 'units': 'metric'}
headers = {'Accept': 'application/json'}

response = requests.get(url, params=params, headers=headers, timeout=10)
print(response.status_code)
print(response.url)
print(response.headers['Content-Type'])
data = response.json()
print(data['city'], data['temp'])
Ожидаемый результат
200
https://api.example.com/v1/weather?city=Baku&units=metric
application/json
Baku 24.5
response.json() превращает JSON-тело в словарь Python. Вывод — пример: настоящий API вернёт другую температуру.

Чтобы создать новый объект, отправляем POST. Аргумент json= превращает словарь в JSON и сам добавляет заголовок Content-Type: application/json. При успешном создании сервер обычно возвращает код 201 и новый объект (с идентификатором).

Python
import requests

new_task = {'title': 'Finish the pandas lesson', 'done': False}
r = requests.post('https://api.example.com/v1/tasks', json=new_task, timeout=10)
print(r.status_code)
print(r.json())
print(r.request.headers['Content-Type'])
Ожидаемый результат
201
{'id': 42, 'title': 'Finish the pandas lesson', 'done': False}
application/json

Ошибки, тайм-ауты и raise_for_status

Внимание: ответ 404 или 500 для requests — не ошибка, код спокойно продолжает работу. raise_for_status() выбрасывает HTTPError при кодах 4xx и 5xx. Сетевые проблемы — отдельные исключения: Timeout, ConnectionError; все они наследуются от requests.exceptions.RequestException.

Python
import requests

def get_json(url, **params):
    try:
        r = requests.get(url, params=params, timeout=5)
        r.raise_for_status()
        return r.json()
    except requests.exceptions.Timeout:
        print('The server did not answer in time')
    except requests.exceptions.HTTPError as e:
        print('HTTP error:', e.response.status_code)
    except requests.exceptions.RequestException as e:
        print('Network problem:', type(e).__name__)
    return None

print(get_json('https://api.example.com/v1/weather', city='Atlantis'))
Ожидаемый результат
HTTP error: 404
None
Частные исключения пишутся раньше общего (RequestException), иначе до них никогда не дойдёт очередь.

Безопасность API-ключей

Большинство API узнают тебя по ключу (API key, токен). Ключ — как пароль: зная его, кто угодно может отправлять запросы от твоего имени, расходовать твой лимит и даже тратить деньги. Правила:

  • Никогда не пиши ключ в коде и не коммить его в Git — храни его в переменной окружения.
  • Если используешь файл .env, добавь его в .gitignore.
  • Если API позволяет, передавай ключ в заголовке, а не в URL: адреса оседают в журналах и истории браузера.
  • Не помещай секретный ключ в код браузерного или мобильного приложения — любой пользователь может его извлечь; отправляй такие запросы через свой сервер.
  • Если ключ утёк, немедленно отзови его и создай новый.
Terminal
# Linux / macOS
export WEATHER_API_KEY='paste-your-key-here'

# Windows PowerShell
$env:WEATHER_API_KEY = 'paste-your-key-here'
Переменная живёт только в текущем сеансе терминала; чтобы сохранить её надолго, используй настройки операционной системы или файл .env.
Python
import os
import requests

api_key = os.environ.get('WEATHER_API_KEY')
if not api_key:
    raise SystemExit('Set the WEATHER_API_KEY environment variable first')

session = requests.Session()
session.headers.update({'Authorization': f'Bearer {api_key}'})
r = session.get('https://api.example.com/v1/weather', params={'city': 'Baku'}, timeout=10)
r.raise_for_status()
print(r.json()['description'])
Ожидаемый результат
sunny
Ключ остаётся вне кода, а Session сама добавляет его в заголовок каждого запроса. Точное имя заголовка (Authorization, X-API-Key и т. п.) указано в документации API.

Главное

  • HTTP-запрос: метод, URL, заголовки, тело; ответ: код состояния, заголовки, тело (часто JSON).
  • GET читает, POST создаёт, PUT/PATCH обновляют, DELETE удаляет; 2xx — успех, 4xx — ошибка клиента, 5xx — ошибка сервера.
  • requests.get(url, params=..., headers=..., timeout=...) и requests.post(url, json=...); результат — через r.json().
  • Всегда передавай timeout и вызывай raise_for_status(); перехватывай исключения от частных к общему.
  • API-ключ хранится в переменной окружения, передаётся в заголовке и никогда не попадает в Git; утёкший ключ отзывают.

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Сервер вернул 404. Что сделает requests.get(...)?