Async Python client for Мирэа LKS (schedule, grades, attendance, ACS, SSO)
Project description
pymirea
Асинхронный Python-клиент для Пульса МИРЭА.
Поддерживает: вход с 2FA через Keycloak SSO, расписание занятий, оценки, посещаемость (отметка + детали), события турникетов (ACS), регистрацию в e-sports, шифрование сессий (Fernet + HKDF).
Установка
pip install pymirea
Первый запрос за 30 секунд
import asyncio
from pymirea import Config, configure, MireaAuth
# Сгенерируйте свой ключ один раз и сохраните:
# python -c "import secrets,base64; print(base64.b64encode(secrets.token_bytes(32)).decode())"
configure(Config(session_keys="ВАША_BASE64_СТРОКА_32_БАЙТА"))
async def main():
auth = MireaAuth()
result = await auth.login("ваш_логин@edu.mirea.ru", "пароль")
if result.challenge:
# МИРЭА просит OTP (приходит на университетскую почту)
code = input("Код из email: ")
result = await auth.complete_2fa(result.challenge, code)
print("Вошли! Токены:", result.tokens)
asyncio.run(main())
Примеры использования
1. Простой скрипт — получить расписание
import asyncio
from datetime import datetime
from pymirea import Config, configure, MireaAuth
from pymirea.grades import MireaGrades
configure(Config(session_keys="..."))
async def main():
auth = MireaAuth()
result = await auth.login("login@edu.mirea.ru", "пароль")
# ... обработка 2FA если потребуется ...
api = MireaGrades(session_cookies=result.tokens)
schedule = await api.get_schedule(days=7)
for lesson in schedule.lessons:
when = datetime.fromtimestamp(lesson.start_epoch).strftime("%d.%m %H:%M")
print(f"{when} {lesson.name} — {lesson.teacher or '?'} ({lesson.room or '?'})")
asyncio.run(main())
Полная версия: examples/cli_schedule.py.
2. Telegram-бот на aiogram
from datetime import datetime
from aiogram import Bot, Dispatcher, types
from pymirea import Config, configure, MireaAuth
from pymirea.grades import MireaGrades
configure(Config(session_keys="..."))
bot = Bot(token="...")
dp = Dispatcher()
# user_id -> session cookies (в продакшене — в БД, зашифрованно через SessionCrypto)
sessions: dict[int, dict] = {}
@dp.message(commands=["schedule"])
async def cmd_schedule(msg: types.Message):
cookies = sessions.get(msg.from_user.id)
if not cookies:
await msg.answer("Сначала /login")
return
api = MireaGrades(session_cookies=cookies)
sched = await api.get_schedule(days=3)
lines = [
f"{datetime.fromtimestamp(l.start_epoch).strftime('%d.%m %H:%M')} — {l.name}"
for l in sched.lessons
]
await msg.answer("\n".join(lines) or "Пар не найдено")
Полная версия: examples/telegram_bot.py.
3. Отметить посещаемость себе и друзьям одним QR-сканом
Классический MireaScanner-флоу — сделайте своё приложение за 20 минут:
from pymirea import MireaAPI, SessionCrypto
from pymirea.crypto import get_crypto
crypto = get_crypto()
# Загрузите из своей БД зашифрованные сессии друзей
friends = [
(123, "Эллиот", crypto.decrypt_session(row_elliot)),
(456, "Уолтер", crypto.decrypt_session(row_walter)),
]
api = MireaAPI(session_cookies=my_session)
results = await api.mark_attendance_for_group(qr_data, friends)
for r in results:
print(f"{r.user_name}: {'✓' if r.success else '✗ ' + r.message}")
mark_attendance_for_group сам извлекает токен из QR-URL, проходит по всем переданным сессиям и возвращает список AttendanceResult — готово к отображению в UI.
4. FastAPI-веб-сервис
from fastapi import FastAPI, Depends, HTTPException
from pymirea import Config, configure
from pymirea.grades import MireaGrades
from pymirea.crypto import get_crypto
configure(Config(session_keys="..."))
crypto = get_crypto()
app = FastAPI()
def current_session(token: str = Depends(...)) -> dict:
"""Расшифровать сессию пользователя из вашего хранилища."""
encrypted = your_db.get_mirea_session(user_id_from(token))
if not encrypted:
raise HTTPException(401)
return crypto.decrypt_session(encrypted)
@app.get("/api/schedule")
async def get_schedule(session: dict = Depends(current_session)):
api = MireaGrades(session_cookies=session)
result = await api.get_schedule(days=7)
return {
"success": result.success,
"lessons": [
{"start": l.start_epoch, "end": l.end_epoch, "name": l.name,
"teacher": l.teacher, "room": l.room}
for l in (result.lessons or [])
],
}
Полная версия: examples/fastapi_app.py.
Примеров для QR-сканирования в папке
examples/пока нет — PR приветствуется.
Шифрование сессий
Хранить cookies МИРЭА в БД в открытом виде нельзя — SessionCrypto оборачивает их в Fernet-токен с ключом, выведенным через HKDF из вашего session_keys:
from pymirea.crypto import get_crypto
crypto = get_crypto()
encrypted: str = crypto.encrypt_session(cookies_dict) # сохраните в БД
decrypted: dict = crypto.decrypt_session(encrypted) # прочтите из БД
При смене session_keys старые токены становятся нечитаемыми — храните старый ключ в legacy_bot_token для grace-period миграции.
Public API
| Имя | Назначение |
|---|---|
Config / configure(Config) |
Конфигурация runtime (DI-style, вызывается один раз на старте) |
MireaAuth |
login(), complete_2fa() (алиас submit_otp()), refresh_tokens(), verify_session() |
MireaAPI (pymirea.session) |
mark_attendance(), mark_attendance_for_group(), extract_token_from_qr(), get_attendance_score() |
MireaGrades (pymirea.grades) |
get_schedule(), get_grades(), get_attendance_detail(), self_approve_attendance() |
MireaACS |
get_today_events() — события турникетов |
MireaEsports |
login(), get_slots(), create_booking(), get_my_bookings(), cancel_booking() |
SessionCrypto |
Шифрование/расшифровка cookies (Fernet + HKDF) |
AuthChallenge / AuthResult |
Результаты login-флоу |
get_authorization_header(cookies) |
Bearer-токен из dict сессии |
try_refresh_tokens(cookies) |
Best-effort обновление access-токена |
get_token_age_seconds(cookies) |
Сколько секунд токен живёт |
Подробнее в исходниках: pymirea/.
Конфигурация
from pymirea import Config
Config(
session_keys="base64-32-bytes", # обязательно
mirea_proxy="http://proxy:8080", # опционально, для pulse.mirea.ru (датацентры заблокированы)
legacy_bot_token=None, # старый ключ для миграции при ротации
request_timeout_s=15.0,
breaker_failure_threshold=5,
breaker_recovery_s=30.0,
)
Совместимость
- Python 3.11+
- Только async (нет sync-обёртки; для скриптов используйте
asyncio.run) - Любой web-фреймворк: FastAPI, aiohttp, Sanic, Litestar, Quart — pymirea не привязан ни к одному
- Любая БД для хранения сессий — pymirea даёт только примитивы шифрования
Что pymirea НЕ делает
- ❌ Не хранит сессии — это задача вашего приложения (БД/Redis/файл)
- ❌ Не управляет пользователями — у вас своя auth-система
- ❌ Не предоставляет HTTP-handlers — пишите свои под свой фреймворк
- ❌ Не парсит сложные нестандартные формы МИРЭА (профили, дипломы — TBD)
Если хочется готовый микросервис — соберите Telegram-бот / FastAPI-сервис на основе примеров.
Внести вклад
Issues и PR приветствуются. Особенно полезно:
- Тесты для новых сценариев (logout, edge-cases в 2FA, etc.)
- Поддержка дополнительных эндпоинтов МИРЭА
- Примеры для других фреймворков (Discord-боты, CLI-tools, ...)
Лицензия
MIT — см. LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pymirea-0.2.3.tar.gz.
File metadata
- Download URL: pymirea-0.2.3.tar.gz
- Upload date:
- Size: 67.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
074e8e15d701507f875ed9f616057a8aef65c368f33cdafd544ac14220f6091f
|
|
| MD5 |
a42de653cf1d3c7f66fe61c6c39b7f43
|
|
| BLAKE2b-256 |
315ea7498ff2db8d65f34e7b40d804cbdc92835c0bcfbe84c617f32df5eda661
|
Provenance
The following attestation bundles were made for pymirea-0.2.3.tar.gz:
Publisher:
release.yml on silverhans/pymirea
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pymirea-0.2.3.tar.gz -
Subject digest:
074e8e15d701507f875ed9f616057a8aef65c368f33cdafd544ac14220f6091f - Sigstore transparency entry: 1401040409
- Sigstore integration time:
-
Permalink:
silverhans/pymirea@643b8280da2cbebe518e2933682ac044062624d7 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/silverhans
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@643b8280da2cbebe518e2933682ac044062624d7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pymirea-0.2.3-py3-none-any.whl.
File metadata
- Download URL: pymirea-0.2.3-py3-none-any.whl
- Upload date:
- Size: 56.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f928312cd692d91b8ca02d617e5bfb2710179f5ba2358be3958c1e9974caeb6
|
|
| MD5 |
5e906d336e1110b88a1a6c802fd1d4d5
|
|
| BLAKE2b-256 |
b5ec767b111a294bb196190a72bba9f069a02b2b1e8a4333456aa3b98a809c87
|
Provenance
The following attestation bundles were made for pymirea-0.2.3-py3-none-any.whl:
Publisher:
release.yml on silverhans/pymirea
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pymirea-0.2.3-py3-none-any.whl -
Subject digest:
7f928312cd692d91b8ca02d617e5bfb2710179f5ba2358be3958c1e9974caeb6 - Sigstore transparency entry: 1401040553
- Sigstore integration time:
-
Permalink:
silverhans/pymirea@643b8280da2cbebe518e2933682ac044062624d7 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/silverhans
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@643b8280da2cbebe518e2933682ac044062624d7 -
Trigger Event:
push
-
Statement type: