본문 바로가기
Back-end/Python

[Telegram] 무작정 시작하기 (3) - Button Message

by 허도치 2020. 1. 30.

2020/01/30 - [Back-end/Python] - [Telegram] 무작정 시작하기 (1) - 설치 및 실행

2020/01/30 - [Back-end/Python] - [Telegram] 무작정 시작하기 (2) - CommandHandler

 

 

  지난 포스트에서는 명령어를 입력하여 이벤트를 실행하는 방법에 대해서 알아보았다. PC를 이용하는 경우에는 명령어를 입력하는게 크게 불편하지 않지만, 스마트폰을 이용하는 경우 다소 불편할 수 있다. 그래서, 봇에서는 버튼을 이용하여 조작할 수 있는 기능을 제공한다. 이번 포스트에서는 이 기능을 활용하여 간단한 예제를 만들어 보도록 하겠다.

 

 

1. Message에 버튼 추가하기.

   1-1. 소스 작성.

         - buttons_bot.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#buttons_bot.py
import time
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater
from telegram.ext import CommandHandler
 
BOT_TOKEN='672768316:AAHXpYmnMzGp_eH0i-juikUFU6q9y78CBhA'
 
updater = Updater( token=BOT_TOKEN, use_context=True )
dispatcher = updater.dispatcher
 
def cmd_task_buttons(update, context):
    task_buttons = [[
        InlineKeyboardButton( '1.네이버 뉴스', callback_data=1 )
        , InlineKeyboardButton( '2.직방 매물', callback_data=2 )
    ], [
        InlineKeyboardButton( '3.취소', callback_data=3 )
    ]]
    
    reply_markup = InlineKeyboardMarkup( task_buttons )
    
    context.bot.send_message(
        chat_id=update.message.chat_id
        , text='작업을 선택해주세요.'
        , reply_markup=reply_markup
    )
    
task_buttons_handler = CommandHandler( 'tasks', cmd_task_buttons )
 
dispatcher.add_handler( task_buttons_handler )
 
updater.start_polling()
updater.idle()
cs

          - 3 ln: Message에 버튼을 추가하기위한 클래스.

            * [ InlineKeyboardButton ]: 버튼을 생성하는 기능.

            * [ InlineKeyboardMarkup ]: 레이아웃을 구성(Markup)하는 기능.

          - 9~10 ln: 봇이 받은 Message를 감시하기 위한 Dispatcher 생성.

          - 12 ln: tasks 명령어 이벤트.

          - 13~18 ln: 2차원 배열에 InlineKeyboardButton을 생성하여 저장.

            * [ [ 컬럼1, 컬럼2 ], [ 컬럼1 ] ]

            * 각 행의 컬럼의 수가 일치하지 않는 경우 가장 큰 행의 컬럼수에 맞게 자동으로 병합됨.

            * InlineKeyboardButton( 버튼명, callback_data=반환값 )

          - 20 ln: Message의 레이아웃을 구성.

            * InlineKeyboardMarkup( 2차원 배열 )

          - 22~26 ln: Markup된 버튼을 Message에 담아서 발송.

            * [ reply_markup ]: Message의 응답을 받을 수 있는 버튼이나 키보드의 Markup을 변경할 때 사용.

          - 28~30 ln: [ /tasks ]가 입력되었을 때 이벤트를 발생시키는 Handler생성.

          - 32~33 ln: 봇의 메시지 감시 시작.

 

   1-2. 실행.

         > python buttons_bot.py

 

   1-3. 실행 결과.

          - [ /tasks ]를 입력하면 봇으로부터 버튼과 함께 메시지를 받을 수 있음.

          - 지금은 Callback을 만들지 않았기 때문에 눌러도 반응이 없음.

 

 

2. 버튼에 Callback 추가하기.

   2-1. 소스 수정.

         - buttons_bot.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#buttons_bot.py
import time
from telegram import ChatAction
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater
from telegram.ext import CommandHandler, CallbackQueryHandler
 
BOT_TOKEN='672768316:AAHXpYmnMzGp_eH0i-juikUFU6q9y78CBhA'
 
updater = Updater( token=BOT_TOKEN, use_context=True )
dispatcher = updater.dispatcher
 
def cmd_task_buttons(update, context):
    task_buttons = [[
        InlineKeyboardButton( '1.네이버 뉴스', callback_data=1 )
        , InlineKeyboardButton( '2.직방 매물', callback_data=2 )
    ], [
        InlineKeyboardButton( '3.취소', callback_data=3 )
    ]]
    
    reply_markup = InlineKeyboardMarkup( task_buttons )
    
    context.bot.send_message(
        chat_id=update.message.chat_id
        , text='작업을 선택해주세요.'
        , reply_markup=reply_markup
    )
    
def cb_button(update, context):
    query = update.callback_query
    data = query.data
    
    context.bot.send_chat_action(
        chat_id=update.effective_user.id
        , action=ChatAction.TYPING
    )
    context.bot.edit_message_text(
        text='[{}] 작업을 완료하였습니다.'.format( data )
        , chat_id=query.message.chat_id
        , message_id=query.message.message_id
    )
    
task_buttons_handler = CommandHandler( 'tasks', cmd_task_buttons )
button_callback_handler = CallbackQueryHandler( cb_button )    
 
dispatcher.add_handler( task_buttons_handler )
dispatcher.add_handler( button_callback_handler )
 
updater.start_polling()
updater.idle()
cs

         - 3 ln: 채팅방에서 봇의 행동을 표시하기 위한 클래스 추가.

         - 5 ln: Callback Handler를 만들기 위한 CallbackQueryHandler 클래스 추가.

         - 29 ln: Callback 이벤트.

         - 30 ln: Callback을 호출한 메시지의 정보를 담고 있는 객체.

         - 31 ln: InlineKeyboardButton에서 callback_data로 정의된 값이 반환됨.

         - 33~35 ln: Message를 입력중인 상태를 채팅방에 표시.

           * [ send_chat_action ]: TYPING은 메시지를 입력중인 상태를 나타내며, 이외에 Upload나 Find와 같은 상태들을 나타낼 수 있음. 더 자세한 내용은 공식 문서를 참조.

         - 37~40 ln: Callback을 호출한 Message를 새로운 Message로 변경.

           * [ edit_message_text ]: 기존에 전송된 메시지를 새로운 메시지로 변경하는 기능.

         - 44, 47 ln: Callback Handler 생성.

 

   2-2. 실행.

         > python buttons_bot.py

 

   2-3. 실행 결과.

          - [ /tasks ] 명령어로 받은 버튼(1.네이버뉴스)을 클릭하면 위와 같은 결과를 얻을 수 있음.

          - 상단에 [ 입력 중 ]이라는 문구가 노출되는 것을 볼 수 있음.

 

 

3. 최종 소스.

   3-1. 소스 수정.

         - buttons_bot.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#buttons_bot.py
import time
from telegram import ChatAction
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater, Filters
from telegram.ext import CommandHandler, MessageHandler, CallbackQueryHandler
 
BOT_TOKEN='672768316:AAHXpYmnMzGp_eH0i-juikUFU6q9y78CBhA'
 
updater = Updater( token=BOT_TOKEN, use_context=True )
dispatcher = updater.dispatcher
 
def cmd_task_buttons(update, context):
    task_buttons = [[
        InlineKeyboardButton( '1.네이버 뉴스', callback_data=1 )
        , InlineKeyboardButton( '2.직방 매물', callback_data=2 )
    ], [
        InlineKeyboardButton( '3.취소', callback_data=3 )
    ]]
    
    reply_markup = InlineKeyboardMarkup( task_buttons )
    
    context.bot.send_message(
        chat_id=update.message.chat_id
        , text='작업을 선택해주세요.'
        , reply_markup=reply_markup
    )
    
def cb_button(update, context):
    query = update.callback_query
    data = query.data
    
    context.bot.send_chat_action(
        chat_id=update.effective_user.id
        , action=ChatAction.TYPING
    )
    
    if data == '3':
        context.bot.edit_message_text(
            text='작업이 취소되었습니다.'
            , chat_id=query.message.chat_id
            , message_id=query.message.message_id
        )
    else:
        context.bot.edit_message_text(
            text='[{}] 작업이 진행중입니다.'.format( data )
            , chat_id=query.message.chat_id
            , message_id=query.message.message_id
        )
        
        if data == '1':
            crawl_navernews()
        elif data == '2':
            crawl_zigbang()
        
        context.bot.send_message(
            chat_id=update.effective_chat.id
            , text='[{}] 작업을 완료하였습니다.'.format( data )
        )
    
def crawl_navernews():
    time.sleep( 5 )
    print'네이버에서 뉴스를 수집했다.' )
    
def crawl_zigbang():
    time.sleep( 5 )
    print'직방에서 매물을 수집했다.' )
    
task_buttons_handler = CommandHandler( 'tasks', cmd_task_buttons )
button_callback_handler = CallbackQueryHandler( cb_button )    
 
dispatcher.add_handler( task_buttons_handler )
dispatcher.add_handler( button_callback_handler )
 
updater.start_polling()
updater.idle()
cs

         - 38~67 ln: 각 버튼마다 이벤트를 부여하여 수행하도록 하였음.

 

   3-2. 실행.

         > python buttons_bot.py

 

   3-3. 실행 결과.

         - [ 1.네이버뉴스 ]버튼을 클릭하면 '[1] 작업이 진행중입니다.'라는 Mesage로 변경.

         - 처리가 완료되면 '[1] 작업을 완료하였습니다.'라는 Message를 한번 더 전송.

         - 명령 프롬프트에는 '네이버에서 뉴스를 수집했다.'라는 Log를 출력.

 

 

4. 마치며.

    - 이번 포스트에서는 텔레그램 봇을 활용하는 예제를 다루어보았다. 이번에는 Message에 버튼을 달아서 보냈는데 ReplyKeyboardMarkup을 사용하면 사용자의 입력창에 버튼을 만들 수도 있다. 잘만 이용하면 게임도 충분히 만들 수 있을 것이라고 생각된다.

    - 텔레그램 봇은 간단하지만 잘 이용하면 강력한 기능으로 만들 수 있기 때문에 익혀두면 써먹을데가 많을 것 같다.

 

댓글