Python Telegram Bot 教學 (by 陳達仁) === ## BotFather 找 [@BotFather](https://t.me/BotFather) 申請一個 Bot。 1. /newbot 2. 輸入名稱 3. 輸入 username 4. 記下 token ![New Bot](https://i.imgur.com/NqKAsLK.png) ## hello, world 執行這個程式,注意 `'YOUR TOKEN HERE'` 的地方請填入前面得到的 Token。 ```python= from telegram.ext import Updater, CommandHandler def hello(bot, update): update.message.reply_text( 'hello, {}'.format(update.message.from_user.first_name)) updater = Updater('YOUR TOKEN HERE') updater.dispatcher.add_handler(CommandHandler('hello', hello)) updater.start_polling() updater.idle() ``` 用 Bot 的 username 或是 BotFather 給的連結可以找到前面建立的 Bot。 對它輸入 `/hello`。 ![hello](https://i.imgur.com/eeRxLC3.png) ## Command Handler 可從 update 獲得的資訊 - update - update_id - message - message_id - from_user:發訊人 - id - first_name - last_name - full_name - username - chat:訊息所在的聊天室 - id - type - text:訊息內容 [更多資訊](https://python-telegram-bot.readthedocs.io/en/stable/telegram.message.html) ## 傳訊息 - bot.send_message(chat_id, text) - update.message.reply_text(text):Shortcut for `bot.send_message(update.message.chat_id, text)` [更多功能](https://python-telegram-bot.readthedocs.io/en/stable/telegram.bot.html) ## 範例 - 語錄 Bot ```python= import random, os from telegram.ext import Updater, CommandHandler # 把語錄檔案載入 if os.path.exists('sentences.txt'): with open('sentences.txt') as FILE: sentences = [sentence.strip() for sentence in FILE] else: sentences = [] def add(bot, update): print('from user:', update.message.from_user.id) # 限制只有特定人才能新增語錄 # if update.message.from_user.id == YOUR_USER_ID_HERE: if True: sentence = update.message.text[5:].replace('\n', ' ') sentences.append(sentence) with open('sentences.txt', 'a') as FILE: print(sentence, file=FILE) update.message.reply_text('已加入:' + sentence) def say(bot, update): if sentences: update.message.reply_text(random.choice(sentences)) else: update.message.reply_text('I have no words.') updater = Updater('YOUR TOKEN HERE') updater.dispatcher.add_handler(CommandHandler('add', add)) updater.dispatcher.add_handler(CommandHandler('say', say)) updater.start_polling() updater.idle() ``` ![語錄](https://i.imgur.com/G0MnIp1.png) ## 互動按鈕 `send_message` 加上 `reply_markup = InlineKeyboardMarkup(...)` 就會在該訊息附上按鈕。 ```python= from telegram.ext import Updater, CommandHandler from telegram import InlineKeyboardMarkup, InlineKeyboardButton def start: bot.send_message(chat_id, '參考資料', reply_markup = InlineKeyboardMarkup([[ InlineKeyboardButton('課程網站', url = 'https://github.com/mzshieh/pa19spring'), InlineKeyboardButton('Documentation', url = 'https://python-telegram-bot.readthedocs.io/en/stable/index.html')]])) # ... ``` ![](https://i.imgur.com/NCuLrN6.png) 除了 `url` 以外,也可以用 `callback_data` 來讓 Bot 知道哪個按鈕被按了。 ```python= from random import randint from telegram.ext import Updater, CommandHandler, CallbackQueryHandler from telegram import InlineKeyboardMarkup, InlineKeyboardButton def start(bot, update): a, b = randint(1, 100), randint(1, 100) update.message.reply_text('{} + {} = ?'.format(a, b), reply_markup = InlineKeyboardMarkup([[ InlineKeyboardButton(str(s), callback_data = '{} {} {}'.format(a, b, s)) for s in range(a + b - randint(1, 3), a + b + randint(1, 3)) ]])) def answer(bot, update): a, b, s = [int(x) for x in update.callback_query.data.split()] if a + b == s: update.callback_query.edit_message_text('你答對了!') else: update.callback_query.edit_message_text('你答錯囉!') updater = Updater('YOUR TOKEN HERE') updater.dispatcher.add_handler(CommandHandler('start', start)) updater.dispatcher.add_handler(CallbackQueryHandler(answer)) updater.start_polling() updater.idle() ``` ![70 + 90 = ?](https://i.imgur.com/ht4CPIH.png) ![你答對了!](https://i.imgur.com/SXfdpqZ.png) ## Callback Query Handler 可從 update 獲得的資訊 - update - update_id - callback_query - from_user - 略 - message:按鈕依附的 message - 略 - data:建立 InlineKeyboardButton 時傳入的 callback_data [更多資訊](https://python-telegram-bot.readthedocs.io/en/stable/telegram.callbackquery.html) ## 回應 Callback Query - bot - answer_callback_query(callback_query_id, text):會顯示文字在畫面中間。 - edit_message_text(chat_id = string, message_id = string, text):修改文字,會同時清除按鈕。 - update.callback_query - answer(text):Shortcut for `bot.answer_callback_query(update.callback_query.id, text)` - edit_message_text(text):Shortcut for `bot.edit_message_text(chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text` [更多功能](https://python-telegram-bot.readthedocs.io/en/stable/telegram.bot.html) ## 範例 - 剪刀石頭布 ```python= import random from telegram.ext import Updater, CommandHandler, CallbackQueryHandler from telegram import InlineKeyboardMarkup, InlineKeyboardButton hands = ['rock', 'paper', 'scissors'] emoji = { 'rock': '👊', 'paper': '✋', 'scissors': '✌️' } def start(bot, update): update.message.reply_text('剪刀石頭布!', reply_markup = InlineKeyboardMarkup([[ InlineKeyboardButton(emoji, callback_data = hand) for hand, emoji in emoji.items() ]])) def judge(mine, yours): if mine == yours: return '平手' elif (hands.index(mine) - hands.index(yours)) % 3 == 1: return '我贏了' else: return '我輸了' def play(bot, update): try: mine = random.choice(hands) yours = update.callback_query.data update.callback_query.edit_message_text('我出{},你出{},{}!'.format(emoji[mine], emoji[yours], judge(mine, yours))) except Exception as e: print(e) updater = Updater('YOUR TOKEN HERE') updater.dispatcher.add_handler(CommandHandler('start', start)) updater.dispatcher.add_handler(CallbackQueryHandler(play)) updater.start_polling() updater.idle() ``` ![剪刀石頭布!](https://i.imgur.com/WCI88EP.png) ![我輸了!](https://i.imgur.com/Y4cNeFq.png) ## Reference https://python-telegram-bot.readthedocs.io/en/stable/index.html