Tigran662 13 Member ID: 18 Сообщений: 9 Репутация: 13 Регистрация: 07/29/17 Статус: Offline В сети: 13 часов назад Жалоба Опубликовано 6 августа, 2017 (изменено) 24 июня разработчики Telegram открыли платформу для создания ботов. Новость кого-то обошла стороной Хабр, однако многие уже начали разрабатывать викторины. При этом мало где указаны хоть какие-то примеры работающих ботов.Прежде всего, бот для Telegram — это по-прежнему приложение, запущенное на вашей стороне и осуществляющее запросы к Telegram Bot API. Причем API довольное простое — бот обращается на определенный URL с параметрами, а Telegram отвечает JSON объектом.Рассмотрим API на примере создания тривиального бота: 1. РегистрацияПрежде чем начинать разработку, бота необходимо зарегистрировать и получить его уникальный id, являющийся одновременно и токеном. Для этого в Telegram существует специальный бот — @BotFatherПишем ему /start и получаем список всех его команд. Первая и главная — /newbot — отправляем ему и бот просит придумать имя нашему новому боту. Единственное ограничение на имя — в конце оно должно оканчиваться на «bot». В случае успеха BotFather возвращает токен бота и ссылку для быстрого добавления бота в контакты, иначе придется поломать голову над именем.Для начала работы этого уже достаточно. Особо педантичные могут уже здесь присвоить боту аватар, описание и приветственное сообщение.Не забудьте проверить полученный токен с помощью ссылки api.telegram.org/bot/getMe, говорят, не всегда работает с первого раза. 2. ПрограммированиеСоздавать бота буду на Python3, однако благодаря адекватности этого языка алгоритмы легко переносятся на любой другой.Telegram позволяет не делать выгрузку сообщений вручную, а поставить webHook, и тогда они сами будут присылать каждое сообщение. Для Python, чтобы не заморачиваться с cgi и потоками, удобно использовать какой-нибудь реактор, поэтому я для реализации выбрал tornado.web. (для GAE удобно использовать связку Python2+Flask) Каркас бота: URL = "https://api.telegram.org/bot%s/" % BOT_TOKEN MyURL = "https://example.com/hook" api = requests.Session() application = tornado.web.Application([ (r"/", Handler), ]) if __name__ == '__main__': signal.signal(signal.SIGTERM, signal_term_handler) try: set_hook = api.get(URL + "setWebhook?url=%s" % MyURL) if set_hook.status_code != 200: logging.error("Can't set hook: %s. Quit." % set_hook.text) exit(1) application.listen(8888) tornado.ioloop.IOLoop.current().start() except KeyboardInterrupt: signal_term_handler(signal.SIGTERM, None) Здесь мы при запуске бота устанавливаем вебхук на наш адрес и отлавливаем сигнал выхода, чтобы вернуть поведение с ручной выгрузкой событий.Приложение торнадо для обработки запросов принимает класс tornado.web.RequestHandler, в котором и будет логика бота. class Handler(tornado.web.RequestHandler): def post(self): try: logging.debug("Got request: %s" % self.request.body) update = tornado.escape.json_decode(self.request.body) message = update['message'] text = message.get('text') if text: logging.info("MESSAGE\t%s\t%s" % (message['chat']['id'], text)) if text[0] == '/': command, *arguments = text.split(" ", 1) response = CMD.get(command, not_found)(arguments, message) logging.info("REPLY\t%s\t%s" % (message['chat']['id'], response)) send_reply(response) except Exception as e: logging.warning(str(e)) Здесь CMD — словарь доступных команд, а send_reply — функция отправки ответа, которая на вход принимает уже сформированный объект Message.Собственно, её код довольно прост: def send_reply(response): if 'text' in response: api.post(URL + "sendMessage", data=response) Теперь, когда вся логика бота описана можно начать придумывать ему команды. 3. КомандыПерво-наперво, необходимо соблюсти соглашение Telegram и научить бота двум командам: /start и /help: def help_message(arguments, message): response = {'chat_id': message['chat']['id']} result = ["Hey, %s!" % message["from"].get("first_name"), "\rI can accept only these commands:"] for command in CMD: result.append(command) response['text'] = "\n\t".join(result) return response Структура message['from'] — это объект типа User, она предоставляет боту информацию как id пользователя, так и его имя. Для ответов же полезнее использовать message['chat']['id'] — в случае личного общения там будет User, а в случае чата — id чата. В противном случае можно получить ситуацию, когда пользователь пишет в чат, а бот отвечает в личку.Команда /start без параметров предназначена для вывода информации о боте, а с параметрами — для идентификации. Полезно её использовать для действий, требующих авторизации.После этого можно добавить какую-нибудь свою команду, например, /base64: def base64_decode(arguments, message): response = {'chat_id': message['chat']['id']} try: response['text'] = b64decode(" ".join(arguments).encode("utf8")) except: response['text'] = "Can't decode it" finally: return response Для пользователей мобильного Telegram, будет полезно сказать @BotFather, какие команды принимает наш бот: I: /setcommands BotFather : Choose a bot to change the list of commands. I: @******_bot BotFather: OK. Send me a list of commands for your bot. Please use this format: command1 - Description command2 - Another description I: whoisyourdaddy - Information about author base64 - Base64 decode BotFather: Success! Command list updated. /help C таким описанием, если пользователь наберет /, Telegram услужливо покажет список всех доступных команд. 4. Свобода.Как можно было заметить, Telegram присылает сообщение целиком, а не разбитое, и ограничение на то, что команды начинаются со слеша — только для удобства мобильных пользователей. Благодаря этому можно научить бота немного говорить по-человечески.UPD: Как верно подсказали, такое пройдет только при личном общении. В чатах боту доставляются только сообщения, начинающиеся с команды (/) (https://core.telegram.org/bots#privacy-mode) All messages that start with a slash ‘/’ (see Commands above) Messages that mention the bot by username Replies to the bot's own messages Service messages (people added or removed from the group, etc.) Чтобы бот получал все сообщения в группах пишем @BotFather команду /setprivacy и выключаем приватность. Для начала в Handler добавляем обработчик: if text[0] == '/': ... else: response = CMD["<speech>"](message) logging.info("REPLY\t%s\t%s" % (message['chat']['id'], response)) send_reply(response) А потом в список команд добавляем псевдо-речь: RESPONSES = { "Hello": ["Hi there!", "Hi!", "Welcome!", "Hello, {name}!"], "Hi there": ["Hello!", "Hello, {name}!", "Hi!", "Welcome!"], "Hi!": ["Hi there!", "Hello, {name}!", "Welcome!", "Hello!"], "Welcome": ["Hi there!", "Hi!", "Hello!", "Hello, {name}!",], } def human_response(message): leven = fuzzywuzzy.process.extract(message.get("text", ""), RESPONSES.keys(), limit=1)[0] response = {'chat_id': message['chat']['id']} if leven[1] < 75: response['text'] = "I can not understand you" else: response['text'] = random.choice(RESPONSES.get(leven[0])).format_map( {'name': message["from"].get("first_name", "")} ) return response Здесь эмпирическая константа 75 относительно неплохо отражает вероятность того, что пользователь всё-таки хотел сказать. А format_map — удобна для одинакового описания строк как требующих подстановки, так и без нее. Теперь бот будет отвечать на приветствия и иногда даже обращаться по имени. 5. Не текст.Боты, как и любой нормальный пользователь Telegram, могут не только писать сообщения, но и делиться картинками, музыкой, стикерами.Для примера расширим словарь RESPONSES: RESPONSES["What time is it?"] = ["<at_sticker>", "{date} UTC"] И будем отлавливать текст if response['text'] == "<at_sticker>": response['sticker'] = "BQADAgADeAcAAlOx9wOjY2jpAAHq9DUC" del response['text'] Видно, что теперь структура Message уже не содержит текст, поэтому необходимо модифицировать send_reply: def send_reply(response): if 'sticker' in response: api.post(URL + "sendSticker", data=response) elif 'text' in response: api.post(URL + "sendMessage", data=response) И все, теперь бот будет время от времени присылать стикер вместо времени: 6. ВозможностиБлагодаря удобству API и быстрому старту боты Telegram могут стать хорошей платформой для автоматизации своих действий, настройки уведомлений, создания викторин и task-based соревнований (CTF, DozoR и прочие).Вспоминая статью про умный дом, могу сказать, что теперь извращений меньше, а работа прозрачнее.7. ОграниченияК сожалению, на данный момент существует ограничение на использование webHook — он работает только по https и только с валидным сертификатом, что, например для меня пока критично за счет отсутствия поддержки сертифицирующими центрами динамических днс. К счастью, Telegram также умеет работать и по ручному обновлению, поэтому не меняя кода можно создать еще одну службу Puller, которая будет выкачивать их и слать на локальный адрес: while True: r = requests.get(URL + "?offset=%s" % (last + 1)) if r.status_code == 200: for message in r.json()["result"]: last = int(message["update_id"]) requests.post("http://localhost:8888/", data=json.dumps(message), headers={'Content-type': 'application/json', 'Accept': 'text/plain'} ) else: logging.warning("FAIL " + r.text) time.sleep(3) P.S. По пункту 7 нашел удобное решение — размещение бота не у себя, а на heroku, благо все имена вида *.herokuapp.com защищены их собственным сертификатом.UPD: Telegram улучшили Бот Апи, из-за чего, теперь не обязательно иметь отдельную функцию для отправки сообщений при установленном вебхуке, а в ответ на POST запрос можно отвечать тем же сформированным JSON с ответным сообщением, где одно из полей устанавливается как ч 'method': 'sendMessage' (или любой другой метод, используемый ботом). Изменено 6 августа, 2017 пользователем Tigran662 Влад и Radells 2 Игрок 27.08.2015 - хх.хх.хххх PixelMoCT 4.04.2017 - хх.хх.хххх RetroMoCT 20.10.2017 - хх.хх.хххх SterBen.Ru Куратор IT-раздела хх.хх.хххх - хх.хх.хххх Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Рекомендуемые сообщения