#!/usr/bin/env python3 import datetime from typing import List from bs4 import BeautifulSoup import tempfile import sys import os import urllib.request from datetime import date, timedelta URL_SLADOVNICKA = "https://sladovnicka.unasplzenchutna.cz/cz/denni-nabidka" URL_MOTLICI = "https://www.umotliku.cz" URL_TECHTOWER = "https://www.equifarm.cz/restaurace-techtower" DAY_NAMES = ['pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota', 'neděle'] # Fráze v názvech jídel, které naznačují že se jedná o polévku SOUP_NAMES = ['polévka', 'česnečka', 'česnekový krém', 'cibulačka', 'vývar'] class bcolors: HEADER = '\033[95m' OKBLUE = '\033[94m' OKCYAN = '\033[96m' OKGREEN = '\033[92m' WARNING = '\033[93m' FAIL = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' class Food: name = None amount = None price = None is_soup = False def __init__(self, name, amount, price, is_soup=False) -> None: self.name = name self.amount = amount self.price = price self.is_soup = is_soup def getOrDownloadHtml(prefix: str, url: str): '''Vrátí HTML pro daný prefix pro aktuální den. Pokud v tempu neexistuje, provede jeho stažení z předané URL a uložení.''' filename = prefix + "_" + date.today().strftime("%Y_%m_%d") + ".html" filepath = os.path.join(tempfile.gettempdir(), filename) if not os.path.isfile(filepath): urllib.request.urlretrieve(url, filepath) file = open(filepath, "r") contents = file.read() file.close() return contents def isNameOfDay(text: str): '''Vrátí True, pokud předaný text představuje název dne v týdnu (např. "pondělí")''' return text.strip().lower() in DAY_NAMES def getDayNameOfDate(date: datetime.datetime): '''Vrátí název dne v týdnu - např. pondělí, úterý, ...''' return DAY_NAMES[date.weekday()] def getStartOfWeekDate(): '''Vrátí datetime představující pondělí v aktuálním týdnu.''' today = datetime.datetime.now() return today - timedelta(days=today.weekday()) def isTextSoupName(text: str): '''Vrátí True, pokud se předaný text jeví jako název polévky. Používá se tam, kde nemáme lepší způsob detekce (TechTower).''' for name in SOUP_NAMES: if name in text.lower(): return True return False def printMenu(name: str, foodList: List[Food]): '''Vytiskne jídelní lístek na obrazovku.''' print(f"{bcolors.OKGREEN}{name}{bcolors.ENDC}\n---------------------------------------------------------------------------------") maxLength = 0 for jidlo in foodList: if len(jidlo.name) > maxLength: maxLength = len(jidlo.name) for jidlo in foodList: barva = bcolors.HEADER if jidlo.is_soup else bcolors.WARNING print(f"{barva}{jidlo.amount}\t{jidlo.name.ljust(maxLength)}\t{bcolors.ENDC}{bcolors.OKCYAN}{jidlo.price}{bcolors.ENDC}") print('\n') def getMenuSladovnicka() -> List[Food]: html = getOrDownloadHtml('sladovnicka', URL_SLADOVNICKA) soup = BeautifulSoup(html, "html.parser") div = soup.select_one("div.tab-pane.fade.in.active") datumDen = div.find("h2").text split = datumDen.split(".") denMesic = split[0] + "." + split[1] + "." # nazevDen = split[2] dnesniDatum = date.today().strftime("%-d.%-m.") if denMesic != dnesniDatum: print('Chyba: neočekávané datum na stránce Sladovnické (' + denMesic + '), očekáváno ' + dnesniDatum, file=sys.stderr) sys.exit(1) tables = div.find_all("table", {"class": "simple"}) if len(tables) != 2: print('Chyba: neočekávaný počet tabulek na stránce Sladovnické (' + str(len(tables)) + '), očekávány 2', file=sys.stderr) sys.exit(1) foodList: List[Food] = [] polevkaValues = tables[0].find_all("td") amount = polevkaValues[0].text.strip() name = polevkaValues[1].text.strip() price = polevkaValues[2].text.strip() foodList.append(Food(name, amount, price, True)) foodTables = tables[1].find_all("tr") for food in foodTables: rows = food.find_all("td") if (len(rows) != 3): print("Neočekávaný počet řádek hlavního jídla Sladovnické (" + str(len(rows)) + ", očekávány 3, přeskakuji...") continue amount = rows[0].text.strip() name = rows[1].text.strip() price = rows[2].text.strip() foodList.append(Food(name, amount, price)) return foodList def getMenuUMotliku() -> List[Food]: html = getOrDownloadHtml('u_motliku', URL_MOTLICI) soup = BeautifulSoup(html, "html.parser") table = soup.find("table", {"class": "Xtable-striped"}) rows = table.find_all("tr") if len(rows) < 4: print('Chyba: neočekávaný celkový počet řádek tabulky (' + str(len(rows)) + '), očekáváno 4 a více', file=sys.stderr) sys.exit(1) foodList: List[Food] = [] if rows[0].td.text.strip() == 'Polévka': tds = rows[1].find_all("td") if len(tds) != 3: print('Chyba: neočekávaný počet elementů v řádce polévky (' + str(len(tds)) + '), očekáváno 3', file=sys.stderr) sys.exit(1) amount = tds[0].text.strip() name = tds[1].text.strip() price = tds[2].text.strip().replace(',-', '') foodList.append(Food(name, amount, price, True)) rows = rows[2:] if rows[0].td.text.strip() == 'Hlavní jídlo': for i in range(1, len(rows)): tds = rows[i].find_all("td") if len(tds) != 3: print("Neočekávaný počet elementů (" + str(len(tds) ) + ") pro hlavní jídlo " + str(i) + ", přeskakuji") continue amount = tds[0].text.strip() name = tds[1].text.strip() price = tds[2].text.strip().replace(',-', '') foodList.append(Food(name, amount, price)) return foodList def getMenuTechTower() -> List[Food]: html = getOrDownloadHtml('techtower', URL_TECHTOWER) soup = BeautifulSoup(html, "html.parser") fonts = soup.find_all("font", {"class": ["wsw-41"]}) font = None for f in fonts: if (f.text.strip().startswith("Obědy")): font = f if font is None: print('Chyba: nenalezen pro obědy v HTML Techtower.', file=sys.stderr) sys.exit(1) siblings = font.parent.parent.find_next_siblings("p") # dayNumber = date.today().strftime("%w") currentDayName = getDayNameOfDate(datetime.datetime.now()) foodList = [] doParse = False for i in range(0, len(siblings)): text = siblings[i].text.strip().replace('\t', '').replace('\n', ' ') if isNameOfDay(text): if text == currentDayName: # Našli jsme dnešní den, odtud začínáme parsovat jídla doParse = True elif doParse == True: # Už parsujeme jídla, ale narazili jsme na následující den - končíme break elif doParse: if len(text.strip()) == 0: # Prázdná řádka - končíme (je za pátečním menu TechTower) break price = '? Kč' if text.endswith('Kč'): split = text.rsplit(' ', 2) price = " ".join(split[1:]) text = split[0] foodList.append(Food(text, '-', price, isTextSoupName(text))) return foodList if __name__ == "__main__": if len(sys.argv) > 1: input = sys.argv[1].lower() selectedDate = None if input[0].isalpha(): matches = [] for day in DAY_NAMES: if day.startswith(input): matches.append(day) if len(matches) == 1: print("Match - den v týdnu - " + matches[0]) selectedDate = getStartOfWeekDate( ) + timedelta(DAY_NAMES.index(matches[0])) elif len(matches) == 0: # TODO zkusit v, z (včera, zítra) if 'zítra'.startswith(input): print("Match - zítra") selectedDate = datetime.datetime.now() + timedelta(days=1) elif 'včera'.startswith(input): print("Match - včera") selectedDate = datetime.datetime.now() + timedelta(days=-1) elif 'dneska'.startswith(input): print("Match - dnes") selectedDate = datetime.datetime.now() else: print('Nejasný parametr "' + input + '" - může znamenat jednu z možností: ' + ', '.join(matches), file=sys.stderr) sys.exit(1) else: # TODO implementovat zadání datem print('Zadání datem není aktuálně implementováno', file=sys.stderr) sys.exit(1) print("Datum: " + selectedDate.strftime('%d.%m.%Y')) print("Den: " + getDayNameOfDate(selectedDate)) # printMenu('Sladovnická', getMenuSladovnicka()) # printMenu('U Motlíků', getMenuUMotliku()) # printMenu('TechTower', getMenuTechTower())