Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions catalog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
TEACHERS = [
{"id": "432837452", "fullname": "Р.Р. Юзькив"},
{"id": "335824546", "fullname": "А.И. Максимов"},
{"id": "664017039", "fullname": "А.Н. Борисов"},
{"id": "364272302", "fullname": "А.А. Агафонов"},
{"id": "147619112", "fullname": "А.В. Кузнецов"},
{"id": "333991624", "fullname": "А.В. Веричев"},
{"id": "544973937", "fullname": "Д.А. Шапиро"},
{"id": "62061001", "fullname": "В.В. Мясников"},
{"id": "114869468", "fullname": "А.В. Сергеев"},
{"id": "594502705", "fullname": "П.В. Чернышев"},
]

GROUPS = [
{"id": "1282690301", "title": "6411-100503D - Информационная безопасность"},
{"id": "1282690279", "title": "6412-100503D - Информационная безопасность"},
{"id": "1213641978", "title": "6413-100503D - Информационная безопасность"},
]
121 changes: 121 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Университетское расписание</title>
<link rel="stylesheet" href="/static/styles.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="app-wrapper">
<div class="top-panel">
<div class="main-container">
<div class="panel-row">
<div class="university-title">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path d="M4 12 L12 3 L20 12 L12 21 Z"/>
<path d="M8 12 L12 8 L16 12 L12 16 Z"/>
</svg>
<span>Расписание учебных занятий</span>
</div>
<div class="week-status">
<span id="currentWeekBadge"></span>
</div>
</div>
</div>
</div>

<div class="content-area">
<div class="main-container">
<div class="mode-selector">
<button id="btnGroups" class="mode-btn active">Студенческие группы</button>
<button id="btnTeachers" class="mode-btn">Преподавательский состав</button>
</div>

<div class="settings-block">
<div class="setting-item">
<div class="setting-caption">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path d="M12 2 L12 7 M12 2 L9 5 M12 2 L15 5"/>
<circle cx="12" cy="12" r="4"/>
<path d="M5 5 L7 7 M19 5 L17 7"/>
</svg>
<span id="selectLabel">Группа</span>
</div>
<select id="entitySelect" class="custom-select">
<option value="">Загрузка...</option>
</select>
</div>

<div class="setting-item">
<div class="setting-caption">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
<line x1="16" y1="2" x2="16" y2="6"/>
<line x1="8" y1="2" x2="8" y2="6"/>
<line x1="3" y1="10" x2="21" y2="10"/>
</svg>
Учебная неделя
</div>
<div class="week-navigation">
<button class="nav-btn" id="weekPrev">‹</button>
<input type="number" id="weekInput" class="week-field" min="1" max="52" value="1">
<button class="nav-btn" id="weekNext">›</button>
</div>
</div>
</div>

<div class="type-legend">
<div class="legend-label">Виды занятий:</div>
<div class="legend-items">
<div class="legend-entry"><div class="legend-marker mark-lecture"></div><span>Лекционное</span></div>
<div class="legend-entry"><div class="legend-marker mark-practical"></div><span>Практическое</span></div>
<div class="legend-entry"><div class="legend-marker mark-labwork"></div><span>Лабораторное</span></div>
<div class="legend-entry"><div class="legend-marker mark-exam"></div><span>Экзамен</span></div>
<div class="legend-entry"><div class="legend-marker mark-credit"></div><span>Зачёт</span></div>
<div class="legend-entry"><div class="legend-marker mark-other"></div><span>Прочее</span></div>
</div>
</div>

<div id="loadingIndicator" class="loading-panel" style="display: none;">
<div class="loading-spinner"></div>
<span>Обработка данных...</span>
</div>

<div class="timetable-block">
<div class="timetable-scroll">
<table class="timetable-grid">
<thead>
<tr>
<th>Временной интервал</th>
<th>ПН</th>
<th>ВТ</th>
<th>СР</th>
<th>ЧТ</th>
<th>ПТ</th>
<th>СБ</th>
</tr>
</thead>
<tbody id="scheduleBody">
<tr>
<td colspan="7" class="info-placeholder">Необходимо выбрать группу или преподавателя</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>

<div class="bottom-footer">
<div class="main-container">
<p>Самарский университет | Автоматическое обновление данных</p>
</div>
</div>
</div>

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="/static/script.js"></script>
</body>
</html>
94 changes: 94 additions & 0 deletions parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from bs4 import BeautifulSoup

def parse_schedule(html):
soup = BeautifulSoup(html, 'html.parser')

day_map = {
'понедельник': 'monday', 'вторник': 'tuesday',
'среда': 'wednesday', 'четверг': 'thursday',
'пятница': 'friday', 'суббота': 'saturday'
}

days = [day_map.get(d.text.strip().lower(), d.text.strip().lower())
for d in soup.select('.schedule__head-weekday')]

if not days:
days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']

days = days[5:] + days[:5]

time_slots = [
"08:00-09:35", "09:45-11:20", "11:30-13:05",
"13:30-15:05", "15:15-16:50", "17:00-18:35"
]

items = soup.select('.schedule__items .schedule__item')

lesson_cells = []
for item in items:
if item.find(class_='schedule__head') or item.find(class_='schedule__time-item'):
continue
lesson_cells.append(item)

rows = [lesson_cells[i:i + 6] for i in range(0, len(lesson_cells), 6)]

for idx, row in enumerate(rows):
if any(cell.find(class_='schedule__lesson') for cell in row):
rows = rows[idx:]
break

rows = [row for row in rows if any(cell.find(class_='schedule__lesson') for cell in row)]

schedule = []

for row_idx, row in enumerate(rows):
if row_idx >= len(time_slots):
break

day_data = {}

for col_idx, cell in enumerate(row):
if col_idx >= len(days):
continue

day = days[col_idx]
lessons = []

for lesson in cell.select('.schedule__lesson'):
title = lesson.select_one('.schedule__discipline')
teacher = lesson.select_one('.schedule__teacher')
place = lesson.select_one('.schedule__place')
type_chip = lesson.select_one('.schedule__lesson-type-chip')

title_text = title.text.strip() if title else ""

teacher_text = ""
if teacher:
a = teacher.find('a')
teacher_text = a.text.strip() if a else teacher.text.strip()

place_text = place.text.strip() if place else ""
type_text = type_chip.text.strip() if type_chip else ""

type_class = 'lesson'
if 'лекц' in type_text.lower():
type_class = 'lecture'
elif 'практ' in type_text.lower():
type_class = 'practice'
elif 'лаб' in type_text.lower():
type_class = 'lab'

if title_text:
lessons.append({
"title": title_text,
"teacher": teacher_text,
"room": place_text,
"type": type_text if type_text else "Занятие",
"typeClass": type_class
})

day_data[day] = lessons

schedule.append({"time": time_slots[row_idx], "days": day_data})

return schedule
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fastapi
uvicorn
requests
beautifulsoup4
Loading