import os import sys import tarfile import time from dataclasses import dataclass from pathlib import Path import wget from loguru import logger from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.firefox import options from selenium.webdriver.firefox.service import Service from selenium.webdriver.firefox.webdriver import WebDriver from aiogram import Bot, types from aiogram.contrib.middlewares.logging import LoggingMiddleware from aiogram.dispatcher import Dispatcher from aiogram.dispatcher.webhook import SendMessage from aiogram.utils.executor import start_webhook logger.remove() logger.add(sink=sys.stdout, colorize=True, level='DEBUG', format="{time:DD.MM.YYYY HH:mm:ss} | {level} | " "{message}") GECKO_DRIVER_VERSION = '0.31.0' BASE_DIR = Path(__file__).parent.resolve().as_posix() API_TOKEN = os.environ.get('API_TOKEN') # webhook settings WEBHOOK_HOST = 'https://bot.mywistr.com' WEBHOOK_PATH = '/transport' WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}" # webserver settings WEBAPP_HOST = 'test-server.lan' # or ip WEBAPP_PORT = 8084 bot = Bot(token=API_TOKEN) dp = Dispatcher(bot) dp.middleware.setup(LoggingMiddleware()) @dataclass class Description: id: int description: str def download_gecko_driver(): gecko_driver = f'https://github.com/mozilla/geckodriver/releases/download/v{GECKO_DRIVER_VERSION}/' \ f'geckodriver-v{GECKO_DRIVER_VERSION}-linux64.tar.gz' if not Path(f'{BASE_DIR}/geckodriver').exists(): logger.info(f'Downloading gecodriver v {GECKO_DRIVER_VERSION}...') geckodriver_file = wget.download(url=gecko_driver, out=BASE_DIR) with tarfile.open(geckodriver_file) as tar: tar.extractall(BASE_DIR) os.remove(f'{BASE_DIR}/geckodriver-v{GECKO_DRIVER_VERSION}-linux64.tar.gz') logger.info(f'\ngeckodriver has been downloaded to folder {BASE_DIR}') def configure_firefox_driver(private_window: bool = False) -> WebDriver: opt = options.Options() opt.headless = True opt.add_argument('-profile') opt.add_argument(f'{Path.home()}/snap/firefox/common/.mozilla/firefox') if private_window: opt.set_preference("browser.privatebrowsing.autostart", True) service = Service(executable_path=f'{BASE_DIR}/geckodriver') firefox_driver = webdriver.Firefox(service=service, options=opt) return firefox_driver def parse_site() -> str: download_gecko_driver() driver = configure_firefox_driver() driver.get( 'https://yandex.ru/maps/213/moscow/stops/stop__9640740/?l=masstransit&ll=37.527754%2C55.823507&tab=overview&z=21' ) time.sleep(4) elements = driver.find_elements(by='class name', value='masstransit-vehicle-snippet-view') bus_300, bus_t19 = None, None bus_300_arrival, bus_t19_arrival = None, None for element in elements: try: bus_300 = element.find_element(by='css selector', value='[aria-label="300"]') bus_300_arrival = element.find_element(by='class name', value='masstransit-prognoses-view__title-text') except NoSuchElementException: pass try: bus_t19 = element.find_element(by='css selector', value='[aria-label="т19"]') bus_t19_arrival = element.find_element(by='class name', value='masstransit-prognoses-view__title-text') except NoSuchElementException: pass return f'{bus_300.text} - {bus_300_arrival.text}\n{bus_t19.text} - {bus_t19_arrival.text}' @dp.message_handler() async def echo(message: types.Message): # Regular request # await bot.send_message(message.chat.id, message.text) text = parse_site() # or reply INTO webhook return SendMessage(message.chat.id, text) async def on_startup(dp): await bot.set_webhook(WEBHOOK_URL) # insert code here to run it after start async def on_shutdown(dp): logger.warning('Shutting down..') # insert code here to run it before shutdown # Remove webhook (not acceptable in some cases) await bot.delete_webhook() # Close DB connection (if used) await dp.storage.close() await dp.storage.wait_closed() logger.warning('Bye!') if __name__ == '__main__': start_webhook( dispatcher=dp, webhook_path=WEBHOOK_PATH, on_startup=on_startup, on_shutdown=on_shutdown, skip_updates=True, host=WEBAPP_HOST, port=WEBAPP_PORT, )