</>
Topic 6 of 6

Course materials are currently available in Russian only.

Сессии, файлы и курс за период

Последняя тема курса собирает всё вместе: запоминать вход на сайт, скачивать файлы и обходить архив по датам.

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.

По правилам ЦБ в такие дни действует последний установленный курс. Поэтому таблица курсов по дням строится так:

  1. идём по дням периода (date + timedelta(days=1));
  2. есть курс — запоминаем его как последний;
  3. нет — пишем последний известный;
  4. если период начинается с выходных, последний курс ищем до начала периода — с ближайшего дня назад.

Даты в адрес удобно подставлять форматом: 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() — нет;
  • в выходные действует последний установленный курс.