Як і для чого я створив телеграм-бот Corona.Travel.Bot

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Привіт! Мене звати Даніїл. В 2020-му році закінчив КПІ, ІПСА. Зараз працюю Python Backend девелопером в українській FinTech компанії «SmartTeam».

Я розробив телеграм бот, який моніторить правила відвідування країн світу та сповіщає користувачів про зміни: Corona.Travel.Bot

Навіщо

Ситуація в світі швидко змінюється, а разом з нею і правила подорожування за кордон! Тому, коли плануєш поїздку, дуже важливо слідкувати за змінами. Самотужки це робити незручно: потрібно регулярно ходити на якісь ресурси і перевіряти чи не змінилося нічого 😩

Як працює бот

  • Ти підписуєшся на країни, які тебе цікавлять.
  • Коли в їх правилах щось зміниться, бот миттєво про це повідомляє!

Сповіщення про зміну правил в’їзду до Марокко:

Як з’явилася ідея

Придумав я цю ідею, коли планував свою першу подорож за кордон після початку всесвітньої епідемії Covid19. Це було в кінці 2020-го року.

Я зіткнувся з тим, що нічого не знаю про правила подорожей в таких умовах. Почав шукати інформацію і наткнувся на офіційний ресурс: інтерактивна карта від Міністерства закордонних справ України (МЗС), на якій можна знайти актуальні правила в’їзду в інші країни світу і транзиту через них.

Я прочитав правила в’їзду в цікаву для мене країну і переконався, що потрапити туди на даний момент можливо. Але авіаквитки купуються зазвичай задовго до подорожі, тому я задався питанням: а чи можу я бути впевнений, що за цей час правила не зміняться? Адже ситуація в світі дуже стрімко змінюється.

Почав шукати на карті кнопку «підписатися на зміни», але такої не знайшов... Ось в цей момент я і зрозумів, що зроблю бот!

Перша спроба співпраці з МЗС

Коли я виявив такий недолік в інтерактивній карті, то одразу ж написав в тех. підтримку цього проєкту: «у вас крутий проєкт, але я знаю як його сильно покращити!» і запропонував свою допомогу.

Але як я й очікував, ніхто зі мною не зв’язався...

Прототип бота

Бота написав на Python. Використав обгортку для Telegram API «pyTelegramBotAPI».

Для того, щоб бот отримував дані від Telegram API є два основних метода:

  1. Pooling — ви регулярно опитуєте API і перевіряєте чи не з’явилась там нова інформація.
  2. Webhooks — ви надаєте API свою URL-адресу і «просите» повідомити вас про нові події.

Хоча опитування та веб-хуки виконують однакові завдання, веб-хуки набагато ефективніші. На відміну від пулінгу, веб-хуки передають дані лише тоді, коли з’являються нові події.

Саме тому я вибрав 2-й метод і реалізував його за допомогою фреймворку Flask за цим прикладом.

Для отримання даних з інтерактивної карти я використав наступні бібліотеки:

  • requests — для виконання HTTP запитів
  • beautifulsoup4 — для скрапінгу інформації зі сторінки, отриманої за допомогою requests
  • re — для скрапінгу того, що не вийшло дістати за допомогою beautifulsoup4

Розгорнув це все безкоштовно на Heroku і почав розповідати про цей сервіс друзям і родичам :)

Головний недолік першої версії бота

Інтерактивна карта МЗС — динамічний сайт, тому отримати всі необхідні дані з неї неможливо, якщо використовувати інструменти для парсинга статичних веб-сайтів: requests, BeautifulSoup4.

Я міг дістати дату останнього оновлення правил, але не міг дізнатися в якій умовній зоні знаходиться країна (зелена/червона/помаранчева). Саме тому перша версія мого сервісу мала серйозний недолік: бот надсилав повідомлення кожного разу, коли відбувалося будь-яке оновлення в правилах по країні.

Користувачі отримували сповіщення занадто часто і було не зрозуміло що саме там змінилося: могло щось істотне, а могли просто кому додати. Також було не зрозуміло в якій категорії відбулися зміни (режим в’їзду чи режим транзиту).

Повідомлення про зміни правил:

Користувачі хотіли отримувати сповіщення лише коли країна переходить з однієї зони в іншу. Наприклад, людина мріє поїхати в Італію, але вона закрита. Вона хоче дізнатися, коли Італія відкриється! Це все що її цікавить.

Для реалізації такої фічі було 2 основні варіанти:

  1. розбиратися з парсингом динамічних сайтів
  2. все ж таки зв’язатися з МЗС

Ще одна спроба співпраці з МЗС

Другий варіант мені більше сподобався, хоч я і не вірив в те, що вони будуть щось робити заради мого бота.. Але все одно про всяк випадок написав міністру в фейсбуці, скинув лінк на прототип бота і почав потихеньку розбиратися з інструментами для парсинга динамічних сайтів.

Але хто б міг подумати, через деякий час зі мною зв’язався глава відділу діджиталізації МЗС і запропонував поспілкуватися за чашкою кави. І вже через 2-3 дні після мого візиту до них, вони зробили для мене ендпойнт з необхідними даними!

В другій спробі співпрацювати з МЗС вирішальну роль зіграв прототип. Коли я писав про якусь абстрактну допомогу, це було нецікаво і незрозуміло. А от коли вже було що поклацати, то це інша справа!

Система пошуку країн

В результаті співпраці з МЗС було зроблено дві основні фічі:

  • повідомлення приходять тільки після зміни умовної зони
  • є можливість підписатися окремо на категорію в’їзду і на категорію транзиту або ж на дві відразу

Крім цього, в МЗС мені порадили переробити систему пошуку країн. В першій версії пошук був по першій літері. Він був простий в реалізації, але не user-friendly: потрібно було спочатку вибрати літеру, а потім вибрати потрібну країну зі списку назв країн, які починаються на цю літеру.

Мені здавалось, що зробити user-friendly пошук через введення назви країни повідомленням — це занадто складно. Це ж не просто виконати «SELECT * from countries WHERE name = ‘Іспанія’». Потрібно врахувати, що користувач може трохи помилитися, або навіть не трохи :)

Тому стояла задача зробити «розумний» пошук. Дуже популярним рішенням є Elasticsearch — механізм повнотекстового пошуку та аналітики з відкритим кодом. Але я вирішив, що це overkill для мого проєкту. Замість цього я взяв дуже просту у використанні бібліотеку FuzzyWuzzy, яка дозволяє робити нечіткий пошук рядків.

Дана бібліотека використовує відстань Левенштейна — мінімальна кількість операцій вставки, видалення і заміни, необхідних для перетворення однієї послідовності в іншу.

from fuzzywuzzy import fuzz

# Найпростіше порівняння:
>>> fuzz.ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    91
# Даний вид порівняння у другому рядку шукає збіг з початковою:
>>> fuzz.partial_ratio("this is a test", "this is a test!")
    100  # перший рядок - підмножина другого рядка

З таким інструментом я зміг написати дуже просту логіку пошуку країн:

from fuzzywuzzy import process  # Для порівняння рядка із списком рядків використовується модуль process
def find_country_id(search_txt, name_list, country_dict):
   """
   :param (str) search_txt: запит користувача
   :param (list) name_list: список назв країн із бази даних
   :param (dict) country_dict: словник із інформацією про кожну країну
   :return: (int) ID знайденої країни / (list) список ID знайдених країн
           якщо це int, то перенаправляємо юзера одразу на сторінку країни;
           якщо list - видаємо список із однієї/двох країн та кнопку "Бажаної країни нема"
   """
   scores = process.extract(search_txt, name_list, limit=2)  # вибираємо дві більш схожі на запит країни
   # scores має вигляд: [('Австралія', 95), ('Австрія', 70)]
   first_score = scores[0][1]  # перша «оцінка схожості»
   second_score = scores[1][1]  # друга «оцінка схожості»
   # first_score >= second_score
   if first_score == 100:  # користувач точно шукає саме цю країну
       country_id = country_dict[scores[0][0]]
   elif first_score >= 90 and second_score < 80:  # користувач ймовірно допустив незначну помилку в назві
       country_id = country_dict[scores[0][0]]
   elif first_score < 90 and second_score < 80:  # користувач ймовірно сильно помилився
       country_id = [country_dict[scores[0][0]]]  # повертаємо як список, тому що ми не впевнені, що це потрібна країна
   else:  # або такої країни немає, або є дві дуже схожі країни
       country_id = [country_dict[score[0]] for score in scores]
   return country_id

Одразу відкрилась сторінка країни, не зважаючи на помилку, тому що помилка незначна і більше немає інших схожих назв.

Дві дуже схожі назви:

Крім цього, країни можуть мати декілька назв: США, Америка, Сполучені штати або Англія, Британія, Велика Британія і тд.

Як буду покращувати сервіс

Насамперед знову зроблю можливість підписки на всі зміни, а не тільки на зміну умовної зони. Але! Так як у мене тепер є в базі даних всі тексти з інтерактивної карти, я можу надсилати звіт про те, що конкретно змінилося. Таким чином користувачеві не потрібно буде перечитувати всі правила від початку до кінця і намагатися знайти що ж там змінилося. Буде зрозуміло показано: що прибрали з попередньої версії правил, а що додали.

Також буду дуже радий обговорити ваші ідеї та пропозиції щодо покращення!

Бот: t.me/corona_travel_bot

Телеграм канал: t.me/corona_travel_channel

Мій телеграм: t.me/danii_iil

👍НравитсяПонравилось14
В избранноеВ избранном4
LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Расширение для трактористов в АУ

def can_travel_to(county_id):
.......return False;

Хороша ідея, але наприклад зміни від 01.07 по Болгарії по факту не приїхали.

Хороша ідея, але по факту зміни по Болгарії від 01.07 не приїхали.

В боте обновление и теперь есть два вида подписки: изменение зоны и просто любое изменение правил.

Старые подписки все отнесены к изменениям зоны.

Чтобы подписаться на изменение правил надо сделать это отдельно. Тогда уведомление придет прилюбом изменении в правил. Я тоже не получил уведомлений по Эстонии из-за этого. Учитывая что бот в активной разработке — приемлемо.

Хочу ещё сказать что лимиты на количество free подписок по изменению зоны и изменению правил разные и не связаны друг с другом. На изменение зоны как и раньше можно подписаться на 5 стран, на изменение правил на одну.

Тот не частый случай когда я бы заплатил за подписку хотя мне и бесплатного лимита хватает. Конечно если подписка не будет $9,99 в месяц.

Виталий, спасибо за такой крутой отзыв :) Я установил лимиты из-за ограничений бесплатного сервера. Но сейчас уже перевёл на платный тариф. Поэтому скоро добавлю возможность заплатить небольшую сумму прямо через бота и увеличить количество возможных подписок

Чудова Ініціатива! дякую =)

Дуже радий, що сподобалось)

Крутий бот, вже знайомий з ним, було цікаво почитати про технічний бік, дякую!

Супер! Дуже приємно )

Корисний бот, встановила собі. Дякую, що він українською :)

Інші варіанти навіть не розглядав, тому що бот поки що саме для українців )) приємного користування!

Встановила собі. Актуально. Дякую.

Приємного користування :)

Подписаться на комментарии