Сессии, файлы и курс за период
Последняя тема курса собирает всё вместе: запоминать вход на сайт, скачивать файлы и обходить архив по датам.
Session
requests.Session() — как вкладка браузера: она помнит cookie, общие заголовки и держит соединение открытым между запросами.
with requests.Session() as s:
s.headers["User-Agent"] = "my-bot/1.0" # уйдёт с каждым запросом
s.post("https://site.ru/login", json={"user": "anna", "password": "..."}, timeout=5)
me = s.get("https://site.ru/me", timeout=5) # cookie после входа отправится сама
print(me.json())
Без сессии каждый requests.get начинает с чистого листа: сайт выдал cookie на вход — и забыл о вас на следующем запросе. Сессия ещё и быстрее: соединение с сервером не открывается заново на каждый запрос, а для сотен запросов к одному API это заметно.
Cookie сессии видно в s.cookies, а cookie из одного ответа — в r.cookies.
Скачивание файлов
Текст — это r.text, а картинки, архивы, PDF — байты: r.content. Никогда не читайте бинарный файл через r.text — requests попытается угадать кодировку, и байты испортятся.
Большой файл лучше качать по кусочкам:
with requests.get(url, stream=True, timeout=(5, 60)) as r:
r.raise_for_status()
with open("python.png", "wb") as f:
for chunk in r.iter_content(chunk_size=65536):
f.write(chunk)
stream=True— тело не скачивается сразу, его читают по мере надобности;iter_contentотдаёт куски и сам распаковывает сжатиеgzip, если сервер сжимал ответ;r.raw.read()читает «сырые» байты из сокета — без распаковки, поэтому он нужен редко.
Проверить, что файл дошёл целым, помогает контрольная сумма: её считают кусками, не держа файл в памяти.
import hashlib
h = hashlib.sha256()
for chunk in r.iter_content(chunk_size=65536):
h.update(chunk)
print(h.hexdigest())
Архив курсов ЦБ
У cbr-xml-daily.ru есть архив: https://www.cbr-xml-daily.ru/archive/2026/01/09/daily_json.js — курсы, установленные на 9 января. На дни, когда курс не устанавливался (выходные, праздники), архив отвечает 404.
По правилам ЦБ в такие дни действует последний установленный курс. Поэтому таблица курсов по дням строится так:
- идём по дням периода (
date+timedelta(days=1)); - есть курс — запоминаем его как последний;
- нет — пишем последний известный;
- если период начинается с выходных, последний курс ищем до начала периода — с ближайшего дня назад.
Даты в адрес удобно подставлять форматом: f"{day:%Y/%m/%d}" → 2026/01/09.
Что дальше
Вы умеете всё, что нужно для большинства задач «программа ходит в интернет»: читать API, отправлять данные, переживать ошибки и работать с сессиями. Дальше — те же приёмы в ботах (aiogram), парсерах (BeautifulSoup) и собственных API (FastAPI).
Итог
Session— cookie, общие заголовки и быстрые повторные соединения;- файлы — байтами:
stream=True+iter_content, неtext; iter_contentраспаковывает gzip,raw.read()— нет;- в выходные действует последний установленный курс.