Как я писал telegram-бота и заливал его на удаленный сервер

Вступление


Как только на территории РФ вступил в силу запрет на анонимность в мессенджерах, у меня дошли руки написать пост про telegram-бота. По ходу создания бота столкнулся с большим количеством проблем, которые пришлось решать по отдельности, и буквально выцеживать крупинки информации со всего интернета. И вот после нескольких месяцев страданий и мучений (кодинг – не основное моё занятие) я наконец-то закончил с ботом, разобрался со всеми проблемами и готов поведать свою историю Вам.



Первые шаги


Для начала нужно установить telegram на ПК и зарегистрироваться в мессенджере. Найти в поиске @BotFather – это отец всех ботов в telegram, именно он их создаёт. Пишем ему /newbot и отвечаем на два простых вопросов: имя бота и его username. После чего @BotFather поздравит нас с успешным созданием бота и отправит нам его token — 523870826:AAF0O8T-e7riRi8m6qlRz4pBKKdh0OfHKj8.



Внимание: token – единственный идентификационный ключ к боту. Нигде не выкладывайте его, иначе другие люди смогут управлять Вашим ботом. Бот с данным token на момент выкладывания статьи удалён.

Какой язык программирования выбрать для написания бота?


Тут я долго не заморачивался и остановился на Python, так как знаю его достаточно хорошо, да и удобная библиотека тоже присутствует. Я решил использовать PyTelagramBotAPI (на момент написания этой статьи последняя доступная версия 3.5.1).

Перейдём к первому коду.

Импортируем библиотеку PyTelegramBotAPI.

# -*- coding: utf-8 -*-
import telebot

Создадим бота.

bot = telebot.TeleBot("523870826:AAF0O8T-e7riRi8m6qlRz4pBKKdh0OfHKj8")

Напишем простую обработку сообщений с помощью декоратора bot.message_handler.

@bot.message_handler(content_types=["text"])
def handle_text(message):
    if message.text == "Hi":
        bot.send_message(message.from_user.id, "Hello! I am HabrahabrExampleBot. How can i help you?")
    
    elif message.text == "How are you?" or message.text == "How are u?":
        bot.send_message(message.from_user.id, "I'm fine, thanks. And you?")
    
    else:
        bot.send_message(message.from_user.id, "Sorry, i dont understand you.")

Поставим бота в режим постоянной обработки информации, приходящей от серверов telegram.

bot.polling(none_stop=True, interval=0)

В переменной message telegram передаёт словарь (map) такого вида:

{'content_type': 'text', 
 'message_id': 1, 
 'from_user': {
     'id': None, 
     'is_bot': False, 
     'first_name': None, 
     'username': None, 
     'last_name': None, 
     'language_code': None}, 
 'date': None, 
 'chat': {
     'type': 'private', 
     'last_name': None, 
     'first_name': None, 
     'username': None, 
     'id': None, 
     'title': None, 
     'all_members_are_administrators': None, 
     'photo': None, 
     'description': None, 
     'invite_link': None, 
     'pinned_message': None, 
     'sticker_set_name': None, 
     'can_set_sticker_set': None}, 
 'forward_from_chat': None, 
 'forward_from': None, 
 'forward_date': None, 
 'reply_to_message': None, 
 'edit_date': None, 
 'author_signature': None, 
 'text': '/start', 
 'entities': '[<telebot.types.MessageEntity object at 0x037CB6B0>]', 
 'caption_entities': None, 
 'audio': None, 
 'document': None, 
 'photo': None, 
 'sticker': None, 
 'video': None, 
 'video_note': None, 
 'voice': None, 
 'caption': None, 
 'contact': None, 
 'location': None, 
 'venue': None, 
 'new_chat_member': None, 
 'new_chat_members': None, 
 'left_chat_member': None, 
 'new_chat_title': None, 
 'new_chat_photo': None, 
 'delete_chat_photo': None, 
 'group_chat_created': None, 
 'supergroup_chat_created': None, 
 'channel_chat_created': None, 
 'migrate_to_chat_id': None, 
 'migrate_from_chat_id': None, 
 'pinned_message': None, 
 'invoice': None, 
 'successful_payment': None}

Также существуют другие декораторы, которые могут принимать аудиофайлы, видео, картинки, документы, геолокацию и т.д.

# Обработчик команд '/start' и '/help'.
@bot.message_handler(commands=['start', 'help'])
def handle_start_help(message):
    pass

 # Обработчик для документов и аудиофайлов
@bot.message_handler(content_types=['document', 'audio'])
def handle_document_audio(message):
    pass

Конечный код.
# -*- coding: utf-8 -*-
import telebot


bot = telebot.TeleBot("523870826:AAF0O8T-e7riRi8m6qlRz4pBKKdh0OfHKj8")
@bot.message_handler(content_types=["text"])
def handle_text(message):
    if message.text == "Hi":
        bot.send_message(message.from_user.id, "Hello! I am HabrahabrExampleBot. How can i help you?")
    
    elif message.text == "How are you?" or message.text == "How are u?":
        bot.send_message(message.from_user.id, "I'm fine, thanks. And you?")
    
    else:
        bot.send_message(message.from_user.id, "Sorry, i dont understand you.")

bot.polling(none_stop=True, interval=0)

# Обработчик команд '/start' и '/help'.
@bot.message_handler(commands=['start', 'help'])
def handle_start_help(message):
    pass

 # Обработчик для документов и аудиофайлов
@bot.message_handler(content_types=['document', 'audio'])
def handle_document_audio(message):
    pass

bot.polling(none_stop=True, interval=0)




Вообще, telegram позволяет ботам производить очень много прикольных операций от создания пользовательских клавиатур до проведения платежей. Ссылка на официальную документацию Telegram.

Для сохранения данных о пользователях решил воспользоваться базой данных sqlite3.

import sqlite3


connection = sqlite3.connect("database", check_same_thread = True)
cursor = connection.cursor()

cursor.execute("CREATE TABLE IF NOT EXISTS Inventory_on (ID INT, 'Primary weapon' TEXT, 'Secondary weapon' TEXT)")
cursor.execute("CREATE TABLE IF NOT EXISTS Clans (Name TEXT, Points INT)")
cursor.execute("CREATE TABLE IF NOT EXISTS WorkStatus (ID INT, Status INT)")

connection.commit()
connection.close()

Параллельные процессы запускал с помощью библиотеки threading. Например: функция расчета битв.

import threading


threading.Thread(target=name_of_your_function).start()

Дальше всё зависит только от Вашей фантазии.

Где запустить Вашего бота?


Свой собственный ПК не хочется оставлять включенным 24/7, да и не практично это. Поэтому я решил воспользоваться бесплатным сервисом heroku, но меня постигла неудача из-за выбранной мною БД. Оказалось, что при каждом перезапуске бота, heroku удаляет все коммиты sqlite3 за последний сеанс без исключений. После чего, я решил купить VDS (Virtual Dedicated Server, виртуальный выделенный сервер) – удаленный ПК, на котором выделяется определенная мощность и память под Вас, и к командной строке которого Вам даётся доступ. Чаще всего операционной системой такой машинки будет linux. Плата небольшая – 400 руб./месяц, так что без особых моральных страданий оплатил VDS на основе Debian GNU/Linux и начал разбираться с тем, как мне включить бота на удалённом сервере.

Как же подключаться к VDS?


Есть разные методы, я решил по SSH-соединению через Putty. Скачиваем Putty через официальный сайт и открываем. Вводим IP-address VDS и нажимаем open.



Должно открыться такое окно, где нужно ввести логин и пароль от сервера.



Все вышеупомянутые данные выдаст компания, у которой Вы приобретёте VDS. Далее VDS – сервер.

Как установить на сервер все необходимые Вам языки программирования и библиотеки?


Тут все просто. Введя эти 5 команд в консоль сервера в данной последовательности, Вы установите на сервер python3, setuptools, pip3 и библиотеку pyTelegramBotAPI.

apt-get update
apt-get install python3
apt-get install python3-setuptools
apt-get install python3-pip
pip3 install pyTelegramBotAPI

Все дополнительные библиотеки, которые не входят в основной пакет python3, также необходимо установить по принципу.

pip3 install ‘name_of_site_package’

Как загрузить файлы с моего ПК на сервер?


Для начала создадим папку, в который будем заливать все необходимые файлы. На сервере пройдем в каталог /usr/local/bin и создадим папку bot.

cd /usr/local/bin
mkdir bot

У меня на ПК установлен windows, соответственно и команды будут для командной строки windows. Для начала необходимо пройти в каталог, где находится putty.exe.

cd /program files/putty

Далее загружаем bot.py, который находится в каталоге C:\Users\Ilya\PycharmProjects\Bot (нужно подставить Ваш каталог) в каталог на сервере /usr/local/bin/bot.

pscp.exe "C:\Users\Ilya\PycharmProjects\Bot\bot.py" root@123.123.12.12:/usr/local/bin/bot

Строчку root@123.123.12.12 нужно заменить на строчку вида login@IP_address, соответственно с Вашим логином и IP-адресом (упомянуты выше в разделе «Как же подключиться к VDS?»). Заменяя bot.py на названия других файлов, загрузите все необходимые.

Как скачать файлы с сервера на ПК?


Так же, как и при загрузке файлов на сервер в командной строке в каталог, где лежит putty.exe. И вводим эту команду, чтобы скачать файл database на рабочий стол Вашего ПК.

pscp.exe root@123.123.12.12:/usr/local/bin/bot/database "C:\Users\Ilya\Desktop

Как запустить бота?


Первый и самый простой вариант – зайти в каталог с исполняемым файлов и прописать python3 bot.py, но тогда при закрытии putty бот будет выключаться.

Второй вариант – запустить бота с помощью screen – модуль, который создаёт параллельные рабочие столы, но тогда бот не будет перезапускаться автоматически в случае падения, а это происходит часто – несколько раз в неделю из-за ночного перезапуска серверов telegram (в 3:00 по МСК).

Третий способ – systemd – cистемный менеджер, демон инициализации других демонов в Linux. Проще говоря, systemd запустит бота и будет перезапускать его в случае падения.

Установим systemd:

apt-get install systemd

Создайте файл на Вашем ПК с именем bot.service с таким содержанием:

[Unit]
Description=Telegram bot 'Town Wars'
After=syslog.target
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/usr/local/bin/bot
ExecStart=/usr/bin/python3 /usr/local/bin/bot/bot.py
RestartSec=10
Restart=always
 
[Install]
WantedBy=multi-user.target

И загружаем его в нужный каталог:

pscp.exe "C:\Users\Ilya\PycharmProjects\Bot\bot.service" root@123.123.12.12:/etc/systemd/system

Далее нужно прописать 4 команды в консоли сервера:

systemctl daemon-reload
systemctl enable bot
systemctl start bot
systemctl status bot

В моём случаи из-за определённых ошибок реализации, а конкретно многопоточности, пришлось переносить функцию для расчёта битв (battle_counter.py) в отдельного демона.

[Unit]
Description=Battle counter for telegram bot 'Town Wars'
After=syslog.target
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/usr/local/bin/bot
ExecStart=/usr/bin/python3 /usr/local/bin/bot/battle_counter.py
RestartSec=10
Restart=always
 
[Install]
WantedBy=multi-user.target

После чего должно появится сообщение примерно такого содержания:



Ваш бот запущен и готов к работе!

БЛАГОДАРНОСТИ


Это был мой первый относительно большой проект и я столкнулся с колоссальным количеством новых для меня проблем. Огромную благодарность хочу выразить Yurii Drake, который помог мне разобраться с ними!

ССЫЛКИ


Telegram
Telegram-бот
Официальная документация telegram
Неофициальная документация
PyTelagramBotAPI

VDS
Debian GNU/Linux
Putty
Командная строка Windows
Командная строка Mac

Screen
Systemd
Поделиться публикацией
Похожие публикации
Ммм, длинные выходные!
Самое время просмотреть заказы на Фрилансим.
Мне повезёт!
Реклама
Комментарии 20
  • +5
    <… или ещё один личный опыт по написанию бота на telegram>
    Серьёзно? Написал бота, установил Putty, залил по scp на удалённый комп… Что-то много в последнее время статей типа «смотрите как я могу»!
    • +1
      Ставить systemd ради автозагрузки бота это прям вау.
      • 0

        Для перезапуска использую crontab с проверкой занят ли порт, если занят — ничего не делаем, иначе — запускаем бота.

        • 0
          Посмотрите в сторону supervisor
          • 0
            Поделитесь реализацией? Очень полезно, на мой взгляд :)
            • +1
              Примерно так
              #/bin/bash
              cd /test_last/
              if lsof -Pi :7772 -sTCP:LISTEN -t >/dev/nul; then
                 echo "Working"
              else
                 echo "Not working.Starting..."
                 python3 bot.py
              fi
              

            • 0
              У себя использую flock в crontab:
              * * * * * /usr/bin/flock -n /run/lock/bot.lock python /homes/user/bot/bot.py
              

            • 0
              Как только на территории РФ вступил в силу запрет на анонимность в мессенджерах,(...)
              Для начала нужно установить telegram на ПК и зарегистрироваться в мессенджере.
              Установил Telegram на ПК, при регистрации требует номер телефона, который выдается в РФ только по паспорту. Запрет на анонимность, однако, работает.
              Список адресов/явок/паролей для анонимного получения телефонного номера был бы актуален.
              • 0
                Ему любой телефонный номер подходит, не только российский.
              • +1
                pscp.exe "C:\Users\Ilya\PycharmProjects\Bot\bot.py" root@123.123.12.12:/usr/local/bin/bot

                Имхо, лучше создать приватный репозиторий на каком-нибудь bitbucket и клонировать его.


                но тогда бот не будет перезапускаться автоматически в случае падения, а это происходит часто – несколько раз в неделю из-за ночного перезапуска серверов telegram (в 3:00 по МСК).

                Эм. С какой стати бот-то падает? А если интернета несколько секунд не будет, бот тоже упадёт? Это неправильный подход.

                • –1
                  Сервера телеграма перезапускаются несколько раз в неделю, и тогда бот падает.
                  • 0
                    Правильней использовать веб-хуки, примеры таких ботов есть в github репозитории библиотеки pytelegrambotapi, все прекрасно будет работать, если проект хостится на heroku, ну или на своем VPS тоже будет работать, только нужно будет настроить получение/продление SSL сертификата
                    • 0
                      У вас очень странный бот, особенно учитывая то, что вы пользуетесь готовой библиотекой.
                  • 0
                    apt-get install python3
                    apt-get update
                    apt-get install python3-setuptools
                    apt-get install python3-pip
                    pip3 install pyTelegramBotAPI
                    

                    Почему Вы устанавливаете Python до обновления репозитория, а остальные пакеты — после?
                    • 0
                      Насколько я помню, python установился без проблем, а вот pip никак не хотел без apt-get update.
                      • +3
                        update стоит выполнять перед установкой любых пакетов, а не когда что-то уже пошло не так. Ваша статья претендует на роль руководства, а по уровню подробностей — на руководство для начинающих в Linux, а обучаться лучше сразу правильно и осмысленно, а не по принципу «получилось — и ладно».
                  • 0
                    С каких пор у Putty официальный сайт стал putty.org?
                    Вот его официальный www.chiark.greenend.org.uk/~sgtatham/putty
                  • 0
                    Про загрузку файлов с ПК на сервер и наоборот.
                    Я обычно использую для этих целей FileZilla. Есть такой протокол, как SFTP, это FTP, работающий поверх SSH. Вводим айпишник, username,password, а порт ставим 22 (по умолчанию), нажимаем подключиться. Просто для меня это было удобнее и быстрее, чем возиться с командной строкой.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.