Historial academico desde Banner + SQLite + dashboard local
Herramienta personal para extraer tus notas desde Banner, consolidarlas en SQLite y visualizarlas en una web local con metricas, promedios y alertas por semestre.
UA Grades automatiza el acceso a Banner y construye un historial academico local a partir de tus datos en Banner.
Con ese historial puedes:
- guardar un respaldo en JSON
- persistir la informacion en SQLite
- levantar un dashboard web local
- ver promedios por semestre
- detectar cursos fuertes, cursos mas debiles y periodos sin nota
- Extraccion HTTP-first con
httpx - Login con Microsoft +
TOTP - Renovacion de sesion con
Playwrightsolo cuando hace falta - Historial consolidado de todos los semestres disponibles
- Persistencia local en
SQLite - Exportacion a
JSON - Dashboard local con metricas y graficos
- Modulo de asistencia con margen de ausencias por ramo
- Soporte para ejecucion local o con
Docker
python main.py: levanta la web local leyendo desde SQLite.- Desde el dashboard puedes usar
Actualizar notasyActualizar asistenciapara traer datos desde Banner. - Si la sesion expiro, el flujo web abre
Playwright, renueva login Microsoft + TOTP, actualiza la sesion y continua por HTTP. - Guarda el resultado en
JSONySQLite.
python main.pyEl dashboard queda disponible en http://127.0.0.1:8000.
python main.py inicia el dashboard local que lee tu historial desde SQLite, muestra el resumen academico, permite actualizar notas desde Banner con Actualizar notas, permite cargar asistencia con Actualizar asistencia y ofrece dos entradas al flujo de comparacion: Ir a dashboard de comparacion y Subir mis datos / Sync.
Los comandos manuales python main.py fetch, python main.py fetch --full y python main.py serve siguen disponibles, pero el flujo normal esta en la web.
fetch actualiza solo el semestre actual cuando ya existe un historial guardado. Usa python main.py fetch --full si quieres recargar todos los semestres manualmente.
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python main.pycp .env.example .env
docker compose build
docker compose upEl dashboard queda disponible en http://localhost:8000.
Para actualizar desde Docker conviene usar UA_HEADLESS=true. Esa opcion solo afecta el browser de renovacion. Si Microsoft cambia la pantalla de 2FA y necesitas intervenir manualmente, ejecuta el dashboard fuera del contenedor con python main.py.
Copia .env.example a .env y completa tus credenciales.
UA_USUARIOUA_CONTRASENAUA_TOTP_SECRETUA_MANTENER_SESIONUA_HEADLESSUA_OUTPUT_DIRUA_SQLITE_PATHUA_WEB_HOSTUA_WEB_PORTUA_COMPARISON_BASE_URLUA_COMPARISON_IDENTITY_PATHUA_CAPTURE_BANNER_CONTRACT
Para usar comparacion solo necesitas levantar la app local:
python main.pyConfiguracion relevante en .env:
UA_COMPARISON_BASE_URL: URL del tablero remoto a donde apunta el dashboard local.UA_COMPARISON_IDENTITY_PATH: archivo local donde se guardadisplay_name,sync_tokeny fecha del ultimo sync.
El dashboard compartido ahora vive como un servicio hospedado en un repositorio y deployment separados. Este repositorio solo mantiene el cliente local que sincroniza tu snapshot y abre ese tablero externo.
Flujo de primera vinculacion:
- La persona abre
Subir mis datos / Syncdesde el dashboard local. - En el primer envio completa
display_nameyclaim_code. - El servicio remoto valida ese claim, crea o reemplaza el snapshot del participante y devuelve un
sync_token. - La app local guarda ese
sync_tokenenUA_COMPARISON_IDENTITY_PATHjunto al nombre mostrado. - Los siguientes sync reutilizan ese token automaticamente, por lo que ya no vuelven a pedir
claim_codey nadie mas puede actualizar los datos de ese participante sin el token correcto.
Consecuencias practicas del flujo:
- El primer enlace solo funciona si
display_namecoincide exactamente con el nombre visible preasignado para eseclaim_code. - Un
claim_codeinvalido en el primer enlace es rechazado por el servidor remoto. - Un
sync_tokenincorrecto tambien es rechazado cuando alguien intenta actualizar un participante ya vinculado. - Cuando ya existe vinculacion, el dashboard local construye el link al tablero remoto con
?participant=<display_name>para resaltar tu posicion al abrir la vista compartida.
.auth/storage_state.jsones la sesion reutilizable principal del flujo HTTP..auth/ua_profile/conserva el perfil persistente de Chromium usado solo cuando hay que renovar la sesion.UA_HEADLESSyUA_SLOW_MOsolo afectan ese flujo de renovacion.UA_MANTENER_SESION=trueresponde automaticamente la pantalla de Microsoft "Mantener sesion iniciada".
Si necesitas refrescar fixtures o diagnosticar cambios de Banner, puedes capturar el contrato HTTP real con:
UA_CAPTURE_BANNER_CONTRACT=true python main.py fetch --fullEso genera artifacts en data/banner_contract/, incluyendo summary.json y una captura por endpoint observado.
data/ua_grades.sqlite3: base SQLite localdata/historial_notas_*.json: exportaciones JSONdata/debug_notas_inicial.htmlydata/debug_notas_final.html: HTMLs de debug del fetch HTTPdata/banner_contract/: capturas del contrato HTTP cuandoUA_CAPTURE_BANNER_CONTRACT=true.auth/storage_state.json: sesion HTTP reutilizable.auth/ua_profile/: perfil persistente del navegador usado para renovacion
- Inicia sesion en
https://myaccount.microsoft.com/uac/device-management. - Activar la verificacion de 2 pasos con una aplicacion de Authenticator.
- Escanea el codigo QR con la aplicacion
Ente Auth. - Obtiene el secreto TOTP desde los detalles del metodo y agregalo a
.envjunto al correo y la contrasena.
- El proyecto esta pensado para uso personal y local.
- La web no scrapea en cada refresh; consume el ultimo historial guardado en SQLite.
- Si quieres actualizar tus datos desde la web, usa
Actualizar notas; el boton queda bloqueado por 1 minuto despues de una carga exitosa. - La asistencia se actualiza con un boton separado y calcula el margen usando 18 semanas por semestre.
- Los screenshots del browser solo se generan en problemas de login o renovacion, no en el fetch HTTP normal.
