Как пропускать и одновременно присутствовать на лекции или «за меня учится Python бот»

от автора

Немного вводной

Я имею самый обычный рабочий график: 5/2, 8ч/день. В настоящий момент удаленно учусь в аспирантуре (коронавирус, все дела) и единственный день, когда я могу вдоволь почувствовать себя человеком-соседом и поделать что-то по дому, – это суббота. Как вы понимаете, здесь что-то пошло не так и вместо обещанных будничных пар, которые должны были проходить по вечерам после работы, нам утрамбовали всю субботу. Но дела ведь себя не переделают, поэтому решено было написать на python простого бота-кликера, который мог бы:

  • Заходить на пару по скормленной извне ссылки;

  • Стартовать запись экрана со звуком;

  • Ожидать окончания пары;

  • Выключать запись и выходить с пары.

Таким образом я и на паре присутствую, и домашними делами занимаюсь. А еще могу просмотреть лекции с удвоенным ускорением и в любое удобное для меня время. Придумано – сделано. Может быть мой опыт поможет кому-то решить аналогичную «проблему».

В ВУЗе мы используем Microsoft Teams и для того, чтобы попасть на лекцию требуется перейти по ссылке, которую за несколько часов до старта этой самой лекции, высылает староста. На мой взгляд, самым простым решением является бот-кликер, наблюдающий за экраном и тыкающий по кнопкам. А также было бы неплохо стартовать все это удаленно и желательно с телефона.

Кликер

Начал я с питонячей библиотеки pyautogui. Если кратенько, она умеет перехватывать управление клавомышью, тыкать кнопки, вводить тексты, делать снимки экрана, искать окна приложений и взаимодействовать с ними и многое-многое другое. Для своего кликера я выстроил следующую логику: я заранее сохраняю картинку нужной кнопки, pyautogui ожидает ее появления на экране, когда он находит кнопку, то тыкает по ней.

Функция ожидания:

def find_element(element):     """Ожидание появления элемента на экране"""     sleep(1)     r = None     count = 100     while r is None:         count -= 1         r = pyautogui.locateOnScreen(dir_true_files + element, confidence=0.7)         print(count)         if count == 0:             print(element + ' не найден!')             break         else:             if r != None:                 print(element + ' нашОлся!')                 return r             else:                 continue

Здесь pyautogui ищет на экране в пределах счетчика «100» совпадений в 70% с заранее сохраненной картинкой.

Далее функции для взаимодействия с приложением и создание скриншота экрана:

def press_key(key):     """Нажатие одной клавиши"""     sleep(1)     pyautogui.press(key)   def write_text(text):     """Ввод текста"""     sleep(1)     pyautogui.write(text, interval=0.2)   def create_screenshot(screens_directory, name):     """Создание скриншота"""     sleep(1)     im1 = pyautogui.screenshot()     screenshot = im1.save(screens_directory + name)     return screenshot

Здесь можно расширить функционал бота, добавив возможность сравнивать время с временем системы, искать поле для ввода текста, делать его активным и вводить приветствие в зависимости от времени суток – с 09.00 до 12.00 «Доброе утро!», с 12.00 до 17.00 «Добрый день!», с 17.00 до 21.00 «Добрый вечер!». Можно сделать список, из которого раз в n минут бот будет забирать рандомное значение и передавать его функции, отправляющей текст – [‘Где экшон?’, ‘Лучше бы в армию пошел’, ‘Отличная мысль!’, ‘Я не расслышал, повторите’, ‘Хочу есть’] и т.д. Но нас на парах отмечали по факту присутствия и нахождению в онлайне – поэтому я не стал с этим заморачиваться.

Для записи экрана по работе я использую заранее настроенный OBS. Здесь его функциональности хватит с головой. Да, я знаю про ffmpeg, но подружиться с ним у меня так и не получилось. В итоге для старта записи я использую поиск окна по заголовку и выношу приложение «на передний план». Эти манипуляции нужны для того, чтобы, имея активное окно OBS, нажать через pyautogui хоткей для старта и окончания записи.

def active_window(title):     """Найти окно по заголовку и сделать его активным"""     sleep(1)     app = Application().connect(title_re=title, backend='win32')     app.window(title_re=title).set_focus()     sleep(3)

Кнопки сохранены, шаги в MS Teams боту прописаны, все отлажено. Как запускаться?

Чат бот

До этого я много игрался с чат-ботами, поэтому мой выбор пал именно на них. Самым простым решением имхо здесь является Телеграмм с его @BotFather. Создаем бота, используя telebot. Я захотел отрезать от него все, что можно и нельзя, оставив ему один единственный функционал – получать ссылку и заходит на пару.

А как скармливать ему ссылку и открывать ее в MS Teams? Тут я вспомнил про давно задвинутый в дальний ящик чудесный selenium. Расчехлил и инициализировал хромдрайвер с нажатием на кнопку «Open Microsoft Teams»:

def site_desktop(url):     chrome_options = webdriver.ChromeOptions()     driver = webdriver.Chrome(executable_path=driver_chrome, options=chrome_options)     driver.set_window_size(1920, 1080)     driver.get(url)     find_and_click('/open_team.png')     sleep(3)     driver.close()

Можно заморочиться с распознаванием сообщений в другом чате, откуда к нам поступаю ссылки на лекции, привязаться ко времени (первая пара в 9.00, вторая в 10.40 и т.д.) и в нужное время автоматом забрать сообщение, начинающееся с ‘https://’, но я предпочитаю контролировать этот процесс и копипастить ссылки лично.

В итоге, когда я отправляю боту url, он делает следующее:

  1. Открывает selenium chrome driver с присланной сслыкой;

  2. Кликает по кнопку «Открыть Microsoft Teams»;

  3. Открывает MS Teams, проверяет статус микрофона — включен/выключен. Если выключен, отключает;

  4. Подключается к паре;

  5. Делает активным окно OBS, нажимает хоткей для записи экрана, отправляет скриншот рабочего стола в Телеграмм;

  6. Ждет 90 минут;

  7. Отправляет сообщение в Телеграмм о том, что пара закончилась;

  8. Вновь делает активным окно OBS, выключает запись, кликает на кнопку для выхода с пары;

  9. Отправляет финальное сообщение о завершении цикла. Ждет новой ссылки.

bot = telebot.TeleBot(bot_token)   @bot.message_handler(content_types=['text']) def get_text_messages(message):     if message.text:         try:             bot.send_message(message.chat.id, text='Стартую вход на пару')             txt = message.text             site_desktop(txt)             find_and_click('/disable_micro.png')             if find_element('/micro_status_on.png'):                 find_and_click('/disable_micro.png')             find_and_click('/apply_study.png')             active_window('OBS')             press_key('f7')             sleep(3)              create_screenshot(dir_to_save_fail_screen, name_fail_screen)             bot.send_photo(message.chat.id, open(dir_to_save_fail_screen + name_fail_screen, 'rb'))             bot.send_message(message.chat.id, text='Зашел на пару, включил запись экрана')              # Длительность пары 90 мин == 5400             sleep(5400)              bot.send_message(message.chat.id, text='Пара подошла к концу, выключаю запись экрана, выхожу')             active_window('OBS')             press_key('f8')             sleep(3)              find_and_click('/exit.png')             bot.send_message(message.chat.id, text='Успешное завершение')         except Exception as e:             bot.send_message(message.chat.id, text='ОШИБКА + ' + str(e))   bot.polling()

Не очень хорошо, что 90 минут пары я обернул в простой time.sleep, но этого, как показала практика, более, чем достаточно. Также в OBS можно настроить запись видео только окна MS Teams в небольшом разрешении с фиксированной частотой кадров и пожатым звуком, дабы уменьшить итоговый размер видоса. И затем слать его себе в Телеграмм.

А вот так это выглядит для меня, который в этот момент вполне может ехать куда-нибудь за стройматериалами (ссылки замазюкал, время сократил):

З.Ы. Я ни в коем случае не призываю пропускать таким образом уроки/пары – ученье свет! Но, увы, отечественное образование частично состоит из архаичных лекций времен советского союза, выхлоп от которых… чуть больше, чем никакой. И такой робот позволит хотя бы частично разгрузиться и переключиться на что-то более полезное и продуктивное.

ссылка на оригинал статьи https://habr.com/ru/post/533640/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *