반응형

이번에는 저번에 만들었던 디스코드 챗봇에 급식 파서를 활용하여

급식을 알려주는 챗봇을 만들도록 하겠습니다.



이전과정

[

디스코드 챗봇 만들기 --> http://mandu-mandu.tistory.com/64

급식 파서 만들기 --> http://mandu-mandu.tistory.com/21

]






코드 작성하기


필요한 모듈로는, datetime 모듈과 만들어둔 parser.py가 필요합니다.


parser.py를 디스코드 봇 소스가 있는 디렉토리로 옮겨두고


아래 코드를, 디스코드 봇 소스 상단에 추가해줍시다.



import datetime

from parser import *





내일의 식단을 출력하기



먼저, 내일의 식단을 출력하는 코드를 작성하겠습니다.


코드를 작성하기 위해 내일의 식단을 출력하는 그 과정을 구상해 봅시다.


1. 디스코드에서 사용자로부터 명령어를 인식합니다.

저는 '!t' 로 설정하겠습니다.


2. 명령어를 인식한 시점으로부터 다음날의 날짜값과 그 날짜의 요일값을 가져옵니다.

파서의 함수가 필요로 하는 인자가 조식.중식.석식 여부 / 날짜 / 요일이기 때문입니다.

모두 datetime 함수를 사용합니다.


3. 급식을 파싱하는 함수를 호출합니다. 그리고 그 값을 저장합니다.


4. 그 값을 출력합니다.

제가 다니는 학교의 급식 상황을 보면, 조식이 전혀 없고 중식이 없을 경우 100% 석식이 없습니다.

이에 따라 조건절을 추가하여 출력되는 메세지를 '최적화'하였습니다.

(식단 내용 외 날짜등의 정보도 같이 출력해주기 때문입니다.)


중식이 없을 경우 급식이 없다고 출력,

중식이 있고 석식은 없을 경우 중식만 출력,

중식 석식 모두 있을 경우 모두 출력.



이를 코드로 구현하면 아래처럼 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    if message.content.startswith('!to'):    #메세지의 내용의 시작이 !to로 시작할 경우
        to_tomorrow = datetime.datetime.today() + datetime.timedelta(days=1)    #오늘 날짜에 하루를 더함
        local_date2 = to_tomorrow.strftime("%Y.%m.%d")    #위에서 구한 날짜를 년.월.일 형식으로 저장
        local_weekday2 = to_tomorrow.weekday()    #위에서  구한 날짜의 요일값을 저장
 
        l_diet = get_diet(2, local_date2, local_weekday2)    #점심식단을 파싱해옴
        d_diet = get_diet(3, local_date2, local_weekday2)    #석식식단을 파싱해옴
 
        if len(l_diet) == 1:    #점심식단의 길이가 1일경우 = parser.py에서 식단이 없을경우 공백한자리를 반환함.
            await client.send_message(message.channel, "급식이 없습니다.")    #급식이 없다고 메세지 보냄
        elif len(d_diet) == 1:    #점심식단의 길이가 1이 아니고 석식식단의 길이가 1일경우 = 점심식단만 있을경우
            lunch = local_date2 + " 중식\n" + l_diet    #날짜와 "중식"을 앞에 붙여서
            await client.send_message(message.channel, lunch)    #메세지 보냄
        else:    #둘다 길이가 1이 아닐경우 = 점심, 석식 식단 모두 있을 경우
            lunch = local_date2 + " 중식\n" + l_diet    #앞에 부가적인 내용을 붙여서
            dinner = local_date2 + " 석식\n" + d_diet
            await client.send_message(message.channel, lunch)    #메세지를 보냄
            await client.send_message(message.channel, dinner)
cs



코드상 

@client.event

async def on_message(message):

아래에 위치하게 됩니다.



상황에 따라 if가 이미 있을 경우

if message.content.startswith('!to'):

if를 elif로 바꿔서 사용해야 합니다. (파이썬의 기본...)





특정 날짜의 식단을 출력하기



이제 날짜값을 주면 그 날짜의 급식을 출력하는 코드를 작성하겠습니다.


코드의 구성은 위 '내일의 식단을 출력하기'의 코드에서 2번의 내용만 수정해 주면 됩니다.


1. 디스코드에서 사용자로부터 명령어를 인식합니다.

저는 '!t' 로 설정하겠습니다.


2. 날짜를 입력하라는 메세지를 보냅니다. 그리고 받은 날짜의 요일값을 구합니다. (코드로 구현하면 길어집니다.)

datetime 모듈을 이용합니다.


3. 급식을 파싱하는 함수를 호출합니다. 그리고 그 값을 저장합니다.


4. 그 값을 출력합니다.

제가 다니는 학교의 급식 상황을 보면, 조식이 전혀 없고 중식이 없을 경우 100% 석식이 없습니다.

이에 따라 조건절을 추가하여 출력되는 메세지를 '최적화'하였습니다.

(식단 내용 외 날짜등의 정보도 같이 출력해주기 때문입니다.)


중식이 없을 경우 급식이 없다고 출력,

중식이 있고 석식은 없을 경우 중식만 출력,

중식 석식 모두 있을 경우 모두 출력.


이를 코드로 구현하면 아래와 같습니다.


 

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
   elif message.content.startswith('!g'):
        await client.send_message(message.channel, '날짜를 보내주세요...')    #날짜를 보내달라는 메세지를 보냄
        meal_date = await client.wait_for_message(timeout=15.0, author=message.author)    #제한시간은 15초
 
        if meal_date is None:    #값이 존재하지 않거나 시간이 초과되었을 경우
            await client.send_message(message.channel, '15초내로 입력해주세요. 다시시도 : !g')    #다시 시도하라는 메세지를 보냄
            return
 
        else:    #값이 있다면
            meal_date = str(meal_date.content) # str형으로 변환, (사용자로부터 20180219와 같은 형태로 받아야 합니다.)
            meal_date = '20' + meal_date[:2+ '.' + meal_date[2:4+ '.' + meal_date[4:6]    # 2018.02.19 사이에 점을 추가함
            #(사용자로부터 점이 포함된 값으로 받을경우 위 코드를 삭제해도 됩니다.)
 
            s = meal_date.replace('.'', ')     # 2018, 02, 19 점을 반점으로 교체
            ss = "datetime.datetime(" + s + ").weekday()"    #eval함수를 통해 요일값을 구하기 위한 작업
            try:
                whatday = eval(ss)    #요일값을 구해서 whatday에 저장
            except:    #오류가 날 경우 다시 시도하라는 메세지를 보냄
                await client.send_message(message.channel, '올바른 값으로 다시 시도하세요 : !g')
                return
#이하 '내일 식단을 출력하기'와 같음
            l_diet = get_diet(2, meal_date, whatday)
            d_diet = get_diet(3, meal_date, whatday)
 
            if len(l_diet) == 1:
                l_diet = "급식이 없습니다."
                await client.send_message(message.channel, embed=l_diet)
            elif len(d_diet) == 1:
                lunch = meal_date + " 중식\n" + l_diet
                await client.send_message(message.channel, embed=lunch)
            else:
                lunch = meal_date + " 중식\n" + l_diet
                dinner = meal_date + " 석식\n" + d_diet
                await client.send_message(message.channel, lunch)
                await client.send_message(message.channel, dinner)
 
cs

파서의 함수를 호출하는 부분에서 윗부분이 많이 복잡해진 것을 알 수 있습니다.

아래부분은 기존과 변화가 없기 때문에 주석을 달지 않았습니다.



위 둘을 합친 전체 코드는 아래와 같게 됩니다.



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
import discord
import asyncio
import datetime
from parser import *
 
 
client = discord.Client()
 
@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')
 
@client.event
async def on_message(message):
    if message.content.startswith('!to'):    #메세지의 내용의 시작이 !to로 시작할 경우
        to_tomorrow = datetime.datetime.today() + datetime.timedelta(days=1)    #오늘 날짜에 하루를 더함
        local_date2 = to_tomorrow.strftime("%Y.%m.%d")    #위에서 구한 날짜를 년.월.일 형식으로 저장
        local_weekday2 = to_tomorrow.weekday()    #위에서  구한 날짜의 요일값을 저장
 
        l_diet = get_diet(2, local_date2, local_weekday2)    #점심식단을 파싱해옴
        d_diet = get_diet(3, local_date2, local_weekday2)    #석식식단을 파싱해옴
 
        if len(l_diet) == 1:    #점심식단의 길이가 1일경우 = parser.py에서 식단이 없을경우 공백한자리를 반환함.
            await client.send_message(message.channel, "급식이 없습니다.")    #급식이 없다고 메세지 보냄
        elif len(d_diet) == 1:    #점심식단의 길이가 1이 아니고 석식식단의 길이가 1일경우 = 점심식단만 있을경우
            lunch = local_date2 + " 중식\n" + l_diet    #날짜와 "중식"을 앞에 붙여서
            await client.send_message(message.channel, lunch)    #메세지 보냄
        else:    #둘다 길이가 1이 아닐경우 = 점심, 석식 식단 모두 있을 경우
            lunch = local_date2 + " 중식\n" + l_diet    #앞에 부가적인 내용을 붙여서
            dinner = local_date2 + " 석식\n" + d_diet
            await client.send_message(message.channel, lunch)    #메세지를 보냄
            await client.send_message(message.channel, dinner)
 
 
   elif message.content.startswith('!g'):
        await client.send_message(message.channel, '날짜를 보내주세요...')    #날짜를 보내달라는 메세지를 보냄
        meal_date = await client.wait_for_message(timeout=15.0, author=message.author)    #제한시간은 15초
 
        if meal_date is None:    #값이 존재하지 않거나 시간이 초과되었을 경우
            await client.send_message(message.channel, '15초내로 입력해주세요. 다시시도 : !g')    #다시 시도하라는 메세지를 보냄
            return
 
        else:    #값이 있다면
            meal_date = str(meal_date.content) # str형으로 변환, (사용자로부터 20180219와 같은 형태로 받아야 합니다.)
            meal_date = '20' + meal_date[:2+ '.' + meal_date[2:4+ '.' + meal_date[4:6]    # 2018.02.19 사이에 점을 추가함
            #(사용자로부터 점이 포함된 값으로 받을경우 위 코드를 삭제해도 됩니다.)
 
            s = meal_date.replace('.'', ')     # 2018, 02, 19 점을 반점으로 교체
            ss = "datetime.datetime(" + s + ").weekday()"    #eval함수를 통해 요일값을 구하기 위한 작업
            try:
                whatday = eval(ss)    #요일값을 구해서 whatday에 저장
            except:    #오류가 날 경우 다시 시도하라는 메세지를 보냄
                await client.send_message(message.channel, '올바른 값으로 다시 시도하세요 : !g')
                return
            #이하 '내일 식단을 출력하기'와 같음
            l_diet = get_diet(2, meal_date, whatday)
            d_diet = get_diet(3, meal_date, whatday)
 
            if len(l_diet) == 1:
                l_diet = "급식이 없습니다."
                await client.send_message(message.channel, embed=l_diet)
            elif len(d_diet) == 1:
                lunch = meal_date + " 중식\n" + l_diet
                await client.send_message(message.channel, embed=lunch)
            else:
                lunch = meal_date + " 중식\n" + l_diet
                dinner = meal_date + " 석식\n" + d_diet
                await client.send_message(message.channel, lunch)
                await client.send_message(message.channel, dinner)
 
client.run('token')
 
cs



# 글을 작성하면서 보니

#[23,35]과 [59,72]가 하는 일이 같은데

#함수로 하나 정의해서 같이 쓰는게

#효율적일 것 같다는 생각이 듭니다..


#지금은 귀찮으니 PASS


#############

18.03.03 추가

!g 를 통해 특정 날짜의 급식을 부르는 과정에서

날짜값을 받고 처리하는 과정에서 한자리 달의 경우 오류가 발생,

이 부분을 수정하여 한자리 달의 경우도 가능합니다.

수정된 코드는 깃허브를 확인.

https://github.com/M4ndU/inhun_discord_chat_bot_2

############


반응형

+ Recent posts