Telegram бот в приватном канале
Пишем систему оповещения через приватный канал в Telegram. В предыдущей статье я писал как можно совместить несовместимое, то есть асинхронное приложение с синхронной работой. В задаче оповещений тоже есть несколько тонкостей. Например задача по поимке chat id приватного канала. Обратимся к хорошо известному tornado, так как приложение будет работать по http. То есть мы будем наше сообщение отправлять в виде аргумента http запроса к телеграм боту. tornado будет слушать 80 порт и обрабатывать запросы, и передавать сообещения в наш приватный канал. Неплохо когда части программы существуют отдельно и развязны между собой посредством какого-то транспорта.
Создаем виртуальное окружение и добавляем следующие необходимые модули:
$ virtuaenv -p python2.7 env
$ source env/bin/activate
(env)$ pip install pyTelegramBotAPI tornado
Тонкости телеграм
При создании канала обязательно запоминаем имя канала @ChannelName
После создания канала и добавления в него бота, мы не можем по имени канала отправить сообщения, нам нужен идентификатор chat_id. Его можно получить используя следующий алгоритм.
- Необходимо создать публичный канал
- Необходимо написать echo бота, который принимает сообщения и выводит их в консоль
- В наш канал надо добавить администратором нашего бота через по поиск по
@имя_бота - Пишем в канеле тестовое сообщение нашему боту
- Смотрим в консоли chat_id и запоминаем его - это идентификатор канала
- Переводим наш канал в приватный
Получим chat id для канала
$ nano telegram.py
# coding: utf8
from telebot import TeleBot
TOKEN = '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11'
if __name__ == "__main__":
bot = TeleBot(TOKEN)
result = bot.send_message(
chat_id='@ChannelName',
text='test_message_text',
reply_markup=''
)
print result.chat.id
bot.polling()
После запуска бота мы получим chat_id
(env) $ python telegram.py
-1001100397557
Напишем бота рассылок
Переводим канал в приватный, если это необходимо и теперь можно написать бота который будет оповещать. Так как по имени в приватный канал не получится отправлять сообщение.
$ nano telegram.py
# coding: utf8
from telebot import TeleBot
import tornado
from tornado.httpserver import HTTPServer
from tornado.ioloop import PeriodicCallback, IOLoop
from tornado.web import RequestHandler
CHAT_ID = -1001100397557
TOKEN = '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11'
SECRET = 'FBNbCyjVRU'
class SendMessageHandler(RequestHandler):
def initialize(self, bot):
self.bot = bot
def get(self):
message = self.get_argument('message')
secret = self.get_argument('secret')
if message and secret and secret == SECRET:
self.bot.send_message(
chat_id=CHAT_ID,
text=message,
reply_markup=''
)
class BotPeriodicCallback(PeriodicCallback):
def __init__(self, bot, callback_time, io_loop=None):
if callback_time <= 0:
raise ValueError("Periodic callback must have a positive callback_time")
self.callback_time = callback_time
self.io_loop = io_loop or IOLoop.current()
self._running = False
self._timeout = None
self.bot = bot
def bot_callback(self, timeout=20):
if self.bot.skip_pending:
self.bot.skip_pending = False
updates = self.bot.get_updates(offset=(self.bot.last_update_id + 1), timeout=timeout)
self.bot.process_new_updates(updates)
def _run(self):
if not self._running:
return
try:
return self.bot_callback()
except Exception:
self.io_loop.handle_callback_exception(self.bot_callback)
finally:
self._schedule_next()
def main():
bot = TeleBot(TOKEN)
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
bot.reply_to(message, u"Добро пожаловать! Вас приветствует робот рассылок!")
@bot.message_handler(func=lambda message: True)
def echo_all(message):
bot.reply_to(message, 'По вопросам связанным с Telegram обращайтесь по телефону +7 950 027 66 17')
ioloop = tornado.ioloop.IOLoop.instance()
BotPeriodicCallback(bot, 1000, ioloop).start()
host = '0.0.0.0'
http_port = 8087
http_server = HTTPServer(
tornado.web.Application([
(r'/send_message/(.*)/', SendMessageHandler, {'bot': bot}),
], debug=True)
)
http_server.listen(http_port, host)
print("HTTP listening on %s:%d..." % (host, http_port))
ioloop.start()
if __name__ == "__main__":
main()
Таким образом мы можем отправить сообщение в наш канал сделав простой GET запрос.
http://<host>:8087/send_message/?secret=<secret>&message=<message>
Все готово!