Pull to refresh

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

Reading time7 min
Views197K

Вступление


Как только на территории РФ вступил в силу запрет на анонимность в мессенджерах, у меня дошли руки написать пост про 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
Tags:
Hubs:
+2
Comments20

Articles

Change theme settings