Обновления сентября 2025

This commit is contained in:
2025-10-08 10:24:08 +04:00
parent 4ef3e1d25f
commit 5022309848
7 changed files with 607 additions and 562 deletions
+4 -3
View File
@@ -1,3 +1,4 @@
__pycache__ __pycache__
lecture.json lecture.json
result.txt result.txt
custom.txt
+9
View File
@@ -0,0 +1,9 @@
День недели
Номер пары
Название занятия
Преподаватель
ВТ
6
Обеспечение антитеррористической защищенности объектов здравоохранения Российской Федерации
Окутина Н Н
-24
View File
@@ -1,24 +0,0 @@
ВТ
2
Методика сохранения и укрепления традиционных российских духовно-нравственных ценностей и профилактики деструктивной идеологии
Сергеева Юлия Валерьевна
ВТ
3
Методика сохранения и укрепления традиционных российских духовно-нравственных ценностей и профилактики деструктивной идеологии
Сергеева Юлия Валерьевна
ПТ
2
Методика сохранения и укрепления традиционных российских духовно-нравственных ценностей и профилактики деструктивной идеологии
Сергеева Юлия Валерьевна
ПТ
3
Методика сохранения и укрепления традиционных российских духовно-нравственных ценностей и профилактики деструктивной идеологии
Сергеева Юлия Валерьевна
ПТ
4
Методика сохранения и укрепления традиционных российских духовно-нравственных ценностей и профилактики деструктивной идеологии
Сергеева Юлия Валерьевна
+99 -75
View File
@@ -1,75 +1,99 @@
import json import json
import requests import requests
import time import time
import tqdm import tqdm
class Non200StatusCodeError(Exception): class Non200StatusCodeError(Exception):
def __init__(self, status_code, message="Сервер вернул не 200 код"): def __init__(self, status_code, message="Сервер вернул не 200 код"):
self.status_code = status_code self.status_code = status_code
self.message = message self.message = message
super().__init__(self.message) super().__init__(self.message)
def __str__(self): def __str__(self):
return f"{self.message}. Код статуса: {self.status_code}" return f"{self.message}. Код статуса: {self.status_code}"
def do_request(name, start, end): class ResultFileWriter:
response = requests.post( def __init__(self, filename):
"https://ulsu.ru/oto/api/production/external/createKtalkMeeting.php", self.filename = filename
data={ self.file = None
"name": name, self.last_auditorium = ""
"desc": "Встреча создана средствами API (Copyright © 2023 Kravenrus), обработка расписания © Kozhilya", self.last_day_of_week = ""
"startAt": start,
"endAt": end, def __enter__(self):
"stateAnonymous": "true", self.file = open(self.filename, "w", encoding="utf-8")
"stateSessionHalls": "false", return self
"stateLobby": "false",
"stateSip": "false", def __exit__(self, exc_type, exc_val, exc_tb):
"stateAutoRecording": "true", if self.file:
"stateAudioPolicy": "false", self.file.close()
"stateVideoPolicy": "false",
"stateScreenSharePolicy": "false", def write_lecture(self, lecture, url):
"pinCode": "false" """Записывает информацию о лекции в файл"""
}, if lecture['auditorium'] != self.last_auditorium:
headers={ \ if self.last_auditorium != "":
"Referer": "https://ulsu.ru/oto/ktalk/" self._write_line("\n========================\n")
} self._write_line(lecture['auditorium'] + "\n")
) self.last_auditorium = lecture['auditorium']
self.last_day_of_week = ""
if response.status_code == 200:
time.sleep(5) if lecture['day_of_week'] != self.last_day_of_week:
data = response.json() prefix = f" {lecture['day_of_week']} "
return f"https://{data['meetingData']['global']['space']}.ktalk.ru/{data['createdMeeting']['roomName']}" self.last_day_of_week = lecture['day_of_week']
else:
else: prefix = " " * 6
raise Non200StatusCodeError(response.status_code, "Ответ сервера: " + response.text)
self._write_line(f"{prefix} #{lecture['pair_number']} - {lecture['name']}\n")
if __name__ == "__main__": self._write_line(" " * 12 + url + "\n")
lines = []
def _write_line(self, line):
with open("lecture.json", "r", encoding="utf-8") as f: """Вспомогательный метод для записи строки в файл"""
lectures = json.load(f) self.file.write(line)
self.file.flush() # Принудительно сбрасываем буфер
last_auditorium = ""
last_day_of_week = "" def do_request(name, start, end):
response = requests.post(
for lecture in tqdm.tqdm(lectures): "https://ulsu.ru/oto/api/production/external/createKtalkMeeting.php",
url = do_request(lecture['name'], lecture['start'], lecture['end']) data={
"name": name,
if lecture['auditorium'] != last_auditorium: "desc": "Встреча создана средствами API (Copyright © 2023 Kravenrus), обработка расписания © Kozhilya",
if last_auditorium != "": "startAt": start,
lines.append("\n========================\n") "endAt": end,
lines.append(lecture['auditorium'] + "\n") "stateAnonymous": "true",
last_auditorium = lecture['auditorium'] "stateSessionHalls": "false",
last_day_of_week = "" "stateLobby": "false",
"stateSip": "false",
if lecture['day_of_week'] != last_day_of_week: "stateAutoRecording": "true",
prefix = f" {lecture['day_of_week']} " "stateAudioPolicy": "false",
last_day_of_week = lecture['day_of_week'] "stateVideoPolicy": "false",
else: "stateScreenSharePolicy": "false",
prefix = " " * 6 "pinCode": "false"
},
lines.append(f"{prefix} #{lecture['pair_number']} - {lecture['name']}\n") headers={
lines.append(" " * 12 + url + "\n") "Referer": "https://ulsu.ru/oto/ktalk/"
}
with open("result.txt", "w", encoding="utf-8") as f: )
f.writelines(lines)
if response.status_code == 200:
time.sleep(5)
data = response.json()
return f"https://{data['meetingData']['global']['space']}.ktalk.ru/{data['createdMeeting']['roomName']}"
else:
raise Non200StatusCodeError(response.status_code, "Ответ сервера: " + response.text)
if __name__ == "__main__":
with open("lecture.json", "r", encoding="utf-8") as f:
lectures = json.load(f)
# Используем контекстный менеджер для работы с файлом
with ResultFileWriter("result.txt") as writer:
for lecture in tqdm.tqdm(lectures):
try:
url = do_request(lecture['name'], lecture['start'], lecture['end'])
writer.write_lecture(lecture, url)
except Exception as e:
# Записываем информацию об ошибке в файл
error_line = f"\nОШИБКА при обработке лекции '{lecture['name']}': {str(e)}\n\n"
writer._write_line(error_line)
print(f"Произошла ошибка: {e}")
# Продолжаем обработку следующих лекций
continue
+15 -14
View File
@@ -1,15 +1,16 @@
{ {
"first_week": "2025-01-06", "first_week": "2025-09-01",
"week": [ "week": [
"ПН", "ПН",
"ВТ", "ВТ",
"СР", "СР",
"ЧТ", "ЧТ",
"ПТ", "ПТ",
"СБ" "СБ"
], ],
"aliases": { "aliases": {
"Введение в НОК": "Введение в специальности Н.О.К.", "Введение в НОК": "Введение в специальности Н.О.К.",
"Проф.электив. Введение в специальность стоматология": "Предпрофессиональный электив. Введение в специальность Стоматология" "Проф.электив. Введение в специальность стоматология": "Предпрофессиональный электив. Введение в специальность Стоматология" ,
} "Абделбаги Мохаммат абба нана": "Абделбаги Махаммат абба нана"
}
} }
+406 -372
View File
@@ -1,373 +1,407 @@
import gspread import gspread
import requests import requests
from datetime import datetime, timedelta from datetime import datetime, timedelta
import json import json
import random import random
import time import time
import re import re
from functools import lru_cache import os
from functools import lru_cache
@lru_cache(None)
def partialize(s): @lru_cache(None)
s = s.lower().replace("ё", "е") def partialize(s):
p = re.split("[. ]+", s) s = s.lower().replace("ё", "е")
return list(filter(lambda a: a, p)) p = re.split("[. ]+", s)
return list(filter(lambda a: a, p))
def test_short(short: str, full: str) -> bool:
short_parts = partialize(short) def test_short(short: str, full: str) -> bool:
full_parts = partialize(full) short_parts = partialize(short)
full_parts = partialize(full)
for i in range(min(len(short_parts), len(full_parts))):
if not full_parts[i].startswith(short_parts[i]): for i in range(min(len(short_parts), len(full_parts))):
return False if not full_parts[i].startswith(short_parts[i]):
return False
return True
return True
def find_in_list(short: str, full_list: list) -> str|list:
result = [] def find_in_list(short: str, full_list: list) -> str|list:
result = []
for item in full_list:
if test_short(short, item): for item in full_list:
result.append(item) if test_short(short, item):
result.append(item)
if len(result) == 1:
return result[0] if len(result) == 1:
elif short in result: return result[0]
return short elif short in result:
else: return short
return result else:
return result
def find_teacher_by_date(input_string: str, target_date: str) -> str:
""" def find_teacher_by_date(input_string: str, target_date: str) -> str:
Ищет преподавателя по целевой дате в строке с датами и ФИО. """
Ищет преподавателя по целевой дате в строке с датами и ФИО.
:param input_string: Строка с датами и ФИО преподавателей.
:param target_date: Целевая дата в формате "%d.%m". :param input_string: Строка с датами и ФИО преподавателей.
:return: ФИО преподавателя, связанного с целевой датой, или None, если дата не найдена. :param target_date: Целевая дата в формате "%d.%m".
""" :return: ФИО преподавателя, связанного с целевой датой, или None, если дата не найдена.
# Преобразуем целевую дату в формат "%d.%m" """
target_date_str = target_date#.strftime("%d.%m") # Преобразуем целевую дату в формат "%d.%m"
target_date_str = target_date#.strftime("%d.%m")
# Регулярное выражение для поиска дат в формате "%d.%m"
date_pattern = re.compile(r"\d{2}\.\d{2}") # Регулярное выражение для поиска дат в формате "%d.%m"
date_pattern = re.compile(r"\d{2}\.\d{2}")
# Разделяем строку на строки по переносам
lines = re.split(" {5,}", input_string) # Разделяем строку на строки по переносам
lines = re.split(" {5,}", input_string)
# Проходим по каждой строке
for i in range(len(lines)): # Проходим по каждой строке
# Разделяем строку на даты и ФИО for i in range(len(lines)):
parts = lines[i].strip().split() # Разделяем строку на даты и ФИО
parts = lines[i].strip().split()
# Извлекаем даты и ФИО
dates = [] # Извлекаем даты и ФИО
teacher = "" dates = []
for part in parts: teacher = ""
if date_pattern.fullmatch(part.replace(",", "")): # Убираем запятые, если они есть for part in parts:
dates.append(part.replace(",", "")) # Убираем запятые, если они есть if date_pattern.fullmatch(part.replace(",", "")): # Убираем запятые, если они есть
else: dates.append(part.replace(",", "")) # Убираем запятые, если они есть
teacher += part + " " # Собираем ФИО else:
teacher += part + " " # Собираем ФИО
# Проверяем, есть ли целевая дата в списке дат
if target_date_str in dates: # Проверяем, есть ли целевая дата в списке дат
return teacher.strip(), i # Возвращаем ФИО преподавателя if target_date_str in dates:
return teacher.strip(), i # Возвращаем ФИО преподавателя
# Если дата не найдена
return input_string, 1 # Если дата не найдена
return input_string, 1
def shorten_name(name: str) -> str:
parts = name.split() def shorten_name(name: str) -> str:
result = "" parts = name.split()
result = ""
for i in range(len(parts)):
if i == 0: for i in range(len(parts)):
result = parts[0] + " " if i == 0:
else: result = parts[0] + " "
result += parts[i][0] + "." else:
result += parts[i][0] + "."
return result
return result
class Singleton(type):
_instances = {} class Singleton(type):
def __call__(cls, *args, **kwargs): _instances = {}
if cls not in cls._instances: def __call__(cls, *args, **kwargs):
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) if cls not in cls._instances:
return cls._instances[cls] cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Lecture:
def __init__(self, auditorium: str, day_of_week: str, pair_number: str, lecture: str, teacher: str, regular: bool = True): class Lecture:
self.struct = Structure() def __init__(self, auditorium: str, day_of_week: str, pair_number: str, lecture: str, teacher: str, regular: bool = True):
self.auditorium = auditorium self.struct = Structure()
self.day_of_week = day_of_week self.auditorium = auditorium
self.day_of_week_i = self.struct.settings["week"].index(day_of_week) self.day_of_week = day_of_week
self.pair_number = pair_number self.day_of_week_i = self.struct.settings["week"].index(day_of_week)
self.input_teacher = teacher self.pair_number = pair_number
self.input_lecture = lecture self.input_teacher = teacher
self.input_lecture = lecture
print("[Пара] ", self.auditorium, "/", self.day_of_week, "/", self.pair_number)
print("[Пара] ", self.auditorium, "/", self.day_of_week, "/", self.pair_number)
self.process_time()
self.process_time()
if regular:
self.teacher = self.process_teacher() if regular:
if self.teacher == False: self.teacher = self.process_teacher()
self.complete = False if self.teacher == False:
print() self.complete = False
return print()
return
self.lecture = self.process_lecture()
if self.lecture == False: self.lecture = self.process_lecture()
self.complete = False if self.lecture == False:
print() self.complete = False
return print()
return
print("[Препод.] ", self.input_teacher, "->", self.teacher)
print("[Предмет] ", self.input_lecture, "->", self.lecture) print("[Препод.] ", self.input_teacher, "->", self.teacher)
else: print("[Предмет] ", self.input_lecture, "->", self.lecture)
self.teacher = self.input_teacher else:
self.lecture = self.input_lecture self.teacher = self.input_teacher
self.lecture = self.input_lecture
self.name = self.format_name()
self.complete = True self.name = self.format_name()
self.complete = True
print()
print()
def process_time(self):
target_date = self.struct.monday + timedelta(days=self.day_of_week_i) def process_time(self):
self.date = target_date.strftime("%d.%m") target_date = self.struct.monday + timedelta(days=self.day_of_week_i)
self.date = target_date.strftime("%d.%m")
for call in self.struct.calls:
if call["lesson"] == self.pair_number: for call in self.struct.calls:
start_time = datetime.fromisoformat("2025-01-01T" + call["start_time"]) if call["lesson"] == self.pair_number:
end_time = datetime.fromisoformat("2025-01-01T" + call["end_time"]) start_time = datetime.fromisoformat("2025-01-01T" + call["start_time"])
end_time = datetime.fromisoformat("2025-01-01T" + call["end_time"])
# Объединяем дату и время
self.start = target_date.replace( # Объединяем дату и время
hour=start_time.hour, self.start = target_date.replace(
minute=start_time.minute, hour=start_time.hour,
second=start_time.second, minute=start_time.minute,
microsecond=0, second=start_time.second,
tzinfo=start_time.tzinfo microsecond=0,
).isoformat(timespec="milliseconds") tzinfo=start_time.tzinfo
self.end = target_date.replace( ).isoformat(timespec="milliseconds")
hour=end_time.hour, self.end = target_date.replace(
minute=end_time.minute, hour=end_time.hour,
second=end_time.second, minute=end_time.minute,
microsecond=0, second=end_time.second,
tzinfo=end_time.tzinfo microsecond=0,
).isoformat(timespec="milliseconds") tzinfo=end_time.tzinfo
def process_teacher(self) -> str: ).isoformat(timespec="milliseconds")
teacher, self.teacher_index = find_teacher_by_date(self.input_teacher, self.date) def process_teacher(self) -> str:
teacher, self.teacher_index = find_teacher_by_date(self.input_teacher, self.date)
if teacher in self.struct.settings["aliases"].keys():
teacher = self.struct.settings["aliases"][teacher] if teacher in self.struct.settings["aliases"].keys():
teacher = self.struct.settings["aliases"][teacher]
variants = find_in_list(teacher, self.struct.teachers)
variants = find_in_list(teacher, self.struct.teachers)
return self.select_variant(teacher, variants, True)
def process_lecture(self) -> str: return self.select_variant(teacher, variants, True)
parts = re.split(" {5,}", self.input_lecture) def process_lecture(self) -> str:
# parts = re.split(" {5,}", self.input_lecture)
if self.teacher_index < len(parts): lecture, _ = find_teacher_by_date(self.input_lecture, self.date)
lecture = parts[self.teacher_index]
else: # if self.teacher_index < len(parts):
lecture = parts[0] # lecture = parts[self.teacher_index]
# else:
if lecture in self.struct.settings["aliases"].keys(): # lecture = parts[0]
lecture = self.struct.settings["aliases"][lecture]
if lecture in self.struct.settings["aliases"].keys():
variants = find_in_list(lecture, self.struct.disciplines) lecture = self.struct.settings["aliases"][lecture]
return self.select_variant(lecture, variants, False) variants = find_in_list(lecture, self.struct.disciplines)
def format_name(self) -> str: return self.select_variant(lecture, variants, False)
formatted_date = datetime.fromisoformat(self.start).strftime("%H:%M %d.%m.%Y")
return f"{self.lecture} [{shorten_name(self.teacher)}] ({formatted_date})" def format_name(self) -> str:
formatted_date = datetime.fromisoformat(self.start).strftime("%H:%M %d.%m.%Y")
def select_variant(self, search: str, variants: str|list, is_teacher: bool) -> bool|str: return f"{self.lecture} [{shorten_name(self.teacher)}] ({formatted_date})"
if isinstance(variants, str):
return variants def select_variant(self, search: str, variants: str|list, is_teacher: bool) -> bool|str:
if isinstance(variants, str):
print("Невозможно выбрать", return variants
"преподавателя" if is_teacher else "лекцию",
"для значения", print("Невозможно выбрать",
f'"{search}".', "преподавателя" if is_teacher else "лекцию",
"Выберите вариант:" if len(variants) > 0 else "") "для значения",
f'"{search}".',
if len(variants) == 0: "Выберите вариант:" if len(variants) > 0 else "")
return False
if len(variants) == 0:
for i in range(len(variants)): return False
print(str(i + 1).rjust(3) + ".", variants[i])
print(" 0. [Пропустить]") for i in range(len(variants)):
print(str(i + 1).rjust(3) + ".", variants[i])
choice = int(input("Введите значение: ")) - 1 print(" 0. [Пропустить]")
if choice < 0: choice = int(input("Введите значение: ")) - 1
return False
if choice < 0:
return variants[choice] return False
def json(self) -> dict|None: return variants[choice]
return {
"auditorium": self.auditorium, def json(self) -> dict|None:
"day_of_week": self.day_of_week, return {
"pair_number": self.pair_number, "auditorium": self.auditorium,
"input_lecture": self.input_lecture, "day_of_week": self.day_of_week,
"input_teacher": self.input_teacher, "pair_number": self.pair_number,
"input_lecture": self.input_lecture,
"input_teacher": self.input_teacher,
"teacher": self.teacher,
"lecture": self.lecture,
"start": self.start, "teacher": self.teacher,
"end": self.end, "lecture": self.lecture,
"name": self.name "start": self.start,
} "end": self.end,
"name": self.name
class Structure(metaclass=Singleton): }
def __init__(self):
print("Подключение Google Sheets...", end=" ") class Structure(metaclass=Singleton):
gc = gspread.oauth() def __init__(self):
self.document = gc.open_by_key("1srtrHkwbTCfvxyeDtb_ca4RMx8W1kxgUQ-MAIumamVA") print("Подключение Google Sheets...", end=" ")
print("Готово.") # gc = self.load_gspread()
# self.document = gc.open_by_key("1srtrHkwbTCfvxyeDtb_ca4RMx8W1kxgUQ-MAIumamVA")
print("Загрузка настроек...", end=" ") self.document = self.load_gspread()
with open("settings.json", 'r', encoding='utf-8') as file: print("Готово.")
self.settings = json.load(file)
print("Готово.") print("Загрузка настроек...", end=" ")
with open("settings.json", 'r', encoding='utf-8') as file:
print("Загрузка списка преподавателей...", end=" ") self.settings = json.load(file)
self.teachers = list(map(lambda a: a["name"], self.get_json("teachers"))) print("Готово.")
print("Готово.")
print("Загрузка списка преподавателей...", end=" ")
print("Загрузка списка дисциплин...", end=" ") self.teachers = list(map(lambda a: a["name"], self.get_json("teachers")))
self.disciplines = list(map(lambda a: a["name"], self.get_json("disciplines"))) print("Готово.")
print("Готово.")
print("Загрузка списка дисциплин...", end=" ")
print("Загрузка расписания...", end=" ") self.disciplines = list(map(lambda a: a["name"], self.get_json("disciplines")))
self.calls = self.get_json("calls", "schedule") print("Готово.")
print("Готово.")
print("Загрузка расписания...", end=" ")
self.monday = self.get_monday() self.calls = self.get_json("calls", "schedule")
self.week = self.get_week_number() print("Готово.")
print("Данные загружены!") self.monday = self.get_monday()
self.week = self.get_week_number()
def get_json(self, type, sub_type=None) -> dict:
resp = requests.get(url="https://ulsu.ru/oto/api/production/internal/getEnterpriseData.php?type=" + type, params={}) print("Данные загружены!")
return resp.json()[type if sub_type is None else sub_type]
def load_gspread(self) -> gspread.Spreadsheet:
def get_monday(self): try:
today = datetime.today() gc = gspread.oauth()
days_until_next_monday = (7 - today.weekday()) % 7 except:
self.remove_auth_data()
# Если сегодня понедельник, days_until_next_monday будет 0, поэтому добавляем 7 дней gc = gspread.oauth()
# if days_until_next_monday == 0:
# days_until_next_monday = 7 try:
return gc.open_by_key("1srtrHkwbTCfvxyeDtb_ca4RMx8W1kxgUQ-MAIumamVA")
return today + timedelta(days=days_until_next_monday) except:
def get_week_number(self, target_date:datetime|None=None): self.remove_auth_data()
if target_date is None: return gc.open_by_key("1srtrHkwbTCfvxyeDtb_ca4RMx8W1kxgUQ-MAIumamVA")
target_date = self.monday
def remove_auth_data(self):
first_week_start_date = datetime.strptime(self.settings["first_week"], "%Y-%m-%d") appdata_path = os.environ.get('APPDATA')
file_path = os.path.join(appdata_path, "gspread", "authorized_user.json")
return ((target_date - first_week_start_date).days // 7) % 2 + 1 os.remove(file_path)
def get_worksheets(self):
return self.document.worksheets() def get_json(self, type, sub_type=None) -> dict:
def get_document_data(self, worksheet, range_name=None, max_retries=5, initial_backoff=1, maximum_backoff=32): resp = requests.get(url="https://ulsu.ru/oto/api/production/internal/getEnterpriseData.php?type=" + type, params={})
retries = 0 return resp.json()[type if sub_type is None else sub_type]
while retries < max_retries:
try: def get_monday(self):
if range_name is None: today = datetime.today()
return worksheet.get_all_values() days_until_next_monday = (7 - today.weekday()) % 7
else:
return worksheet.get(range_name) # Если сегодня понедельник, days_until_next_monday будет 0, поэтому добавляем 7 дней
except gspread.exceptions.APIError as e: # if days_until_next_monday == 0:
retries += 1 # days_until_next_monday = 7
if retries == max_retries:
raise e return today + timedelta(days=days_until_next_monday)
def get_week_number(self, target_date:datetime|None=None):
backoff = min(initial_backoff * (2 ** (retries - 1)) + random.random(), maximum_backoff) if target_date is None:
time.sleep(backoff) target_date = self.monday
def find_range(self, worksheet, first_week=True):
def check(cell): first_week_start_date = datetime.strptime(self.settings["first_week"], "%Y-%m-%d")
if first_week:
return "1 неделя" in cell or "I неделя" in cell return ((target_date - first_week_start_date).days // 7) % 2 + 1
else:
return "2 неделя" in cell or "II неделя" in cell def get_worksheets(self):
return self.document.worksheets()
all_values = self.get_document_data(worksheet) def get_document_data(self, worksheet, range_name=None, max_retries=5, initial_backoff=1, maximum_backoff=32):
retries = 0
week_row = None while retries < max_retries:
for i, row in enumerate(all_values): try:
for j, cell in enumerate(row): if range_name is None:
if check(cell): return worksheet.get_all_values()
week_row = i + 1 else:
break return worksheet.get(range_name)
if week_row is not None: except gspread.exceptions.APIError as e:
break retries += 1
if retries == max_retries:
for row in range(week_row, worksheet.row_count + 1): raise e
cell_value = all_values[row][0]
if cell_value == "1": backoff = min(initial_backoff * (2 ** (retries - 1)) + random.random(), maximum_backoff)
return "C%d:H%d" % (row+1, row+16) time.sleep(backoff)
def find_range(self, worksheet, first_week=True):
def get_lectures_from_range(self, worksheet, range_name) -> list: def check(cell):
# Получаем название аудитории из названия листа if first_week:
auditorium = worksheet.title return "1 неделя" in cell or "I неделя" in cell
else:
# Получаем данные из указанного диапазона return "2 неделя" in cell or "II неделя" in cell
data = self.get_document_data(worksheet, range_name)
all_values = self.get_document_data(worksheet)
if len(data) < 2: week_row = None
return [] for i, row in enumerate(all_values):
for j, cell in enumerate(row):
# Дни недели if check(cell):
days_of_week = self.settings["week"] week_row = i + 1
day_order = {day: idx for idx, day in enumerate(days_of_week)} # Словарь для порядка дней break
if week_row is not None:
# Список для хранения лекций break
lectures = []
for row in range(week_row, worksheet.row_count + 1):
# Проходим по данным cell_value = all_values[row][0]
for row_index in range(0, len(data), 2): # Шаг 2, так как каждая пара строк — это одна пара в расписании if cell_value == "1":
lecture_row = data[row_index] # Строка с названием лекции return "C%d:H%d" % (row+1, row+16)
teacher_row = data[row_index + 1] # Строка с преподавателем
def get_lectures_from_range(self, worksheet, range_name) -> list:
# Номер пары # Получаем название аудитории из названия листа
pair_number = (row_index // 2) + 1 auditorium = worksheet.title
# Проходим по дням недели (столбцам) # Получаем данные из указанного диапазона
for col_index, (lecture, teacher) in enumerate(zip(lecture_row, teacher_row)): data = self.get_document_data(worksheet, range_name)
if lecture.strip() and teacher.strip(): # Если есть и название лекции, и преподаватель
day_of_week = days_of_week[col_index] # День недели
lectures.append(Lecture(auditorium, day_of_week, pair_number, lecture, teacher)) if len(data) < 2:
return []
lectures = sorted(lectures, key=lambda x: (x.day_of_week_i, x.pair_number))
# Дни недели
return lectures days_of_week = self.settings["week"]
day_order = {day: idx for idx, day in enumerate(days_of_week)} # Словарь для порядка дней
# Список для хранения лекций
if __name__ == "__main__": lectures = []
struct = Structure()
# Проходим по данным
week = struct.get_week_number() for row_index in range(0, len(data), 2): # Шаг 2, так как каждая пара строк — это одна пара в расписании
lecture_row = data[row_index] # Строка с названием лекции
lectures = []
if row_index + 1 == len(data):
for worksheet in struct.get_worksheets(): print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
print(worksheet.title + "...") print(f"Ошибка с данными, row_index = {row_index + 1} не существует!")
range_name = struct.find_range(worksheet, week == 1) print(data)
part = struct.get_lectures_from_range(worksheet, range_name) print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
continue
lectures.extend(part)
teacher_row = data[row_index + 1] # Строка с преподавателем
lectures = list(filter(lambda l: l.complete, lectures))
# Номер пары
with open("lecture.json", "w", encoding="utf-8") as f: pair_number = (row_index // 2) + 1
# Проходим по дням недели (столбцам)
for col_index, (lecture, teacher) in enumerate(zip(lecture_row, teacher_row)):
if lecture.strip() and teacher.strip(): # Если есть и название лекции, и преподаватель
day_of_week = days_of_week[col_index] # День недели
# if col_index > 3:
# continue
lectures.append(Lecture(auditorium, day_of_week, pair_number, lecture, teacher))
lectures = sorted(lectures, key=lambda x: (x.day_of_week_i, x.pair_number))
return lectures
if __name__ == "__main__":
struct = Structure()
week = struct.get_week_number()
lectures = []
for worksheet in struct.get_worksheets():
print(worksheet.title + "...")
range_name = struct.find_range(worksheet, week == 1)
part = struct.get_lectures_from_range(worksheet, range_name)
lectures.extend(part)
lectures = list(filter(lambda l: l.complete, lectures))
with open("lecture.json", "w", encoding="utf-8") as f:
json.dump(list(map(lambda l: l.json(), lectures)), f, ensure_ascii=False, indent=4) json.dump(list(map(lambda l: l.json(), lectures)), f, ensure_ascii=False, indent=4)
+74 -74
View File
@@ -1,75 +1,75 @@
import re import re
from functools import lru_cache from functools import lru_cache
@lru_cache(None) @lru_cache(None)
def partialize(s): def partialize(s):
s = s.lower().replace("ё", "е") s = s.lower().replace("ё", "е")
p = re.split("[. ]+", s) p = re.split("[. ]+", s)
return list(filter(lambda a: a, p)) return list(filter(lambda a: a, p))
def test_short(short: str, full: str) -> bool: def test_short(short: str, full: str) -> bool:
short_parts = partialize(short) short_parts = partialize(short)
full_parts = partialize(full) full_parts = partialize(full)
for i in range(min(len(short_parts), len(full_parts))): for i in range(min(len(short_parts), len(full_parts))):
if not full_parts[i].startswith(short_parts[i]): if not full_parts[i].startswith(short_parts[i]):
return False return False
return True return True
def find_in_list(short, full_list): def find_in_list(short, full_list):
result = [] result = []
for item in full_list: for item in full_list:
if test_short(short, item): if test_short(short, item):
result.append(item) result.append(item)
if len(result) == 1: if len(result) == 1:
return result[0] return result[0]
elif short in result: elif short in result:
return short return short
else: else:
return result return result
def find_teacher_by_date(input_string, target_date): def find_teacher_by_date(input_string, target_date):
""" """
Ищет преподавателя по целевой дате в строке с датами и ФИО. Ищет преподавателя по целевой дате в строке с датами и ФИО.
:param input_string: Строка с датами и ФИО преподавателей. :param input_string: Строка с датами и ФИО преподавателей.
:param target_date: Целевая дата в формате "%d.%m". :param target_date: Целевая дата в формате "%d.%m".
:return: ФИО преподавателя, связанного с целевой датой, или None, если дата не найдена. :return: ФИО преподавателя, связанного с целевой датой, или None, если дата не найдена.
""" """
# Преобразуем целевую дату в формат "%d.%m" # Преобразуем целевую дату в формат "%d.%m"
target_date_str = target_date#.strftime("%d.%m") target_date_str = target_date#.strftime("%d.%m")
# Регулярное выражение для поиска дат в формате "%d.%m" # Регулярное выражение для поиска дат в формате "%d.%m"
date_pattern = re.compile(r"\d{2}\.\d{2}") date_pattern = re.compile(r"\d{2}\.\d{2}")
# Разделяем строку на строки по переносам # Разделяем строку на строки по переносам
lines = re.split(" {5,}", input_string) lines = re.split(" {5,}", input_string)
# Проходим по каждой строке # Проходим по каждой строке
for line in lines: for line in lines:
# Разделяем строку на даты и ФИО # Разделяем строку на даты и ФИО
parts = line.strip().split() parts = line.strip().split()
# Извлекаем даты и ФИО # Извлекаем даты и ФИО
dates = [] dates = []
teacher = "" teacher = ""
for part in parts: for part in parts:
if date_pattern.fullmatch(part.replace(",", "")): # Убираем запятые, если они есть if date_pattern.fullmatch(part.replace(",", "")): # Убираем запятые, если они есть
dates.append(part.replace(",", "")) # Убираем запятые, если они есть dates.append(part.replace(",", "")) # Убираем запятые, если они есть
else: else:
teacher += part + " " # Собираем ФИО teacher += part + " " # Собираем ФИО
# Проверяем, есть ли целевая дата в списке дат # Проверяем, есть ли целевая дата в списке дат
if target_date_str in dates: if target_date_str in dates:
return teacher.strip() # Возвращаем ФИО преподавателя return teacher.strip() # Возвращаем ФИО преподавателя
# Если дата не найдена # Если дата не найдена
return input_string return input_string
if __name__ == "__main__": if __name__ == "__main__":
# print(test_short("кузнецов в.н.", "Кузнецов Владимир Николаевич")) # print(test_short("кузнецов в.н.", "Кузнецов Владимир Николаевич"))
s = " 10.02, 24.02, 10.03 Абдусалямова Л.И . 27.01, 07.04 Голубцова Т.С. 24.03 Шаршова С.М. " s = " 10.02, 24.02, 10.03 Абдусалямова Л.И . 27.01, 07.04 Голубцова Т.С. 24.03 Шаршова С.М. "
print(find_teacher_by_date(s, "10.03")) print(find_teacher_by_date(s, "10.03"))