</>
Topic 3 of 6

Course materials are currently available in Russian only.

Параметры и заголовки

Почти каждый запрос к API — это адрес, параметры и заголовки. Разберёмся, как передавать их правильно.

Параметры адреса: params

r = requests.get(
    "https://api.github.com/search/repositories",
    params={"q": "tkinter game", "sort": "stars", "per_page": 5},
    timeout=5,
)
print(r.url)
# https://api.github.com/search/repositories?q=tkinter+game&sort=stars&per_page=5

Не склеивайте адрес вручную. В адресе у символов особый смысл: & разделяет параметры, # начинает якорь, + означает пробел, ? начинает параметры. Строка f"...?q={query}" сломается на первом запросе rock & roll или C++. params кодирует всё сам: C++ → C%2B%2B.

Значение-список превращается в повторяющийся параметр: params={"tag": ["a", "b"]} → ?tag=a&tag=b.

Заголовки: headers

Заголовки — служебные строки запроса: кто спрашивает, в каком формате ждёт ответ, есть ли доступ.

headers = {
    "Authorization": "Bearer ghp_xxx",          # токен доступа
    "Accept": "application/vnd.github+json",    # какой формат ответа нужен
    "User-Agent": "my-weather-bot/1.0",         # кто спрашивает
}
r = requests.get("https://api.github.com/user", headers=headers, timeout=5)
  • Authorization — чаще всего Bearer <токен>; слово и пробел обязательны, сервер сравнивает строку целиком;
  • Accept — формат ответа; некоторые API без него отвечают ошибкой 406;
  • User-Agent — имя программы; многие сайты отказывают запросам без него или с подозрительным значением.

Заголовки ответа читают через r.headers["Content-Type"] — регистр букв в имени не важен.

Токены не пишут прямо в коде, который выкладывают на GitHub: их читают из переменной окружения, os.environ["GITHUB_TOKEN"].

Ссылки и urljoin

API часто возвращают ссылки на другие ресурсы: «следующая страница», «автор», «картинка». Ссылка бывает полной, от корня сайта или относительной. Собрать из неё адрес помогает urljoin — он работает как браузер:

from urllib.parse import urljoin

page = "https://api.site.ru/v1/items?cursor=c1"
urljoin(page, "https://cdn.site.ru/a.png")   # https://cdn.site.ru/a.png
urljoin(page, "/v1/items?cursor=c2")          # https://api.site.ru/v1/items?cursor=c2
urljoin(page, "items?cursor=c2")              # https://api.site.ru/v1/items?cursor=c2

Постраничная выдача

Большие списки API отдают страницами. Два частых способа:

  1. Номер страницы в параметре: ?page=1, ?page=2… — пока не придёт пустая страница.
  2. Ссылка на следующую в ответе (next) или в заголовке Link — пока она не станет null.
url = "https://pokeapi.co/api/v2/pokemon?limit=100"
while url:
    data = requests.get(url, timeout=10).json()
    for p in data["results"]:
        print(p["name"])
    url = data["next"]

Если в ответе есть next, доверяйте ему, а не «пустой странице»: страница может оказаться пустой посередине списка, например когда записи удалили.

Итог

  • параметры — только через params=, вручную адрес не склеиваем;
  • заголовки — через headers=: Authorization: Bearer …, Accept, User-Agent;
  • ссылки из ответа — через urljoin(текущий_адрес, ссылка);
  • страницы — идём по next, пока он не None.