Как создать Telegram-бота с помощью библиотеки python-telegram-bot
Делимся инструкцией, как написать бота с помощью библиотеки python-telegram-bot за считанные минуты. На примере гайда от программиста Давида Мастроматтео.
Установка python-telegram-bot
Для создания бота понадобится пакет python-telegram-bot — оболочка для API от Telegram. Написать бота с помощью этой библиотеки очень просто, так как она полностью совместима с Python 3.6+.
Первое, что нужно сделать — установить python-telegram-bot. Вот ссылка на официальную документацию библиотеки.
$ pip install python-telegram-bot –upgrade
Создание бота
Теперь можно взяться за создание бота. Для этого даже не нужно писать код. Перейдите в Telegram и найдите канал @BotFather, который отвечает за регистрацию новых ботов. Начните общаться с ботом и введите команду /newbot. Затем BotFather спросит у вас имя и юзернейм.

BotFather 1

BotFather 2
У BotFather можно запросить много других интересных вещей. Например, изменить изображение профиля бота.
Теперь нужно принять важное решение: определиться с главной задачей бота. В этой инструкции мы сделаем бота, который предоставляет информацию о биоритмах пользователей. Будьте осторожны: речь идет о псевдонаучных теориях, так что бот будет такой же полезный, как и гороскопы. Но если дойдете до конца — сможете создавать любых ботов.
Освоить язык программирования Python вам могут помочь онлайн курсы от наших партнеров Mate Academy и Powercode. Получите качественный уровень знаний от практикующих специалистов.
Программирование бота
Пакет python-telegram-bot состоит из оболочки API Telegram. Этот инструмент доступен через telegram.Bot-классы. Помимо них, есть еще модуль telegram.ext, который значительно упростит работу.
Модуль telegram.ext содержит много классов, но самые важные — telegram.ext.Updater и telegram.ext.Dispatcher. Updater отвечает за выборку новых обновлений от Telegram. Также он передает их в Dispatcher, после чего они обрабатываются с помощью Handler.
Приступим к программированию:
# mastrobot_example.py
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
# function to handle the /start command
def start(update, context):
update.message.reply_text('start command received')
# function to handle the /help command
def help(update, context):
update.message.reply_text('help command received')
# function to handle errors occured in the dispatcher
def error(update, context):
update.message.reply_text('an error occured')
# function to handle normal text
def text(update, context):
text_received = update.message.text
update.message.reply_text(f'did you said "{text_received}" ?')
def main():
TOKEN = "insert here your token and don't share it with anyone!"
# create the updater, that will automatically create also a dispatcher and a queue to
# make them dialoge
updater = Updater(TOKEN, use_context=True)
dispatcher = updater.dispatcher
# add handlers for start and help commands
dispatcher.add_handler(CommandHandler("start", start))
dispatcher.add_handler(CommandHandler("help", help))
# add an handler for normal text (not commands)
dispatcher.add_handler(MessageHandler(Filters.text, text))
# add an handler for errors
dispatcher.add_error_handler(error)
# start your shiny new bot
updater.start_polling()
# run the bot until Ctrl-C
updater.idle()
if __name__ == '__main__':
main()
В функции main создан класс Updater, который автоматически сгенерировал объект Dispatcher, доступный через .dispatcher-свойства класса Updater.
Добавьте несколько обработчиков:
- команда /start вызывает функцию start(), которая отвечает пользователю информативным сообщением;
- команда /help вызывает функцию help(), которая отвечает пользователю информативным сообщением;
- если при отправке сообщений возникает ошибка, вызываем функцию error();
- если пользователь напишет фразы или символы, которые не являются командой, вызываем функцию text(), отвечающую пользователю тем же полученным текстом.
Сейчас в коде прописаны функции обратного вызова, которые используют полученные данные для отправки сообщений пользователю.
Тестирование
Теперь можно протестировать бота. Запустите его.
$ python mastrobot_example.py
Пошлите ему команду /start .
Ура, бот работает!
Но это не конец. Надо создать бота, который сообщает пользователю его ежедневный биоритм. Для этого следует применить команду /start. С ее помощью при запуске чата можно получить данные о дне рождения пользователя. Затем надо создать функцию для обработки новой команды /biorhythm, чтобы отправить ответ пользователю с его личным биоритмом.
Чтобы узнать день рождения пользователя, для начала нужно изменить функцию, обрабатывающую команду /start. Чтобы упростить задачу, попросите пользователя указать год, месяц и день рождения.
# function to handle the /start command
def start(update, context):
first_name = update.message.chat.first_name
update.message.reply_text(f"Hi {first_name}, nice to meet you!")
start_getting_birthday_info(update, context)
В параметре update можно найти полезную информацию о пользователе, например, его имя.
В самом начале скрипта определите новую переменную STATE, которая нужна, чтобы понять, на какой вопрос отвечает пользователь.
STATE = None BIRTH_YEAR = 1 BIRTH_MONTH = 2 BIRTH_DAY = 3
Теперь необходимо реализовать функцию start_getting:_birthday_info(), она вызывается с помощью команды start(). После запуска вы получите информацию о дне рождения от пользователя.
def start_getting_birthday_info(update, context):
global STATE
STATE = BIRTH_YEAR
update.message.reply_text(f"I would need to know your birthday, so tell me what year were you born in...")
Для переменной STATE устанавливается значение BIRTH_YEAR, чтобы после ответа пользователя было понятно, что вопрос касался года рождения. Затем отправляется сообщение, чтобы узнать год рождения.
Теперь пользователь ответит обычным текстом, поэтому нужно изменить функцию text().
def text(update, context):
global STATE
if STATE == BIRTH_YEAR:
return received_birth_year(update, context)
if STATE == BIRTH_MONTH:
return received_birth_month(update, context)
if STATE == BIRTH_DAY:
return received_birth_day(update, context)
В функции text() необходимо понять, на какой вопрос отвечает пользователь, используя переменную STATE. После чего остается вызвать функцию для обработки каждого ответа.
Эти функции можно записать так:
def received_birth_year(update, context):
global STATE
try:
today = datetime.date.today()
year = int(update.message.text)
if year > today.year:
raise ValueError("invalid value")
context.user_data['birth_year'] = year
update.message.reply_text(f"ok, now I need to know the month (in numerical form)...")
STATE = BIRTH_MONTH
except:
update.message.reply_text("it's funny but it doesn't seem to be correct...")
def received_birth_month(update, context):
global STATE
try:
today = datetime.date.today()
month = int(update.message.text)
if month > 12 or month < 1:
raise ValueError("invalid value")
context.user_data['birth_month'] = month
update.message.reply_text(f"great! And now, the day...")
STATE = BIRTH_DAY
except:
update.message.reply_text("it's funny but it doesn't seem to be correct...")
def received_birth_day(update, context):
global STATE
try:
today = datetime.date.today()
dd = int(update.message.text)
yyyy = context.user_data['birth_year']
mm = context.user_data['birth_month']
birthday = datetime.date(year=yyyy, month=mm, day=dd)
if today - birthday < datetime.timedelta(days=0):
raise ValueError("invalid value")
context.user_data['birthday'] = birthday
STATE = None
update.message.reply_text(f'ok, you born on {birthday}')
except:
update.message.reply_text("it's funny but it doesn't seem to be correct...")
Когда получен год рождения пользователя, остается проверить, допустимое ли это значение. Если да, то оно сохраняется в словаре context.user_data[]. Продолжайте устанавливать значения для переменной STATE и задавать следующие вопросы.
Когда зададите последний вопрос и будете знать день рождения, создайте переменную даты и сохраните ее в context.user_data[] словаре.
Если пользователь вводит недопустимое значение, то получает ответ, что оно неверно. Значение переменной STATE не меняется, поэтому пользователь застревает на этом вопросе, пока не ответит правильно.
Получить новые знания в языке программирования Python вам могут помочь специальные курсы от Hillel и ШАГ. Получите качественный уровень знаний от практикующих специалистов.
Создание команды
Теперь нужно обработать команду /biorhythm.
Добавьте новый обработчик команд в функцию main().
dispatcher.add_handler(CommandHandler("biorhythm", biorhythm))
Напишите функцию расчета биоритма:
# This function is called when the /biorhythm command is issued
def biorhythm(update, context):
user_biorhythm = calculate_biorhythm(
context.user_data['birthday'])
update.message.reply_text(f"Phisical: {user_biorhythm['phisical']}")
update.message.reply_text(f"Emotional: {user_biorhythm['emotional']}")
update.message.reply_text(f"Intellectual: {user_biorhythm['intellectual']}")
def calculate_biorhythm(birthdate):
today = datetime.date.today()
delta = today - birthdate
days = delta.days
phisical = math.sin(2*math.pi*(days/23))
emotional = math.sin(2*math.pi*(days/28))
intellectual = math.sin(2*math.pi*(days/33))
biorhythm = {}
biorhythm['phisical'] = int(phisical * 10000)/100
biorhythm['emotional'] = int(emotional * 10000)/100
biorhythm['intellectual'] = int(intellectual * 10000)/100
biorhythm['phisical_critical_day'] = (phisical == 0)
biorhythm['emotional_critical_day'] = (emotional == 0)
biorhythm['intellectual_critical_day'] = (intellectual == 0)
return biorhythm
В примере представлены две разные функции: одна для обработки команды, а другая для расчета биоритма. Таким образом удается разделить ответственность этих функций.
Полный код бота
# mastrobot_example2.py
import datetime
import math
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
STATE = None
BIRTH_YEAR = 1
BIRTH_MONTH = 2
BIRTH_DAY = 3
# function to handle the /start command
def start(update, context):
first_name = update.message.chat.first_name
update.message.reply_text(f"Hi {first_name}, nice to meet you!")
start_getting_birthday_info(update, context)
def start_getting_birthday_info(update, context):
global STATE
STATE = BIRTH_YEAR
update.message.reply_text(
f"I would need to know your birthday, so tell me what year were you born in...")
def received_birth_year(update, context):
global STATE
try:
today = datetime.date.today()
year = int(update.message.text)
if year > today.year:
raise ValueError("invalid value")
context.user_data['birth_year'] = year
update.message.reply_text(
f"ok, now I need to know the month (in numerical form)...")
STATE = BIRTH_MONTH
except:
update.message.reply_text(
"it's funny but it doesn't seem to be correct...")
def received_birth_month(update, context):
global STATE
try:
today = datetime.date.today()
month = int(update.message.text)
if month > 12 or month < 1:
raise ValueError("invalid value")
context.user_data['birth_month'] = month
update.message.reply_text(f"great! And now, the day...")
STATE = BIRTH_DAY
except:
update.message.reply_text(
"it's funny but it doesn't seem to be correct...")
def received_birth_day(update, context):
global STATE
try:
today = datetime.date.today()
dd = int(update.message.text)
yyyy = context.user_data['birth_year']
mm = context.user_data['birth_month']
birthday = datetime.date(year=yyyy, month=mm, day=dd)
if today - birthday < datetime.timedelta(days=0):
raise ValueError("invalid value")
context.user_data['birthday'] = birthday
STATE = None
update.message.reply_text(f'ok, you born on {birthday}')
except:
update.message.reply_text(
"it's funny but it doesn't seem to be correct...")
# function to handle the /help command
def help(update, context):
update.message.reply_text('help command received')
# function to handle errors occured in the dispatcher
def error(update, context):
update.message.reply_text('an error occured')
# function to handle normal text
def text(update, context):
global STATE
if STATE == BIRTH_YEAR:
return received_birth_year(update, context)
if STATE == BIRTH_MONTH:
return received_birth_month(update, context)
if STATE == BIRTH_DAY:
return received_birth_day(update, context)
# This function is called when the /biorhythm command is issued
def biorhythm(update, context):
print("ok")
user_biorhythm = calculate_biorhythm(
context.user_data['birthday'])
update.message.reply_text(f"Phisical: {user_biorhythm['phisical']}")
update.message.reply_text(f"Emotional: {user_biorhythm['emotional']}")
update.message.reply_text(f"Intellectual: {user_biorhythm['intellectual']}")
def calculate_biorhythm(birthdate):
today = datetime.date.today()
delta = today - birthdate
days = delta.days
phisical = math.sin(2*math.pi*(days/23))
emotional = math.sin(2*math.pi*(days/28))
intellectual = math.sin(2*math.pi*(days/33))
biorhythm = {}
biorhythm['phisical'] = int(phisical * 10000)/100
biorhythm['emotional'] = int(emotional * 10000)/100
biorhythm['intellectual'] = int(intellectual * 10000)/100
biorhythm['phisical_critical_day'] = (phisical == 0)
biorhythm['emotional_critical_day'] = (emotional == 0)
biorhythm['intellectual_critical_day'] = (intellectual == 0)
return biorhythm
def main():
TOKEN = "insert here your token and don't share it with anyone!"
# create the updater, that will automatically create also a dispatcher and a queue to
# make them dialoge
updater = Updater(TOKEN, use_context=True)
dispatcher = updater.dispatcher
# add handlers for start and help commands
dispatcher.add_handler(CommandHandler("start", start))
dispatcher.add_handler(CommandHandler("help", help))
# add an handler for our biorhythm command
dispatcher.add_handler(CommandHandler("biorhythm", biorhythm))
# add an handler for normal text (not commands)
dispatcher.add_handler(MessageHandler(Filters.text, text))
# add an handler for errors
dispatcher.add_error_handler(error)
# start your shiny new bot
updater.start_polling()
# run the bot until Ctrl-C
updater.idle()
if __name__ == '__main__':
main()
Пришло время проверить его:

Telegram bot
Поздравляем! Telegram-бот на Python полностью готов.
Бот, созданный для примера, был сохранен. Его можно протестировать по имени пользователя @mastro35_mastrobot.

Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: