Содержание
Мессенджеры *Python *Социальные сети и сообщества Из песочницы На Хабре, да и не только, про ботов рассказано уже так много, что даже слишком. Но заинтересовавшись пару недель назад данной темой, найти нормальный материал у меня так и не вышло: все статьи были либо для совсем чайников и ограничивались отправкой сообщения в ответ на сообщение пользователя, либо были неактуальны. Это и подтолкнуло меня на написание статьи, которая бы объяснила такому же новичку, как я, как написать и запустить более-менее осмысленного бота (с возможностью расширения функциональности).
Часть 1: Регистрация бота
Самая простая и описанная часть. Очень коротко: нужно найти бота @BotFather, написать ему /start, или /newbot, заполнить поля, которые он спросит (название бота и его короткое имя), и получить сообщение с токеном бота и ссылкой на документацию. Токен нужно сохранить, желательно надёжно, так как это единственный ключ для авторизации бота и взаимодействия с ним.
Часть 2: Подготовка к написанию кода
Как уже было сказано в заголовке, писать бота мы будем на Python’е. В данной статье будет описана работа с библиотекой PyTelegramBotAPI (Telebot). Если у вас не установлен Python, то сперва нужно сделать это: в терминале Linux нужно ввести
sudo apt-get install python python-pip
Если же вы пользуетесь Windows, то нужно скачать Python с официального сайта . После, в терминале Linux, или командной строке Windows вводим
pip install pytelegrambotapi
Теперь все готово для написания кода.
Часть 3: Получаем сообщения и говорим «Привет»
Небольшое отступление. Телеграмм умеет сообщать боту о действиях пользователя двумя способами: через ответ на запрос сервера (Long Poll), и через Webhook, когда сервер Телеграмма сам присылает сообщение о том, что кто-то написал боту. Второй способ явно выглядит лучше, но требует выделенного IP-адреса, и установленного SSL на сервере. В этой статье я хочу рассказать о написании бота, а не настройке сервера, поэтому пользоваться мы будем Long Poll’ом. Открывайте ваш любимый текстовый редактор, и давайте писать код бота! Первое, что нужно сделать это импортировать нашу библиотеку и подключить токен бота:
import telebot; bot = telebot.TeleBot('%ваш токен%');
Теперь объявим метод для получения текстовых сообщений:
@bot.message_handler(content_types=['text']) def get_text_messages(message):
В этом участке кода мы объявили слушателя для текстовых сообщений и метод их обработки. Поле content_types может принимать разные значения, и не только одно, например
@bot.message_handler(content_types=['text', 'document', 'audio'])
Будет реагировать на текстовые сообщения, документы и аудио. Более подробно можно почитать в официальной документации Теперь добавим в наш метод немного функционала: если пользователь напишет нам «Привет», то скажем ему «Привет, чем я могу помочь?», а если нам напишут команду «/help», то скажем пользователю написать «Привет»:
if message.text == "Привет": bot.send_message(message.from_user.id, "Привет, чем я могу тебе помочь?") elif message.text == "/help": bot.send_message(message.from_user.id, "Напиши привет") else: bot.send_message(message.from_user.id, "Я тебя не понимаю. Напиши /help.")
Данный участок кода не требует комментариев, как мне кажется. Теперь нужно добавить в наш код только одну строчку (вне всех методов).
bot.polling(none_stop=True, interval=0)
Теперь наш бот будет постоянно спрашивать у сервера Телеграмма «Мне кто-нибудь написал?», и если мы напишем нашему боту, то Телеграмм передаст ему наше сообщение. Сохраняем весь файл, и пишем в консоли
python bot.py
Где bot.py – имя нашего файла. Теперь можно написать боту и посмотреть на результат:
Часть 4: Кнопки и ветки сообщений
Отправлять сообщения это несомненно весело, но ещё веселее вести с пользователем диалог: задавать ему вопросы и получать на них ответы. Допустим, теперь наш бот будет спрашивать у пользователя по очереди его имя, фамилию и возраст. Для этого мы будем использовать метод register_next_step_handler бота:
name = ''; surname = ''; age = 0; @bot.message_handler(content_types=['text']) def start(message): if message.text == '/reg': bot.send_message(message.from_user.id, "Как тебя зовут?"); bot.register_next_step_handler(message, get_name); #следующий шаг – функция get_name else: bot.send_message(message.from_user.id, 'Напиши /reg'); def get_name(message): #получаем фамилию global name; name = message.text; bot.send_message(message.from_user.id, 'Какая у тебя фамилия?'); bot.register_next_step_handler(message, get_surnme); def get_surname(message): global surname; surname = message.text; bot.send_message('Сколько тебе лет?'); bot.register_next_step_handler(message, get_age); def get_age(message): global age; while age == 0: #проверяем что возраст изменился try: age = int(message.text) #проверяем, что возраст введен корректно except Exception: bot.send_message(message.from_user.id, 'Цифрами, пожалуйста'); bot.send_message(message.from_user.id, 'Тебе '+str(age)+' лет, тебя зовут '+name+' '+surname+'?')
И так, данные пользователя мы записали. В этом примере показан очень упрощённый пример, по хорошему, хранить промежуточные данные и состояния пользователя нужно в БД, но мы сегодня работаем с ботом, а не с базами данных. Последний штрих – запросим у пользователей подтверждение того, что все введено верно, да не просто так, а с кнопками! Для этого немного отредактируем код метода get_age
def get_age(message): global age; while age == 0: #проверяем что возраст изменился try: age = int(message.text) #проверяем, что возраст введен корректно except Exception: bot.send_message(message.from_user.id, 'Цифрами, пожалуйста'); keyboard = types.InlineKeyboardMarkup(); #наша клавиатура key_yes = types.InlineKeyboardButton(text='Да', callback_data='yes'); #кнопка «Да» keyboard.add(key_yes); #добавляем кнопку в клавиатуру key_no= types.InlineKeyboardButton(text='Нет', callback_data='no'); keyboard.add(key_no); question = 'Тебе '+str(age)+' лет, тебя зовут '+name+' '+surname+'?'; bot.send_message(message.from_user.id, text=question, reply_markup=keyboard)
И теперь наш бот отправляет клавиатуру, но если на нее нажать, то ничего не произойдёт. Потому что мы не написали метод-обработчик. Давайте напишем:
@bot.callback_query_handler(func=lambda call: True) def callback_worker(call): if call.data == "yes": #call.data это callback_data, которую мы указали при объявлении кнопки .... #код сохранения данных, или их обработки bot.send_message(call.message.chat.id, 'Запомню : )'); elif call.data == "no": ... #переспрашиваем
Остаётся только дописать в начало файла одну строку:
from telebot import types
Вот и всё, сохраняем и запускаем нашего бота:
Python для новичков
Если ты совсем не ориентируешься в Python, то отличным началом будет прочтение трех вводных статей, которые я публиковал в «Хакере» этим летом, либо посещение курса «Python для новичков», который я начну вести для читателей «Хакера» уже совсем скоро — 30 ноября.
- Python с абсолютного нуля. Учимся кодить без скучных книжек
- Python с абсолютного нуля. Учимся работать со строками, файлами и интернетом
- Python с абсолютного нуля. Работаем с ОС, изучаем регулярные выражения и функции
Чтобы создать бота, нам нужно дать ему название, адрес и получить токен — строку, которая будет однозначно идентифицировать нашего бота для серверов Telegram. Зайдем в Telegram под своим аккаунтом и откроем «отца всех ботов», BotFather.
Жмем кнопку «Запустить» (или отправим / start
), в ответ BotFather пришлет нам список доступных команд:
/ newbot
— создать нового бота;/ mybots
— редактировать ваших ботов;/ setname
— сменить имя бота;/ setdescription
— изменить описание бота;/ setabouttext
— изменить информацию о боте;/ setuserpic
— изменить фото аватарки бота;/ setcommands
— изменить список команд бота;/ deletebot
— удалить бота.
Отправим бате‑боту команду / newbot
, чтобы создать нового бота. В ответ он попросит ввести имя будущего бота, его можно писать на русском. После ввода имени нужно будет отправить адрес бота, причем он должен заканчиваться на слово bot. Например, xakepbot
или xakep_bot
. Если адрес будет уже кем‑то занят, BotFather начнет извиняться и просить придумать что‑нибудь другое.
Когда мы наконец найдем свободный и красивый адрес для нашего бота, в ответ получим сообщение, в котором после фразы Use this token to access the HTTP API будет написана строка из букв и цифр — это и есть необходимый нам токен. Сохраним ее где‑нибудь на своем компьютере, чтобы потом использовать в скрипте бота.
Для взаимодействия с Telegram API есть несколько готовых модулей. Самый простой из них — Telebot. Чтобы установить его, набери
pip install pytelegrambotapi
В Linux, возможно, понадобится написать pip3
вместо pip
, чтобы указать, что мы хотим работать с третьей версией Python.
Эхо-бот
Для начала реализуем так называемого эхо‑бота. Он будет получать от пользователя текстовое сообщение и возвращать его.
import telebot # Создаем экземпляр ботаbot = telebot.TeleBot('Здесь впиши токен, полученный от @botfather') # Функция, обрабатывающая команду /start@bot.message_handler(commands=["start"])def start(m, res=False): bot.send_message(m.chat.id, 'Я на связи. Напиши мне что-нибудь )') # Получение сообщений от юзера@bot.message_handler(content_types=["text"])def handle_text(message): bot.send_message(message.chat.id, 'Вы написали: ' + message.text) # Запускаем ботаbot.polling(none_stop=True, interval=0)
Запускай скрипт и ищи в поиске Telegram своего бота по адресу, который ты придумал ранее. Запускаем бота кнопкой «Запустить» (Start) или командой / start
и можем убедиться в том, что он работает и возвращает сообщения.
Wikipedia-бот
Давай научим нашего бота не просто отсылать сообщения обратно, а чему‑нибудь поинтереснее. Например, по введенному слову давать статью на Википедии. Здесь нам поможет модуль Wikipedia:
pip install wikipedia
Готовим код.
import telebot, wikipedia, re # Создаем экземпляр ботаbot = telebot.TeleBot('Здесь впиши токен, полученный от @botfather') # Устанавливаем русский язык в Wikipediawikipedia.set_lang("ru") # Чистим текст статьи в Wikipedia и ограничиваем его тысячей символовdef getwiki(s): try: ny = wikipedia.page(s) # Получаем первую тысячу символов wikitext=ny.content[:1000] # Разделяем по точкам wikimas=wikitext.split('.') # Отбрасываем всЕ после последней точки wikimas = wikimas[:-1] # Создаем пустую переменную для текста wikitext2 = '' # Проходимся по строкам, где нет знаков «равно» (то есть все, кроме заголовков) for x in wikimas: if not('==' in x): # Если в строке осталось больше трех символов, добавляем ее к нашей переменной и возвращаем утерянные при разделении строк точки на место if(len((x.strip()))>3): wikitext2=wikitext2+x+'.' else: break # Теперь при помощи регулярных выражений убираем разметку wikitext2=re.sub('([^()]*)', '', wikitext2) wikitext2=re.sub('([^()]*)', '', wikitext2) wikitext2=re.sub('{[^{}]*}', '', wikitext2) # Возвращаем текстовую строку return wikitext2 # Обрабатываем исключение, которое мог вернуть модуль wikipedia при запросе except Exception as e: return 'В энциклопедии нет информации об этом' # Функция, обрабатывающая команду /start@bot.message_handler(commands=["start"])def start(m, res=False): bot.send_message(m.chat.id, 'Отправьте мне любое слово, и я найду его значение на Wikipedia') # Получение сообщений от юзера@bot.message_handler(content_types=["text"])def handle_text(message): bot.send_message(message.chat.id, getwiki(message.text)) # Запускаем ботаbot.polling(none_stop=True, interval=0)
Другие статьи в выпуске:
Xakep #272. Приручаем WinAFL
- Содержание выпуска
- Подписка на «Хакер»-70%
www
При создании следующих ботов мы будем использовать несколько текстовых файлов с контентом. Скачать их можно с моего сайта.
Бот с двумя виртуальными кнопками
Во многих Telegram-ботах для выбора каких‑то действий используются так называемые виртуальные кнопки. Давай попробуем сделать себе такие же!
Предположим, что у нас есть два файла facts. txt
и thinks. txt
, которые содержат список интересных фактов и поговорки. На каждой строке файлов находится по одному факту или поговорке.
Сделаем бота, в котором будут две кнопки: «Факты» и «Поговорки». Если нажать любую, бот отправит пользователю соответствующее сообщение.
info
Если ты будешь использовать для этого бота тот же токен, что и для предыдущего, то, чтобы увидеть кнопки, перезапусти бота командой / start
.
import telebotimport randomfrom telebot import types # Загружаем список интересных фактовf = open('data/facts.txt', 'r', encoding='UTF-8')facts = f.read().split('n')f.close() # Загружаем список поговорокf = open('data/thinks.txt', 'r', encoding='UTF-8')thinks = f.read().split('n')f.close() # Создаем ботаbot = telebot.TeleBot('Здесь твой токен, полученный от @botfather') # Команда start@bot.message_handler(commands=["start"])def start(m, res=False): # Добавляем две кнопки markup=types.ReplyKeyboardMarkup(resize_keyboard=True) item1=types.KeyboardButton("Факт") item2=types.KeyboardButton("Поговорка") markup.add(item1) markup.add(item2) bot.send_message(m.chat.id, 'Нажми: nФакт для получения интересного фактаnПоговорка — для получения мудрой цитаты ', reply_markup=markup) # Получение сообщений от юзера@bot.message_handler(content_types=["text"])def handle_text(message): # Если юзер прислал 1, выдаем ему случайный факт if message.text.strip() == 'Факт' : answer = random.choice(facts) # Если юзер прислал 2, выдаем умную мысль elif message.text.strip() == 'Поговорка': answer = random.choice(thinks) # Отсылаем юзеру сообщение в его чат bot.send_message(message.chat.id, answer) # Запускаем ботаbot.polling(none_stop=True, interval=0)
Бот, ведущий Telegram-канал с анекдотами
Предыдущие боты посылали юзеру сообщения тогда, когда получали от него команды или фразы. Но что, если нам нужен бот, который будет периодически и в автоматическом режиме постить что‑то в наш канал?
Давай сделаем бота, который получает список анекдотов из файла и каждый час постит в канал один из этих анекдотов. Для этого нам нужно создать свой канал в Telegram, добавить в подписчики канала нашего бота и назначить его администратором канала с правом публиковать сообщения.
Файл с анекдотами должен лежать в папке data
рядом со скриптом бота.
import telebotimport time # Токен, который выдает @botfatherbot = telebot.TeleBot('Здесь твой токен, полученный от @botfather')# Адрес телеграм-канала, начинается с @CHANNEL_NAME = '@адрес_твоего_канала' # Загружаем список шутокf = open('data/fun.txt', 'r', encoding='UTF-8')jokes = f.read().split('n')f.close() # Пока не закончатся шутки, посылаем их в каналfor joke in jokes: bot.send_message(CHANNEL_NAME, joke) # Делаем паузу в один час time.sleep(3600) bot.send_message(CHANNEL_NAME, "Анекдоты закончились :-(")
Чат-бот «Маша»
Теперь давай сделаем простейшего чат‑бота, который будет болтать с пользователем. Для этого мы подготовим файл boltun. txt
, содержащий строки с вопросами (в начале таких строк поставим метку u:
) и ответами на них в следующей строке.
u: как зовутМаша меня зовут!u: сколько тебе летМне уже 18, честно-честно!
Файл boltun. txt
поместим в папку data
рядом со скриптом бота. Для поиска похожих вопросов используем модуль fuzzywuzzy, который позволяет сравнивать, насколько похожи между собой две строки. Естественно, сперва этот модуль нужно установить:
pip install fuzzywuzzypip install python-Levenshtein
Ниже приведен исходный код бота. После его запуска напиши боту «Привет» и попробуй с ним пообщаться. Естественно, это не искусственный интеллект и набор его ответов ограничен фразами из файла boltun. txt
.
import telebotimport osfrom fuzzywuzzy import fuzz # Создаем бота, пишем свой токенbot = telebot.TeleBot('Здесь твой токен, полученный от @botfather') # Загружаем список фраз и ответов в массивmas=[]if os.path.exists('data/boltun.txt'): f=open('data/boltun.txt', 'r', encoding='UTF-8') for x in f: if(len(x.strip()) > 2): mas.append(x.strip().lower()) f.close() # С помощью fuzzywuzzy вычисляем наиболее похожую фразу и выдаем в качестве ответа следующий элемент спискаdef answer(text): try: text=text.lower().strip() if os.path.exists('data/boltun.txt'): a = 0 n = 0 nn = 0 for q in mas: if('u: ' in q): # С помощью fuzzywuzzy получаем, насколько похожи две строки aa=(fuzz.token_sort_ratio(q.replace('u: ',''), text)) if(aa > a and aa!= a): a = aa nn = n n = n + 1 s = mas[nn + 1] return s else: return 'Ошибка' except: return 'Ошибка' # Команда «Старт»@bot.message_handler(commands=["start"])def start(m, res=False): bot.send_message(m.chat.id, 'Я на связи. Напиши мне Привет )') # Получение сообщений от юзера@bot.message_handler(content_types=["text"])def handle_text(message): # Запись логов f=open('data/' + str(message.chat.id) + '_log.txt', 'a', encoding='UTF-8') s=answer(message.text) f.write('u: ' + message.text + 'n' + s +'n') f.close() # Отправка ответа bot.send_message(message.chat.id, s) # Запускаем ботаbot.polling(none_stop=True, interval=0)
Выводы
Мы написали пять простых ботов, на примере которых научились принимать и отправлять сообщения, делать кнопки и понимать неточные запросы.
В следующей статье мы рассмотрим работу с Telegram-ботами более подробно: научимся делать ботов, работающих через веб‑хуки, принимать оплату от пользователей и взаимодействовать с базой данных SQLite.
Также призываю тебя не откладывать и записываться на курс «Python для новичков», где мы от простейших понятий перейдем к созданию первых интересных проектов. Стартуем уже совсем скоро!
Курс по Python
Курс «Python с нуля» направлен на изучение основ и базовых концепций программирования. После него ты сможешь легко углубиться в любую из ИТ‑сфер: веб‑разработку, анализ данных, безопасность приложений и так далее. Продолжительность курса — два календарных месяца. Уроки будут проводиться два раза в неделю (вторник и четверг, ориентировочно в 17:00 по Москве), каждый по одному академическому часу. Периодически будут выдаваться домашние задания.
Записаться на курс
← Ранее Интерпол сообщил об аресте 1000 человек, связанных с киберпреступностью Далее → HTB Intelligence. Пентестим Active Directory от MSA до KDC Интенсив «Научитесь собирать информацию с сайтов с помощью парсера на Python» tproger.ru События и курсы на tproger.ru
Ну вот и всё, простенький бот в Телеграмме на языке Python готов.
Docker
Сейчас мало кто не слышал про Docker, но если вдруг не слышали — вот хорошая статья. Для нашего проекта потребуется самый простой Dockerfile:
FROM python:3.8 # set work directory WORKDIR /usr/src/app/ # copy project COPY . /usr/src/app/ # install dependencies RUN pip install --user aiogram # run app CMD ["python", "bot.py"]
Каталог проекта должны при этом содержать следующие файлы:
- bot.py;
- Dockerfile.
Для локальных тестов достаточно установить Docker (linux, mac, windows), после чего в папке проекта собрать и запустить контейнер с помощью команд:
docker build -t my_app docker run -d my_app
my_app
— это просто название нашего контейнера, вместо которого можно использовать другое имя.
-d
— специальный флаг, который запускает контейнер в фоне и позволяет дальше работать в терминале. Это называется detached mode.
Деплой на AWS
Прежде всего нам понадобится аккаунт на Docker Hub. Это аналог GitHub, только не с исходниками кода, а с уже созданными контейнерами. Работа с Docker Hub выглядит достаточно просто:
- Локально или с помощью пайплайнов собрали контейнер.
- Загрузили его на докер хаб.
- В любом удобном месте скачали его. Это может быть локальная машина, VPS сервер или облачный провайдер по типу AWS.
- Запустили.
Пройдёмся по этим шагам. Везде, где указано , надо вставлять свой юзернейм, использованный при регистрации на докерхабе. Если это ваша первая публикация на докерхаб, для начала потребуется залогиниться с помощью docker login.
Билдим контейнер:
docker build -t /my_app
Загружаем его на докерхаб:
docker push /my_app
Для проверки успешности загрузки можете запустить контейнер из Docker Hub с помощью команды:
docker run -d /my_app
Далее загрузим наш контейнер в AWS Elastic Beanstalk. Для этого потребуется аккаунт на AWS. Если его нет, необходимо зарегистрироваться. Вас попросят ввести данные карты для верификации, но переживать не стоит, ведь мы воспользуемся бесплатным годовым триалом. Чтобы поиграться, этого более чем достаточно, а вот если вы захотите вывести проект в продакшен, следует перейти на VPS — это даст больше контроля и гибкости.
- Переходим в Elastic Beanstalk, на вкладку Applications, и создаём новое приложение:
- Называем приложение, теги оставляем пустыми:
- Создаём для приложения environment:
- Выбираем Worker environment:
- В качестве платформы выбираем Docker:
- В пункте Application code нужно загрузить JSON-файл с конфигурацией Docker-образа. Сам файл:
Dockerrun.aws.json { "AWSEBDockerrunVersion": "1", "Image": { "Name": "/my_app", "Update": "true" }, "Ports": [ { "ContainerPort": 5000, "HostPort": 8000 } ] }
- Создаём окружение:
- AWS начинает создавать окружение, просто ждём завершения процесса:
- Если всё прошло успешно, вы увидите индикатор успешного запуска приложения:
Проверяем работу нашего Telegram bot:
Успех!
Заключение
Поздравляем! Теперь вы знаете, как писать роботов для Telegram на Python.
Бота можно дополнять другими функциями, например, добавить отправку файлов, опрос или клавиатуру.
Кстати, в телеграмме есть аж целых два типа клавиатур:
- Классическая RelpyKeyboardMarkup, у которой кнопки располагаются под полем ввода сообщения:
- Более современная InlineKeyboardMarkup, которая привязывается к конкретному сообщению:
Но и это полностью рабочий Телеграм-бот на Python: дополните словарём, и получите полноценную беседу. Также можете опробовать функциональность нашего Telegram-бота.
В «настоящих проектах» не обойтись без базы данных. Тут на помощь приходит docker-compose, который позволяет объединить несколько контейнеров в один сервис. Таким образом, например, можно создать приложение и положить его в контейнер, а базу данных, как отдельный сервис, поместить в другой контейнер, и с помощью docker-compose наладить между ними связь.
Также для более серьёзной разработки лучше использовать выделенный виртуальный сервер (VPS): он даёт гораздо больше гибкости и свободы, чем тот же AWS. А самое главное, он более приближён к «боевой» разработке. Схема работы тут будет даже проще, чем с AWS: вам просто нужно установить Docker, спуллить образ с Docker Hub и запустить его.
Вынуждены разочаровать тех, кто представляет ботов, как инструмент исключительно для автоответов и искусственной активности. Думайте о Telegram боте как об автоматизированной учетной записи, которая может выполнять для вас некоторые действия. Например, вы хотите поделиться ссылкой YouTube в групповом чате, но у вас пока нет ссылки.
Без бота это выглядело бы так:
- Вы открываете в веб-браузере YouTube.
- Ищете видео, которым хотите поделиться.
- Выбираете общий доступ.
- Возвращаетесь в мессенджер и, наконец, делитесь ссылкой.
Конечно, большинство из нас привыкло к вышеуказанному алгоритму, и это неплохо работает. Однако…
С ботом:
- Вы находитесь в мессенджере.
- Вводите @vid, а затем видео, которым хотите поделиться.
И это всего лишь одна из возможностей ботов. Разработчики Telegram проделали отличную работу и позволили пользователям создавать своих собственных ботов. Отвечая на вопрос, почему это может быть интересно, я могу сказать, что это самый простой способ получить представление об API.
Прежде всего, зарегистрируйтесь. Рекомендую использовать веб-клиент. Откройте кроссплатформенный мессенджер, найдите @BotFather и запустите чат. Отправьте в сообщении /newbot и следуйте инструкциям. После завершения начальных шагов вы получите:
– токен; – API URL; – ссылку на документацию.
На момент создания бот 100% пассивен. Вам нужно инициализировать разговор. Для этого откройте поиск и введите имя своего бота, а после начните разговор, нажав /start. Введите что-то вроде «Hello». Это сообщение важно, поскольку это первое обновление, которое получит ваш бот.
Если это первый опыт, откройте новую вкладку в своем браузере и используйте /getUpdates” target=”_blank” rel=”noopener noreferrer”>URL-адрес: так вы отправите запрос на сервер Telegram. Пришедший ответ будет в формате JSON и чем-то напоминающим словарь Python. Вы должны увидеть что-то вроде этого:
{"ok":true,"result":[{"update_id":523349956, "message":{"message_id":51,"from":{"id":303262877,"first_name":"YourName"},"chat":{"id":303262877,"first_name":"YourName","type":"private"},"date":1486829360,"text":"Hello"}}]}
Если вы откроете документацию и заглянете на раздел /sendMessage, то заметите, что требуется 2 дополнительных параметра: chat_id и text. В строке поиска браузера можно использовать ? для первого параметра и & для остальных. Отправка сообщения будет выглядеть следующим образом:
/sendMessage?chat_id=303262877&text=test
Для ответа от бота замените chat_id на значение, которое получите с вызовом /getUpdates. У нас это 303262877. Текстовый параметр зависит от вас. Запрос должен выглядеть так:
https://api.telegram.org/bot/sendMessage?chat_id=303262877&text=Hello
Если ваша операционная система – Windows, но еще не установлен Python, скачайте его здесь. Без разницы, будет это версия 2.x или 3.x. Для примера мы будем использовать Python 3.x. На macOS и Linux обе версии уже установлены (либо минимум Python 2.x), поэтому нет необходимости дополнительно скачивать что-либо.
Следующий шаг – установка системы управления пакетами pip. Для Python 2.7.9 и выше, а также Python 3.4 и выше они уже предустановленны (равно как и для операционных систем macOS/Linux). Если нужно, вы всегда можете проверить это, используя в терминале команду pip –version. При отсутствии данной системы установите ее с помощью команды:
$ sudo apt-get install python-pip.
Интересная штука: разные версии Python работают с разными pip. Для обладателей macOS подойдет эта инструкция. Если же у вас ОС Windows, загрузите get-pip.py, откройте cmd, перейдите к скачанным файлам (директория) и выполните следующее:
$ python get-pip.py
Это было самое сложное. Осталось воспользоваться pip и установить пакет requests:
$ pip install requests
Дополнительно можно скачать PyCharm, хотя этот шаг и не относится к обязательным.
Если принцип API понятен, и у вас есть все необходимые инструменты, давайте создадим скрипт Python, который будет проверять наличие обновлений и отвечать на них желаемым текстом.
Прежде всего, наш Telegram бот должен проверять наличие обновлений. Сообщение можно рассматривать как самое последнее из них. Так или иначе, getUpdates вернет все обновления за последние 24 часа. Давайте создадим небольшой скрипт, чтобы получить последнее обновление:
import requests url = "https://api.telegram.org/bot/" def get_updates_json(request): response = requests.get(request + 'getUpdates') return response.json() def last_update(data): results = data['result'] total_updates = len(results) - 1 return results[total_updates]
Словарь обновлений состоит из двух элементов – «ok» и «results». Нам нужен второй, который представляет собой список всех обновлений за последние 24 часа. Здесь вы можете посмотреть дополнительную информацию о библиотеке запросов. Основная идея заключается в том, что всякий раз, когда вам нужно получать, обновлять или удалять информацию на сервере, вы отправляете запрос и принимаете ответ.
Следующий шаг – добавление еще 2-х функций. Первая получит chat_id от обновления, а вторая отправит сообщение:
def get_chat_id(update): chat_id = update['message']['chat']['id'] return chat_id def send_mess(chat, text): params = {'chat_id': chat, 'text': text} response = requests.post(url + 'sendMessage', data=params) return response chat_id = get_chat_id(last_update(get_updates_json(url))) send_mess(chat_id, 'Your message goes here')
Помните, как мы привязывали параметры с помощью ? и &? Вы можете сделать то же самое, добавив dict в качестве второго необязательного параметра для запросов get/post.
Telegram скрипт готов
Однако он еще далек от идеала. Главный недостаток заключается в том, что вам нужно запускать скрипт каждый раз, когда вы хотите обменяться сообщениями с ботом. Давайте исправим это. Чтобы заставить нашего бота слушать сервер для получения обновлений, необходимо запустить главный цикл. Добавьте from time import sleep после import requests и замените 2 последние строки на:
def main(): update_id = last_update(get_updates_json(url))['update_id'] while True: if update_id == last_update(get_updates_json(url))['update_id']: send_mess(get_chat_id(last_update(get_updates_json(url))), 'test') update_id += 1 sleep(1) if __name__ == '__main__': main()
Хотя мы добавили «тайм-аут» в 1 секунду, приведенный выше пример должен использоваться только в целях тестирования, поскольку он использует частые опросы. Это не очень хорошо для серверов Telegram. Есть еще два способа получить обновления через API – вебхуки и длинные опросы. Но так как мы проверяем обновления с использованием метода getUpdates, запросы будут частыми.
Поскольку мы использовали основной цикл, следует переключиться на длинные опросы. Изменим первую функцию, добавив параметр timeout. Тайм-аут сам по себе не сделает проверку скрипта для обновления реже. Кроме того, тайм-аут будет работать только в том случае, если последние обновления отсутствуют. Для отметки просмотренных обновлений нужно добавить параметр offset:
def get_updates_json(request): params = {'timeout': 100, 'offset': None} response = requests.get(request + 'getUpdates', data=params) return response.json()
Теперь бот должен работать нормально, но немного изменим код
Неплохо было бы инкапсулировать использованные функции в класс. Модифицированная версия скрипта будет выглядеть таким образом:
import requests import datetime class BotHandler: def __init__(self, token): self.token = token self.api_url = "https://api.telegram.org/bot{}/".format(token) def get_updates(self, timeout=30): method = 'getUpdates' params = {'timeout': timeout} resp = requests.get(self.api_url + method, params) result_json = resp.json()['result'] return result_json def send_message(self, chat_id, text): params = {'chat_id': chat_id, 'text': text} method = 'sendMessage' resp = requests.post(self.api_url + method, params) return resp def get_last_update(self): get_result = self.get_updates() if len(get_result) > 0: last_update = get_result[-1] else: last_update = get_result[len(get_result)] return last_update
Ну и последний штрих – объявить переменные и научить нашего бота некоторым манерам. Идея состоит в том, чтобы сделать Telegram бота, который будет приветствовать вас раз в день. В зависимости от времени суток сообщение должно быть разным. Если вы хотите попробовать этот скрипт, добавьте строку import datetime после import requests , а также дополните скрипт данным кодом:
greet_bot = BotHandler(token) greetings = ('hello', 'hi', 'greetings', 'sup') now = datetime.datetime.now() def main(): new_offset = None today = now.day hour = now.hour while True: greet_bot.get_updates(new_offset) last_update = greet_bot.get_last_update() last_update_id = last_update['update_id'] last_chat_text = last_update['message']['text'] last_chat_id = last_update['message']['chat']['id'] last_chat_name = last_update['message']['chat']['first_name'] if last_chat_text.lower() in greetings and today == now.day and 6 <= hour < 12: greet_bot.send_message(last_chat_id, 'Good Morning {}'.format(last_chat_name)) today += 1 elif last_chat_text.lower() in greetings and today == now.day and 12 <= hour < 17: greet_bot.send_message(last_chat_id, 'Good Afternoon {}'.format(last_chat_name)) today += 1 elif last_chat_text.lower() in greetings and today == now.day and 17 <= hour < 23: greet_bot.send_message(last_chat_id, 'Good Evening {}'.format(last_chat_name)) today += 1 new_offset = last_update_id + 1 if __name__ == '__main__': try: main() except KeyboardInterrupt: exit()</pre> Теперь у вас есть тысячи различных способов улучшать своего бота! Можно добавить дополнительные кнопки или даже настроить отправку медиафайлов. Последний шаг – это как вишенка на торте, которая позволит сделать из вашего Telegram бота настоящего помощника: его необходимо развернуть на сервере. Скорее всего, у вас нет собственного сервера, и уж вряд ли вы захотите покупать для этого дорогостоящую аппаратуру. К счастью, существует множество облачных сервисов, на которых можно бесплатно разместить приложение. Давайте развернем небольшой скрипт на Heroku. Прежде всего, вам нужна учетная запись на GitHub. Переходите на главную страницу и регистрируйтесь: это обязательный шаг для любого, кто действительно заинтересован в программировании. Помимо учетной записи GitHub, вам также необходимо установить Git. Если у вас Linux, выполните следующую команду: $ sudo apt-get install git-all
Для macOS и Windows можно произвести ручную установку программы. И, конечно же, не забудьте завести аккаунт на Heroku.
Устанавливаем virtualenv, используя команду:
$ pip install virtualenv
Теперь вам нужно немного упорядочить свои файлы. Создайте новую папку, откройте терминал/cmd и перейдите в нее. Для инициализации в созданной папке virtualenv введите:
$ virtualenv my_env
Название не имеет особого значения, однако лучше делать его максимально понятным. Перейдите в папку my_env. Следующий шаг – клонировать ваш репозиторий Git. Введите следующую команду:
$ git clone https://github.com/yourprofilename/yourreponame
Поместите свой скрипт в папку и вернитесь в my_env, чтобы запустить virtualenv.
Windows:
$ scriptsactivate.bat
Linux/macOS:
$ source bin/activate
При успешном запуске virtualenv командная строка должна начинаться с (my_env). Установите модуль requests, перейдя в папку репозитория:
$ pip install requests
Для создания зависимостей Heroku введите:
$ pip freeze > requirements.txt
Создайте файл Procfile. В нем вы найдете инструкции для работы со своим скриптом. Имя должно быть Procfile или Procfile.windows, если это Windows. Не стоит включать в название .txt, .py или любые другие расширения. Содержимое файла должно быть следующим (измените my_bot на название вашего скрипта):
web: python my_bot.py
Добавьте файл __init__.py в свою папку. Файл может быть пустым, но он должен находиться там. Введите такую команду:
$ git init $ git add . $ git commit -m ‘short message that describe changes to commit’ $ git push -u https://github.com/yourusername/nameofrepo
А теперь развернем нашего Telegram бота на Heroku. Потренируемся делать это через консоль. При возникновении проблем, обратитесь к руководству. Для Windows и macOS нужно установить интерфейс командной строки, используя этот гайд. Для Ubuntu используем команды:
$ sudo add-apt-repository "deb https://cliassets.heroku.com/branches/stable/apt ./" $ curl -L https://cli-assets.heroku.com/apt/release.key | $ sudo apt-key add - $ sudo apt-get update $ sudo apt-get install heroku
Интересный факт: на моем домашнем компьютере все прошло без сучка и задоринки, а вот на ноутбуке последний шаг выполнить не удалось. Если вы столкнулись с такой же проблемой, проверьте терминал на наличие всех зависимостей. После выполните команды:
$ heroku login $ heroku create $ git push heroku master $ heroku ps:scale web=1 $ heroku open
С этого момента ваше приложение должно работать на сервере Heroku. Если по какой-либо причине оно не работает, проверьте журналы, используя следующую команду:
$ heroku logs --trail
Коды ошибок можно посмотреть здесь.
Да, используя бесплатный аккаунт, вы столкнетесь с определенными ограничениями. Но даже так после проделанных действий у вас будет полностью функциональный бот.
Приветствую тебя, читатель! Telegram Bot API – это мощный инструмент для вообще чего угодно. Автоматизация действий, работа с пользователями, онлайн-магазины, игры и много чего ещё. В этом учебнике мы научимся писать ботов для Telegram на языке Python.
Сразу оговорюсь: тот бот, который получится в итоге – это лишь прототип, цель всех этих постов – рассказать об основах ботостроения, показать, как можно за короткое время написать простого бота для своих нужд.
Язык программирования будет Python 3, но это не означает, что любители PHP, Ruby и т.д. в пролёте; все основные принципы совпадают. Я не буду особо останавливаться на описании самого языка, желающие могут ознакомиться с документацией по Python здесь.
Подготовка к запуску
Взаимодействие ботов с людьми основано на HTTP-запросах. Чтобы не мучаться с обработкой «сырых» данных, воспользуемся библиотекой pyTelegramBotAPI, которая берет на себя все нюансы отправки и получения запросов, позволяя сконцентрироваться непосредственно на логике. Установка библиотеки предельно простая:
pip install pytelegrambotapi python3
Скриншот из терминала с запущенным интерпретатором Python
Обратите внимание: библиотека называется
pyTelegramBotAPI
, а неtelebot
. Последнюю ставить не нужно!
Теперь можно выйти из режима Python-консоли (Ctrl+Z или Ctrl+D, или exit()
)
Пишем простого echo-бота
Ну, довольно слов, перейдем к делу. В качестве практики к первому уроку, напишем бота, повторяющего присланное текстовое сообщение. Создадим каталог, а внутри него 2 файла: bot.py
и config.py
. Я рекомендую выносить различные константы и настройки в файл config.py
, дабы не загромождать другие. В файл config.py
впишем:
# Токен ненастоящий :) Подставьте свой token = '1234567890:AAE_abCDEFghijKLmNOpqRsTuVWxyz'
Теперь надо научить бота реагировать на сообщения. Напишем обработчик, который будет реагировать на все текстовые сообщения.
@bot.message_handler(content_types=["text"]) def repeat_all_messages(message): # Название функции не играет никакой роли bot.send_message(message.chat.id, message.text)
У читателя возникнет вопрос: зачем там символ “@”? Что это вообще за message_handler
? Дело в том, что после приёма сообщения от Telegram его надо обработать по-разному в зависимости от того, что это за сообщение: текст “привет” или текст “пока”, может быть, вообще стикер или музыка. Первое, что придёт в голову – написать множество конструкций if-then-else
, но такой подход некрасивый и позволяет быстро запутаться. Для решения этой проблемы автор библиотеки pyTelegramBotAPI реализовал механизм хэндлеров, которые используют питоновские декораторы (пока просто запомним это слово). В хэндлере описывается, в каком случае необходимо выполнять ту или иную функцию. Например, хэндлер @bot.message_handler(content_types=["text"])
выполнит нижестоящую функцию, если от Telegram придёт текстовое сообщение, а хэндлер @bot.message_handler(commands=["start"])
сработает при получении команды /start.
Теперь запустим бесконечный цикл получения новых записей со стороны Telegram:
if __name__ == '__main__': bot.infinity_polling()
Функция infinity_polling запускает т.н. Long Polling, бот должен стараться не прекращать работу при возникновении каких-либо ошибок. При этом, само собой, за ботом нужно следить, ибо сервера Telegram периодически перестают отвечать на запросы или делают это с большой задержкой приводя к ошибкам 5xx)
Итак, полный код файла bot.py
выглядит следующим образом:
import config import telebot bot = telebot.TeleBot(config.token) @bot.message_handler(content_types=["text"]) def repeat_all_messages(message): # Название функции не играет никакой роли bot.send_message(message.chat.id, message.text) if __name__ == '__main__': bot.infinity_polling()
Готово! Осталось запустить бота: python3 bot.py
Бот работает
На этом первый урок окончен.
Урок №2 →
ли со статьей или есть что добавить?