В посте я поделюсь своим опытом разработки телеграм-бота для большого количества пользователей: разберу свои ошибки и шаги для их решения.
Одной из моих рабочих задач как программиста была автоматизация проведения викторины. Конечно, уже существуют специализированные бесплатные приложения, заточенные под эти задачи, но нужно было такое, в котором не было бы ничего лишнего, оно было всегда под рукой и такое привычное, чтобы не нужно было с ним разбираться. Выбор пал на телеграм бота и для того, чтобы он справлялся с большей нагрузкой. Было принято решение использовать асинхронную библиотеку aiogram.
Начнём с создания эхо бота на aiogram, тут нет ничего сложного, возьмём пример из документации:
Однако преимущество aiogram над python-telegram-bot и pyTelegramBotAPI в том, что он асинхронный, а значит может обрабатывать несколько запросов почти единовременно. Стандартная база данных sqlite отлично подходит для несложных проектов и уже входит в стандартную библиотеку питона, поэтому для начала я решил использовать её.
How to Send TradingView Alerts to Telegram Channel — Webhook
Через несколько часов работы приложение было написано, и мы с коллегами решили протестировать на себе его работоспособность. Бот запускался с использование технологии long polling, и запускался на локальном компьютере. Для небольшого количества человек этого вполне достаточно: 3-4 человека в секунду бот выдерживает без особых проблем.
Но, к сожалению или к счастью, во время проведения викторины боту посыпалось бОльшее количество запросов, на которое мы не рассчитывали, в связи с чем посыпались ошибки — необрабатываемые ошибки, связанные с одновременным постоянным запросом новых сообщений у сервера и обработкой уже полученных.
Решением этой проблемы стал переход на вебхуки. Для обеспечения бесперебойной работы разместим его на удалённом сервере. Отличным решением для этого является heroku: здесь можно управлять запуском приложения как с компьютера, так и с мобильного приложения, отслеживать логи и, что является наиболее важным для нас, настраивать вебхуки.
Алгоритм, для реализации эхо бота в данном случае занимает больше времени, но он достаточно прост:
2) Создаём новое приложение на странице Personal
Выбираем имя нашего приложения (у меня это «aiogram-echo-bot-webhook» — запомним его, оно нам ещё понадобится!), меняем сервер на Europe и нажимаем кнопку «create app».
Отлично, мы подготовили контейнер для нашего приложения! Передать туда код самого приложения можно несколькими способами, например через Heroku CLI или через GitHub. Разберём деплой через гитхаб, так как при любой возможности лучше использовать контроль версий
Перед деплоем на Heroku хорошо бы переписать наше приложение на вебхуки:
Что здесь происходит?
TradingView Alerts WebHook + Python = Telegram | with Yandex Cloud Functions and Telegram Bot API
TOKEN, HEROKU_APP_NAME – мы считываем из переменных окружения, которые скоро добавим в наш проект.
WEBHOOK_HOST – доменное имя нашего приложения
WEBHOOK_PATH – часть пути, на который мы будем принимать запросы. Его следует придумать таким, чтобы не было возможности его угадать, во избежание фальсификации запросов. В нашем случае используется токен бота, так как его, также, следует держать в секрете.
WEBHOOK_URL – полный url адрес, на который будут принимать запросы.
WEBAPP_HOST – хост нашего приложения, оставляем локальный.
WEBAPP_PORT – порт, на котором работает наше приложение, так же считывается с переменных окружения, которое предоставляет Heroku.. Его мы не заполняем.
Асинхронная функция on_startup устанавливает вебхук для нашего телеграм бота, на который будут отсылаться уведомления о получении новых сообщений. И on_shutdown, наоборот, удаляет этот вебхук при выключении.
Далее мы переключаем вывод логов только на вывод только чисто информативной информации. И запускаем наш диспетчер, при этом при запуске опускаются все сообщения, которые были получены в то время, когда бот не работал, что указано в параметре «skip_updates».
Почти всё готово, но чтобы дать инструкции Heroku, как именно развернуть наше приложение, нужно создать файл «Procfile» и вставить туда следующий код:
web: python main.py
Здесь: web – значит, что наше приложение будет web приложением, а то, что идёт после «:» это строка, которую необходимо выполнить в первую очередь. Запустить наш файл main.py с помощью питона.
И ещё один файл, который необходим для запуска, это requirements.txt, в котором мы указываем все зависимости нашего проекта. Его создаём, выполнив команду pip freeze > requirements.txt .
Также можно указать, какую конкретную версию питона использовать: для этого создадим файл «runtime.txt» и впишем туда версию питона по шаблону «python-3.9.7»
Теперь подготовим переменные среды на Heroku: для этого переходим на вкладку «Settings» и жмём кнопку «Reveal Config Vars»
Здесь добавляем два поля:
BOT_TOKEN – токен, полученный у BotFather
HEROKU_APP_NAME – имя приложения созданного на heroku, которое мы с вами запоминали.
Отлично! Перейдём обратно к деплою: создадим репозиторий на гитхаб и зальём туда все файлы. На странице с нашим приложением в Heroku переходим во вкладку «Deploy». Кликаем на вкладку «Github». После того, как вошли в свой аккаунт гитхаб заполняем имя репозитория.
Помним, что репозиторий должен быть не пустым!
Кликаем на кнопку «connect».
Для того, чтобы наше приложение обновлялось каждый раз, как мы заливаем новые изменения в ветку «master», можем нажать кнопку «Enable Automatic Deploys»
В первый раз, всё-таки придётся деплоить самим, для этого нажимаем кнопку ниже:
И дожидаемся окончания деплоя. При положительном результате, вывод будет, примерно таким:
Также можно посмотреть логи вверху окна кнопка «More»->«View logs»:
Переходим в наш бот и отправляем ему пару сообщений, если бот отвечает, значит всё в порядке, если нет, то переходим в логи и смотрим, в чём может быть ошибка.
На этом можно было бы остановиться, эхо-бот готов, но в реальном проекте нам понадобится сохранять различные данные из приложения. Для этого нужна база данных, как и в прошлый раз мы можем воспользоваться стандартной sqlite, но так как мы используем асинхронную библиотеку, то и запросы в бд должны быть асинхронными. Поэтому устанавливаем библиотеку databases для sqlite: pip install databases[sqlite] .
Разобьём код по модулям и подключимся к базе данных: создаём файл config.py и выносим туда все переменные (WEBHOOK_HOST, WEBHOOK_PATH и т.д.).
И ещё один модуль «db.py», в котором пишем следующий код:
from databases import Database database = Database(‘sqlite:///bot.db’) # где bot.db – путь к файлу базы данных
CREATE TABLE messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, telegram_id INTEGER NOT NULL, text text NOT NULL );
И дополняем модуль main.py:
Здесь мы после получения сообщения сохраняем его в базу данных, и затем просто возвращаем все сообщения, полученные от этого пользователя.
Не забываем обновить requirements.txt
Пушим всё на гитхаб, процесс сборки можно посмотреть на вкладке «Activity»
Проверяем в боте: отправляем пару сообщений, бот возвращает нам список сохранённых в базу.
Казалось бы, всё хорошо, но вдруг произошла непредвиденная ошибка и приложение необходимо перезапустить: зайдём на вкладку «Resources»
Нажимаем на карандаш, жмём переключатель, для выключения приложения и подтверждаем «confirm».
Вновь включаем таким же способом и пробуем отправить боту сообщения:
Ужас, мы потеряли все данные! Но почему, ведь они хранятся в базе данных? Это происходит потому, что деплой происходит в изолированных контейнерах и при каждом новом запуске создаётся новый контейнер, а как мы помним исходный файл с бд у нас был пустым.
В нашем случае данные нужны будут и после выключения, поэтому нам нужна изолированная от приложения база данных. К счастью на Heroku, помимо множества приложений, можно бесплатно развернуть и базу данных, например postgres.
Переходим в «elements»
Выбираем «Heroku Postgres»
Выбираем бесплатный план и вводим имя приложения, для которого подключаем бд, для того чтобы потом мы могли считывать строку подключения с переменных среды:
Переходим в переменные среды нашего приложения и видим, что там появился ключ «DATABASE_URL», который мы и будем использовать для подключения.
Для подключения к бд postgresql, установим пакет databases[postgresql]: pip install databases[postgresql] . Создаём исходные таблицы, но синтаксис создания таблицы немного поменяется:
CREATE TABLE messages ( id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL, text text NOT NULL );
Также следует немного изменить метод «read» следующим образом:
async def read(user_id): results = await database.fetch_all(‘SELECT text ‘ ‘FROM messages ‘ ‘WHERE telegram_id = :telegram_id ‘, values=) return [next(result.values()) for result in results]
Вновь обновляем requirements.txt и пушим на гит.
Дожидаемся окончания деплоя, если приложение не запущено, то запускаем его и отправляем проверочные сообщения боту:
Получаем сообщения, всё отлично! Как и в прошлый раз возникает непредвиденная ситуация, из-за которой приходится перезапускать приложение. Перезапускаем, отправляем ещё одно сообщение и …
Видим, что все данные сохранились в бд!
Вот всё и готово! А дальше всё зависит только от ваших предпочтений: для чего и под какие задачи разработать функционал бота, но вы можете быть уверенны, что его производительность будет на высоте, а данные надёжно сохранены.
Исходный код приложения размещён в репозитории: ссылка.
Источник: newtechaudit.ru
Telegram Webhook
Telegram Webhook – это технология, позволяющая отслеживать в чате события в реальном времени и отправлять информацию о нем на указанный адрес. Если вы создали бот, то метод необходим, чтобы система могла реагировать на сообщения и действия пользователей. Получая информацию о них, сервер отправляет ее программе бота, в алгоритм которой заложена обработка.
Что нужно для рабочего коннекта Webhook
- Адрес (URL) страницы с программным кодом;
- Поддержка IPv4, но рекомендуем поддержка IPv6 из-за частой блокировки телеграмма по IPv4;
- Возможность сервера обрабатывать HTTPS трафик;
- Наличие SSL сертификата.
Команды работы с методом описаны в Telegram Webhook Bot API. К ним относятся:
- setWebhook – установка соединения . При этом необходимо передать адрес, на который будут отправляться сообщения из чата;
- deleteWebhook – удаление соединения . Указание предыдущей команды без параметров также удалит его;
- getWebhookInfo – получение текущего статуса соединения.
Активация Webhook Telegram
Чтобы использовать метод постоянного коннекта сервера и бота, следует запустить программный код, в котором выполняется команда API для Телеграм.
Для официального сертификата SSL :
https://api.telegram.org/botТОКЕН/setWebhook?url=ВАША_ССЫЛКА
Для самоподписанного сертификата :
https://api.telegram.org/botТОКЕН/setWebhook?url=ВАША_ССЫЛКАhttps://telegramzy.ru/webhook/» target=»_blank»]telegramzy.ru[/mask_link]
Telegram-бот без сторонних библиотек
Практически все примеры в гугле которые я встречал разбираясь с API телеграмма, работают с какой-то библиотекой. Для совсем простых задач они вовсе не обязательны.
После статьи про бота в вк у меня спрашивали так же про ботов в телеграмме. Расскажу про максимально простой пример создания ботов в телеграмме. Даже не то что создания ботов, а скорее того, как именно работать с апи телеграмма в целом. Делать мы будем абсолютно то же самое, что и в той статье про каллбек апи от вк.
Сделаем то же самое — ответ на сообщения просто задом-наперёд.
Для начала нужно создать бота. Чтобы сделать это, нужно написать отцу ботов в телеграмме команду /newbot
После чего он спросит имя бота и его логин, который обязательно должен кончаться на bot.
Например: evilbot, coder_bot, samplebot и т.д.
Следом вы получите ссылку на своего бота и токен. Боту можете написать даже сейчас, но он ничего Вам не ответит.
Непорядок! Давайте исправим это.
Нам нужно создать файлы webhook.php и tg.class.php.
Ниже будут приведён полный код этих файлов с комментариями
$body = file_get_contents(‘php://input’); //Получаем в $body json строку $arr = json_decode($body, true); //Разбираем json запрос на массив в переменную $arr function cir_strrev($stroka) < //Так как функция strrev не умеет нормально переворачивать кириллицу, нужен костыль через массив. Создадим функцию preg_match_all(‘/./us’, $stroka, $array); return implode(»,array_reverse($array[0])); >include_once (‘tg.class.php’); //Меж дела подключаем наш tg.class.php //Сразу и создадим этот класс, который будет написан чуть позже //Сюда пишем токен, который нам выдал бот $tg = new tg(‘000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA’); $sms = $arr[‘message’][‘text’]; //Получаем текст сообщения, которое нам пришло. //О структуре этого массива который прилетел нам от телеграмма можно узнать из официальной документации. //Сразу и id получим, которому нужно отправлять всё это назад $tg_id = $arr[‘message’][‘chat’][‘id’]; //Перевернём строку задом-наперёд используя функцию cir_strrev $sms_rev = cir_strrev($sms); //Используем наш ещё не написанный класс, для отправки сообщения в ответ $tg->send($tg_id, $sms_rev); exit(‘ok’); //Обязательно возвращаем «ok», чтобы телеграмм не подумал, что запрос не дошёл
tg.class.php:
token = $token; //Забиваем в переменную токен при конструкте класса > public function send($id, $message) < //Задаём публичную функцию send для отправки сообщений //Заполняем массив $data инфой, которую мы через api отправим до телеграмма $data = array( ‘chat_id’ =>$id, ‘text’ => $message, ); //Получаем ответ через функцию отправки до апи, которую создадим ниже $out = $this->request(‘sendMessage’, $data); //И пусть функция вернёт ответ. Правда в данном примере мы это никак не будем использовать, пусть будет задаток на будущее return $out; > public function request($method, $data = array()) < $curl = curl_init(); //мутим курл-мурл в переменную. Для отправки предпочтительнее использовать курл, но можно и через file_get_contents если сервер не поддерживает curl_setopt($curl, CURLOPT_URL, ‘https://api.telegram.org/bot’ . $this->token . ‘/’ . $method); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, ‘POST’); //Отправляем через POST curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); //Сами данные отправляемые $out = json_decode(curl_exec($curl), true); //Получаем результат выполнения, который сразу расшифровываем из JSON’a в массив для удобства curl_close($curl); //Закрываем курл return $out; //Отправляем ответ в виде массива > >
Всё! Всё что осталось — это указать в настройках бота ссылку на наш webhook.php, на который будут приходить уведомления от телеграмма. Для этого нужно перейти по ссылке:
Источник: evilcoder.ru