Параметры и заголовки
Почти каждый запрос к 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 отдают страницами. Два частых способа:
- Номер страницы в параметре:
?page=1,?page=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.