Вступление


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

Комментарии (19)


  1. alexyr
    20.01.2018 16:37

    <… или ещё один личный опыт по написанию бота на telegram>
    Серьёзно? Написал бота, установил Putty, залил по scp на удалённый комп… Что-то много в последнее время статей типа «смотрите как я могу»!


  1. dpigo
    20.01.2018 18:08

    Ставить systemd ради автозагрузки бота это прям вау.


  1. ximik666
    20.01.2018 18:13

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


    1. dmkuznetsov
      21.01.2018 11:41

      Посмотрите в сторону supervisor


    1. forcam
      21.01.2018 18:12

      Поделитесь реализацией? Очень полезно, на мой взгляд :)


      1. ximik666
        22.01.2018 11:10
        +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
        


    1. alexyr
      22.01.2018 11:36

      У себя использую flock в crontab:

      * * * * * /usr/bin/flock -n /run/lock/bot.lock python /homes/user/bot/bot.py
      


  1. andrzzc
    20.01.2018 18:13

    Как только на территории РФ вступил в силу запрет на анонимность в мессенджерах,(...)
    Для начала нужно установить telegram на ПК и зарегистрироваться в мессенджере.
    Установил Telegram на ПК, при регистрации требует номер телефона, который выдается в РФ только по паспорту. Запрет на анонимность, однако, работает.
    Список адресов/явок/паролей для анонимного получения телефонного номера был бы актуален.


    1. dpigo
      20.01.2018 18:24

      Ему любой телефонный номер подходит, не только российский.


  1. lgorSL
    20.01.2018 20:47

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

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


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

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


    1. Richer_17 Автор
      20.01.2018 20:51

      Сервера телеграма перезапускаются несколько раз в неделю, и тогда бот падает.


      1. kvamob
        20.01.2018 22:01

        Правильней использовать веб-хуки, примеры таких ботов есть в github репозитории библиотеки pytelegrambotapi, все прекрасно будет работать, если проект хостится на heroku, ну или на своем VPS тоже будет работать, только нужно будет настроить получение/продление SSL сертификата


      1. majere
        20.01.2018 22:01

        У вас очень странный бот, особенно учитывая то, что вы пользуетесь готовой библиотекой.


  1. Serge78rus
    20.01.2018 21:59

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

    Почему Вы устанавливаете Python до обновления репозитория, а остальные пакеты — после?


    1. Richer_17 Автор
      20.01.2018 22:02

      Насколько я помню, python установился без проблем, а вот pip никак не хотел без apt-get update.


      1. Serge78rus
        20.01.2018 22:30

        update стоит выполнять перед установкой любых пакетов, а не когда что-то уже пошло не так. Ваша статья претендует на роль руководства, а по уровню подробностей — на руководство для начинающих в Linux, а обучаться лучше сразу правильно и осмысленно, а не по принципу «получилось — и ладно».


        1. Richer_17 Автор
          21.01.2018 18:16

          Спасибо. Исправил.


  1. VecH
    21.01.2018 18:15

    С каких пор у Putty официальный сайт стал putty.org?
    Вот его официальный www.chiark.greenend.org.uk/~sgtatham/putty


    1. Richer_17 Автор
      21.01.2018 18:16

      Спасибо. Исправил.