어푸푸

코레일 자동 예약 매크로 제작기 #4 본문

잡동사니/자동화

코레일 자동 예약 매크로 제작기 #4

예수님부처 2018. 3. 31. 15:21

텔레그램의 API인 MessageLoop 함수를 사용하면 챗 봇으로 메시지가 올 때마다 행동을 하게 할 수 있습니다. 그러나 MessageLoop 함수는 자유롭게 사용하기에 몇 가지 제한 사항이 있습니다. 그러나 MessageLoop 함수는 getUpdates 함수를 계속해서 호출하는 함수이기 때문에 GetUpdates 함수를 직접 사용하게 되면 프로그램을 보다 자유롭게 작성할 수 있습니다.

GetUpdates 함수는 '사용자가 확인하지 않은' Update 오브젝트 배열을 반환해줍니다. (API를 정확히 숙지하지 않고) GetUpdates 함수를 사용하게 되면 처음에 겪는 혼란이 있습니다. 과연 무엇이 '사용자가 확인하지 않은' 메세지냐는 것이죠. getUpdates 함수를 여러 번 호출하고 호출해도 확인했던 메세지가 Update 오브젝트의 형태로 반환됩니다. getUpdates 함수가 '사용자가 확인한 메세지'를 어떻게 처리하는지를 숙지하지 않았기 때문에 생기는 문제입니다.

Update 오브젝트는 여러 개의 딕셔너리를 가지고 있습니다. 이렇게 말하는 것이 맞는 표현인지는 모르겠지만요. 이 중 개인적으로 생각할 때 가장 중요한 것은 'update_id'와 'msg'입니다. 음식점에 가면 msg를 뿌리죠. 제 6의 맛인 감칠맛을 더해주는 msg는 텔레그램 챗 봇 프로그래밍에서도 아주 중요한 것입니다. 심심해서 아무 말이나 써봤습니다. 아래 그림은 텔레그램 홈페이지에서 getUpdates 함수의 부분을 캡처한 것입니다. 이 때 입력 파라미터인 offset 쪽의 내용을 보시면 무엇이 '사용자에게 확인된 메시지'인지가 서술되어 있습니다. 이를 다시 옮겨쓰자면 offset으로 들어오는 숫자보다 작은 값의 update_id를 가지는 Update 오브젝트는 '사용자에게 확인된 메시지'로 간주됩니다. 이를 이용하면 이미 확인한 메시지는 다음에 getUpdates 함수를 호출할 때 반환되지 않습니다.

 

<텔레그램 챗 봇 API 함수 getUpdates >

이를 이용해서 언제나 가위바위보를 사용자에게 패배하는 접대용 가위바위보 챗 봇을 만들어봅시다. 이를 구현하기 위해서 getUpdates 함수를 사용합니다. bot.py의 소스 코드는 다음과 같습니다. 이 챗 봇은 사용자가 가위 바위 보 중에 한 메세지를 보내면 무료로 져줍니다.

#	첫 번째 줄 들여쓰기 뭐야..
import sys
import time
import telepot

#----------------------------------------------------------
def Determine(bot, unread):
    n = len(unread)

    for i in range(n):
        msg = unread[i]['message']
        content_type, chat_type, chat_id = telepot.glance(msg)
        print(content_type, chat_type, chat_id, msg['text'])
        if(msg['text'] == '가위'):
            bot.sendMessage(chat_id, '보')

        if(msg['text'] == '바위'):
            bot.sendMessage(chat_id, '가위')

        if(msg['text'] == '보'):
            bot.sendMessage(chat_id, '바위')


TOKEN = sys.argv[1]  # get token from command-line
bot = telepot.Bot(TOKEN)

print ('Listening...')
# Keep the program running.
update_id = 0
while 1:
    unread = bot.getUpdates(offset=update_id + 1)
    if unread:
        update_id = unread[len(unread)-1]['update_id']
    else:
        update_id = 0
    
    if unread:
        Determine(bot, unread)

    time.sleep(0.5)

<이 챗 봇은 무료로 져줍니다>

위 그림에서 보시면 메세지가 여러 개가 오더라도 limit에 update_id+1를 넘겨주었기 때문에 쌓이지 않습니다. 게다가 무료로 잘 져줍니다. 의도된대로 잘 작동하고 있는 셈이죠. 위와 같은 예제의 프로그램 구조를 통하면 매크로를 구현할 수 있습니다.

외부 모듈 및 라이브러리를 사용해서 프로그램을 작성하다보면 문제점이 생깁니다. 바로 예상치 못한 오류가 날 수 있다는 것이죠. 코레일 자동 예약 매크로 프로그램과 같은 프로그램은 언제나 실행되어있어야 하는 프로그램입니다. 예상치 못한 상황으로 인해 프로그램이 종료되면 아무리 매크로 프로그램을 잘 짜놓아도 소용이 없습니다. 특히 사용자가 자리에서 부재중인 경우에는 더욱 그렇죠. 원격으로 작업을 해결하려고 프로그램을 구성했는데 프로그램 자체가 종료되는 경우라면 의미가 없어집니다.

실제로 작성된 매크로 프로그램을 사용하다보니 많은 경우에 예상하지 못한 에러로 종료가 되었습니다. 대표적으로 오타로 인해 예상치 못한 입력이 들어온 경우나 URLLIB3 라이브러리에서 대기 시간 초과로 프로그램이 종료되는 경우가 종종 발생하였습니다. 이러한 문제는 배치파일을 재귀적으로 실행하여 해결할 수 있습니다. 즉 Run.bat 파일을 Run.bat 파일에서 실행하면 프로그램이 예상치못하게 종료가 되는 동시에 다시 실행되므로 예상치 못한 종료의 늪에서 빠져나올 수 있게 됩니다. 

<종종 외부 라이브러리에서 예상치 못한 문제로 종료가 되는 경우가 발생한다>

<이 프로그램은 종료되도 자동으로 실행이 됩니다>

 

코레일 자동 예약 매크로 제작기 #5에서 계속...