From 9745d580d4e04f6f6622b97094c5193635976aec Mon Sep 17 00:00:00 2001 From: Ernest Litvinenko Date: Tue, 5 Mar 2024 14:46:43 +0300 Subject: [PATCH] fix logging messages and add TG listener --- database.db | Bin 49152 -> 73728 bytes excel_parser.py | 2 +- main.py | 88 +++++++++++++++++++++++++++++++++++++++++++++-- requirements.in | 3 +- requirements.txt | 37 +++++++++++++++++++- storage.py | 5 +++ telegram_logs.py | 10 +++--- webserver.py | 4 +++ 8 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 webserver.py diff --git a/database.db b/database.db index 2b7efcc19c6ff0c32ccbcdbf531555052adcfc5a..94e41402a1b2c5e81e466d51e4c20e2837fc5809 100644 GIT binary patch delta 5637 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 BlPdrK delta 1730 zcmZuxT}&KR6rS0c-PwhOSQMdbMYeEfGA57iE_~1()e6mQI^u^e;M(^AiC=h3}XL8SX z&bf2H@0>fmB2G^Wb5E8X=Qu9v|AqN_D|nn!yN=}hKa%4?>K5g7YB@=MDE}qjm)8sX zlq>T5Tw6s+n7YFfHIWcCLGhZx$M(t1oK((nazI{@r^;`Z=gM2lx#*e4Kbqee4VR5` zKk(+QFQKBTA%O|jTDv-Nt2!|}Rz{(B1&U3%ST!<@bP>|Ux#E(GPDCl(O3`)~t;7V` zo0+BZB>#XyaX7u4ikUWY6H2J_Tk0I}<1yNdkFq3nS%{gdo zHez=78G(YeW(uBXLd(IheTnLH-Bk> zpJon}QwFTf&4brk#8@~W9OX*y2}kp}X9an_Mv4d*vcjdt#k7Bx2+hGP2ma|NVcQ{= z6&N~Ks7UdAgdH;8FKWyaJs)ok`OnsQ%ds9Q^VsU1IecqO;fQA z`JM*&d+i-qoV^jkhK(#8x=!rnO~`h%i6+4WuCJ# z6l!aJ55z9Yp%Nh%$#UnG1r25}rCq@u0LU|of)Ukwz* z*B;3Wogs0RlUDP&Z=}L%wzXag0Vl;mkk8G8$|j>>Atz*M2m13P(D}KXllX&i+c6ND zA1QVFC~&E6soS3++DHBjxsph*e@NkvQc_V=H8 zb@?|nWlX2p_9fZBCEa=VZb@G!!$5T{RHs{Tr@Qumu6zCH zwVm!YIO|GJ5aLUr+0Zgrxm)jJyfSt-+Sc<>vT7xdVH dict: + if PARSER_ALIVE is False: + raise KeyboardInterrupt("Бот остановлен по запросу") fp = self.download_documentation() e_parser = ExcelParser(fp, url) price = e_parser.calculate() @@ -116,6 +130,9 @@ class Parser: return price def accept_documentation(self, url: str): + if PARSER_ALIVE is False: + raise KeyboardInterrupt("Бот остановлен по запросу") + time.sleep(3) self._driver.get(url) @@ -142,6 +159,8 @@ class Parser: delivery_range=price['max_days']) def download_documentation(self) -> list[pathlib.Path]: + if PARSER_ALIVE is False: + raise KeyboardInterrupt("Бот остановлен по запросу") try: all_files_1 = set( pathlib.Path('./downloads') / pathlib.Path(file) for tree in os.walk('./downloads') for file in tree[2]) @@ -168,6 +187,8 @@ class Parser: raise KeyboardInterrupt() def send_offer_link(self, price: int, nds: int, delivery_range: str, delivery_time: str): + if PARSER_ALIVE is False: + raise KeyboardInterrupt("Бот остановлен по запросу") try: logger.info( f"Предварительные данные по заявке: Цена: {price}, НДС: {nds}%, Доставка: {delivery_range} дн., Подача машины {delivery_time}") @@ -220,10 +241,71 @@ class Parser: time.sleep(10) -if __name__ == "__main__": +PARSER_ALIVE = True + + +def parse_runner(): with Parser() as parser: parser.login() while True: parser.search() - logger.info("Все LTL заявки обработаны, обновление через 60сек") time.sleep(60) + + +parser_thread = threading.Thread(target=parse_runner, daemon=True) + + +@dp.message(CommandStart()) +async def start_handler(message: Message): + s = Storage() + if message.from_user.id not in s.get_users(): + await message.answer("Вы не зарегистрированы, обратитесь к администратору") + return + markup = ReplyKeyboardMarkup(keyboard=[[KeyboardButton(text="Запустить Бот")]]) + await message.answer(f"Hello, {message.from_user.full_name}!", reply_markup=markup) + + +@dp.message() +async def message_handler(message: Message): + global PARSER_ALIVE + s = Storage() + if message.from_user.id not in s.get_users(): + await message.answer("Вы не зарегистрированы, обратитесь к администратору") + return + + markup = ReplyKeyboardMarkup(keyboard=[[KeyboardButton(text="Запустить Бот")]]) + if message.text == "Запустить Бот": + PARSER_ALIVE = True + for chat_id in s.get_users(): + await bot.send_message(chat_id, + f"Пользователь {message.from_user.full_name} запускает бот", + reply_markup=markup) + parser_thread.start() + return + if message.text == "Остановить Бот": + for chat_id in s.get_users(): + await bot.send_message(chat_id, + f"Пользователь {message.from_user.full_name} остановил бот", + reply_markup=markup) + PARSER_ALIVE = False + await message.answer("Бот остановлен", reply_markup=markup) + return + await message.answer("Неизвестная команда") + + +async def main(): + storage = Storage() + markup = ReplyKeyboardMarkup(keyboard=[[KeyboardButton(text="Запустить Бот")]]) + for chat_id in storage.get_users(): + await bot.send_message(chat_id, + "Контроллер запущен, бот ожидает включения", + reply_markup=markup, + disable_notification=True) + await dp.start_polling(bot) + +if __name__ == "__main__": + # with Parser() as p: + # p.login() + # p.search() + asyncio.run(main()) + diff --git a/requirements.in b/requirements.in index 4f03502..143a01f 100644 --- a/requirements.in +++ b/requirements.in @@ -11,4 +11,5 @@ pyexcel pyexcel-xls pyexcel-xlsx loguru -pydotenv \ No newline at end of file +pydotenv +aiogram \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 95dfbef..c18c8a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,14 +4,28 @@ # # pip-compile # +aiofiles==23.2.1 + # via aiogram +aiogram==3.4.1 + # via -r requirements.in +aiohttp==3.9.3 + # via aiogram +aiosignal==1.3.1 + # via aiohttp +annotated-types==0.6.0 + # via pydantic +async-timeout==4.0.3 + # via aiohttp attrs==23.2.0 # via + # aiohttp # outcome # trio beautifulsoup4==4.12.3 # via xls2xlsx certifi==2023.11.17 # via + # aiogram # requests # selenium chardet==5.2.0 @@ -32,18 +46,29 @@ exceptiongroup==1.2.0 # trio-websocket fonttools==4.47.2 # via xls2xlsx +frozenlist==1.4.1 + # via + # aiohttp + # aiosignal h11==0.14.0 # via wsproto idna==3.6 # via # requests # trio + # yarl lml==0.1.0 # via # pyexcel # pyexcel-io loguru==0.7.2 # via -r requirements.in +magic-filter==1.0.12 + # via aiogram +multidict==6.0.5 + # via + # aiohttp + # yarl numpy==1.26.3 # via pandas openpyxl==3.1.2 @@ -59,6 +84,10 @@ pandas==2.2.0 # via -r requirements.in pillow==10.2.0 # via xls2xlsx +pydantic==2.5.3 + # via aiogram +pydantic-core==2.14.6 + # via pydantic pydotenv==0.0.7 # via -r requirements.in pyexcel==0.7.0 @@ -108,7 +137,11 @@ trio==0.24.0 trio-websocket==0.11.1 # via selenium typing-extensions==4.9.0 - # via selenium + # via + # aiogram + # pydantic + # pydantic-core + # selenium tzdata==2023.4 # via pandas urllib3[socks]==2.1.0 @@ -137,3 +170,5 @@ xlwt==1.3.0 # -r requirements.in # pyexcel-xls # xlutils +yarl==1.9.4 + # via aiohttp diff --git a/storage.py b/storage.py index 83f8f0d..cd9bf83 100644 --- a/storage.py +++ b/storage.py @@ -5,10 +5,15 @@ from typing import ContextManager class Storage: def __init__(self): + self.con = None + + def set_connection(self): self.con = sqlite3.connect("database.db") @contextmanager def get_cursor(self) -> ContextManager[sqlite3.Cursor]: + if self.con is None: + self.set_connection() cur = self.con.cursor() try: yield cur diff --git a/telegram_logs.py b/telegram_logs.py index 379dce2..406e11d 100644 --- a/telegram_logs.py +++ b/telegram_logs.py @@ -1,3 +1,5 @@ +import json + import requests from loguru import logger from storage import Storage @@ -19,11 +21,11 @@ def _log(message): r = requests.post("{0}{1}/sendMessage".format(_URL, _TOKEN), { "chat_id": int(chat_id), "disable_notification": True, - "text": icon + message + "text": icon + message, + "reply_markup": json.dumps({"keyboard": [[{"text": "Остановить Бот"}]]}) }) - - if r.status_code >= 400: - logger.error("Failed to send message: {0} {1}".format(r.status_code, r.text)) + if r.status_code != 200: + print(r.json()) def _filter_info_only(record): diff --git a/webserver.py b/webserver.py new file mode 100644 index 0000000..066ef1a --- /dev/null +++ b/webserver.py @@ -0,0 +1,4 @@ +from aiogram import Bot, Dispatcher + +dp = Dispatcher() +bot = Bot(token="6767909836:AAFpsqtWeBNIBgSSi2_19rltEHOF0mrvTg0")