Як і для чого я створив телеграм-бот Corona.Travel.Bot
Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.
Привіт! Мене звати Даніїл. В
Я розробив телеграм бот, який моніторить правила відвідування країн світу та сповіщає користувачів про зміни: Corona.Travel.Bot
Навіщо
Ситуація в світі швидко змінюється, а разом з нею і правила подорожування за кордон! Тому, коли плануєш поїздку, дуже важливо слідкувати за змінами. Самотужки це робити незручно: потрібно регулярно ходити на якісь ресурси і перевіряти чи не змінилося нічого 😩
Як працює бот
- Ти підписуєшся на країни, які тебе цікавлять.
- Коли в їх правилах щось зміниться, бот миттєво про це повідомляє!
Сповіщення про зміну правил в’їзду до Марокко:
Як з’явилася ідея
Придумав я цю ідею, коли планував свою першу подорож за кордон після початку всесвітньої епідемії Covid19. Це було в кінці
Я зіткнувся з тим, що нічого не знаю про правила подорожей в таких умовах. Почав шукати інформацію і наткнувся на офіційний ресурс: інтерактивна карта від Міністерства закордонних справ України (МЗС), на якій можна знайти актуальні правила в’їзду в інші країни світу і транзиту через них.
Я прочитав правила в’їзду в цікаву для мене країну і переконався, що потрапити туди на даний момент можливо. Але авіаквитки купуються зазвичай задовго до подорожі, тому я задався питанням: а чи можу я бути впевнений, що за цей час правила не зміняться? Адже ситуація в світі дуже стрімко змінюється.
Почав шукати на карті кнопку «підписатися на зміни», але такої не знайшов... Ось в цей момент я і зрозумів, що зроблю бот!
Перша спроба співпраці з МЗС
Коли я виявив такий недолік в інтерактивній карті, то одразу ж написав в тех. підтримку цього проєкту: «у вас крутий проєкт, але я знаю як його сильно покращити!» і запропонував свою допомогу.
Але як я й очікував, ніхто зі мною не зв’язався...
Прототип бота
Бота написав на Python. Використав обгортку для Telegram API «pyTelegramBotAPI».
Для того, щоб бот отримував дані від Telegram API є два основних метода:
- Pooling — ви регулярно опитуєте API і перевіряєте чи не з’явилась там нова інформація.
- Webhooks — ви надаєте API свою URL-адресу і «просите» повідомити вас про нові події.
Хоча опитування та веб-хуки виконують однакові завдання, веб-хуки набагато ефективніші. На відміну від пулінгу, веб-хуки передають дані лише тоді, коли з’являються нові події.
Саме тому я вибрав
Для отримання даних з інтерактивної карти я використав наступні бібліотеки:
- requests — для виконання HTTP запитів
- beautifulsoup4 — для скрапінгу інформації зі сторінки, отриманої за допомогою requests
- re — для скрапінгу того, що не вийшло дістати за допомогою beautifulsoup4
Розгорнув це все безкоштовно на Heroku і почав розповідати про цей сервіс друзям і родичам :)
Головний недолік першої версії бота
Інтерактивна карта МЗС — динамічний сайт, тому отримати всі необхідні дані з неї неможливо, якщо використовувати інструменти для парсинга статичних веб-сайтів: requests, BeautifulSoup4.
Я міг дістати дату останнього оновлення правил, але не міг дізнатися в якій умовній зоні знаходиться країна (зелена/червона/помаранчева). Саме тому перша версія мого сервісу мала серйозний недолік: бот надсилав повідомлення кожного разу, коли відбувалося будь-яке оновлення в правилах по країні.
Користувачі отримували сповіщення занадто часто і було не зрозуміло що саме там змінилося: могло щось істотне, а могли просто кому додати. Також було не зрозуміло в якій категорії відбулися зміни (режим в’їзду чи режим транзиту).
Повідомлення про зміни правил:
Користувачі хотіли отримувати сповіщення лише коли країна переходить з однієї зони в іншу. Наприклад, людина мріє поїхати в Італію, але вона закрита. Вона хоче дізнатися, коли Італія відкриється! Це все що її цікавить.
Для реалізації такої фічі було 2 основні варіанти:
- розбиратися з парсингом динамічних сайтів
- все ж таки зв’язатися з МЗС
Ще одна спроба співпраці з МЗС
Другий варіант мені більше сподобався, хоч я і не вірив в те, що вони будуть щось робити заради мого бота.. Але все одно про всяк випадок написав міністру в фейсбуці, скинув лінк на прототип бота і почав потихеньку розбиратися з інструментами для парсинга динамічних сайтів.
Але хто б міг подумати, через деякий час зі мною зв’язався глава відділу діджиталізації МЗС і запропонував поспілкуватися за чашкою кави. І вже через
В другій спробі співпрацювати з МЗС вирішальну роль зіграв прототип. Коли я писав про якусь абстрактну допомогу, це було нецікаво і незрозуміло. А от коли вже було що поклацати, то це інша справа!
Система пошуку країн
В результаті співпраці з МЗС було зроблено дві основні фічі:
- повідомлення приходять тільки після зміни умовної зони
- є можливість підписатися окремо на категорію в’їзду і на категорію транзиту або ж на дві відразу
Крім цього, в МЗС мені порадили переробити систему пошуку країн. В першій версії пошук був по першій літері. Він був простий в реалізації, але не 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_channel
Мій телеграм: t.me/danii_iil
15 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів