본문 바로가기

Developing/Python

Python - Flask를 이용한 카카오톡 급식 봇을 만들어보자.

파이썬과 Flask를 이용해서 카카오톡 급식 봇을 만들어보자.


들어가기에 앞서, 급식 봇은 서버가 하나 있어야 한다. 필자는 개인 윈도우 서버를 이용하기로 한다.


만든 코드는 다음과 같다.


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
# -*- coding: utf-8 -*-
 
import os
from flask import Flask, request, jsonify
 
app = Flask(__name__)
 
@app.route('/keyboard')
def Keyboard():
    dataSend = {
        "type""buttons",
        "buttons": ["오늘의 급식""도움말"]
    }
    return jsonify(dataSend)
 
@app.route('/message', methods=['POST'])
def Message():
    dataReceive = request.get_json()
    content = dataReceive['content']
    if content == u"오늘의 급식":

        ### Engine ###
 
        import urllib.request
        from bs4 import BeautifulSoup
        from datetime import datetime
 
        homepage = "http://www.haan.ms.kr/wah/main/schoolmeal/view.htm?menuCode=137&domain.year=" + str(datetime.today().year) + "&domain.month=" + str(datetime.today().month) + "&domain.day=" + str(datetime.today().day)
        # homepage = "http://www.haan.ms.kr/wah/main/schoolmeal/view.htm?menuCode=137&domain.year=2017&domain.month=8&domain.day=14"
 
        dda = urllib.request.Request(homepage)
        data = urllib.request.urlopen(dda).read()
        bs = BeautifulSoup(data, 'html.parser')
        g = bs.find("div", class_="Schoolmeal_Cont_Cont_Cont")
 
        if not g:
            g = "하안중학교 " + str(datetime.today().month) + "월 " + str(datetime.today().day) + "일 급식 : 없음"
        else:
            g = g.prettify()
            g = g.replace('<div class="Schoolmeal_Cont_Cont_Cont">''')
            g = g.replace('</div>''')
            g = g.replace(' ''')
            g = g.replace('\n''')
 
            g = "하안중학교 " + str(datetime.today().month) + "월 " + str(datetime.today().day) + "일 급식 :\n" + g
 
        ### End of Engine ###
        
        dataSend = {
            "message": {
                "text": g
            },
            "keyboard": {
                "type""buttons",
                "buttons": ["오늘의 급식""도움말"]
            }
        }
    elif content == u"도움말":
        dataSend = {
            "message": {
               "text""지금 이 도움말을 볼 수 있다면, 정상작동 하고 있습니다.\n혹시나 메뉴가 뜨지 않는다면, 그건 학교 서버의 문제입니다."
            },
            "keyboard": {
                "type""buttons",
                "buttons": ["오늘의 급식""도움말"]
            }
        }
    return jsonify(dataSend)
 
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=82)
cs



자, 이제 코드를 하나하나씩 살펴보자.


1
2
3
4
5
6
7
@app.route('/keyboard')
def Keyboard():
    dataSend = {
        "type""buttons",
        "buttons": ["오늘의 급식""도움말"]
    }
    return jsonify(dataSend)
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
@app.route('/message', methods=['POST'])
def Message():
    dataReceive = request.get_json()
    content = dataReceive['content']
    if content == u"오늘의 급식":
        
        ### Engine omitted ###
 
        dataSend = {
            "message": {
                "text": g
            },
            "keyboard": {
                "type""buttons",
                "buttons": ["오늘의 급식""도움말"]
            }
        }
    elif content == u"도움말":
        dataSend = {
            "message": {
               "text""지금 이 도움말을 볼 수 있다면, 정상작동 하고 있습니다.\n혹시나 메뉴가 뜨지 않는다면, 그건 학교 서버의 문제입니다."
            },
            "keyboard": {
                "type""buttons",
                "buttons": ["오늘의 급식""도움말"]
            }
        }
    return jsonify(dataSend)
cs



이 부분은 엔진(코드 크롤링) 을 제외한 부분만의 코드이다.


만약에, '오늘의 급식'이라는 버튼이 눌리면, 메시지로 g 변수의 내용을 보내고, 버튼 '오늘의 급식' , '도움말' 을 누를 수 있다. 


필자는 학교 급식 봇이라, 진행하는 과정이 필요없기 때문에 이처럼 단순 반복만 하도록 설정을 할 수 있다.


만약 '도움말'이라는 버튼이 눌리면, 메시지로 '지금 이 도움말 ~ 입니다' 라고 보낸다.


역시나 버튼은 '오늘의 급식' , '도움말' 을 띄운다.



그러면 크롤링 부분을 살펴보자.


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
### Engine ###
 
# Example : http://www.haan.ms.kr/wah/main/schoolmeal/view.htm?menuCode=137&domain.year=2017&domain.month=8&domain.day=14
# Usage : datetime.today().year/month/day
 
import urllib.request
from bs4 import BeautifulSoup
from datetime import datetime
 
homepage = "http://www.haan.ms.kr/wah/main/schoolmeal/view.htm?menuCode=137&domain.year=" + str(datetime.today().year) + "&domain.month=" + str(datetime.today().month) + "&domain.day=" + str(datetime.today().day)
# homepage = "http://www.haan.ms.kr/wah/main/schoolmeal/view.htm?menuCode=137&domain.year=2017&domain.month=8&domain.day=14"
 
dda = urllib.request.Request(homepage)
data = urllib.request.urlopen(dda).read()
bs = BeautifulSoup(data, 'html.parser')
= bs.find("div", class_="Schoolmeal_Cont_Cont_Cont")
 
if not g:
    g = "하안중학교 " + str(datetime.today().month) + "월 " + str(datetime.today().day) + "일 급식 : 없음"
else:
    g = g.prettify()
    g = g.replace('<div class="Schoolmeal_Cont_Cont_Cont">''')
    g = g.replace('</div>''')
    g = g.replace(' ''')
    g = g.replace('\n''')
 
    g = "하안중학교 " + str(datetime.today().month) + "월 " + str(datetime.today().day) + "일 급식 :\n" + g
 
### End of Engine ###
cs


그냥, 평소 코드 붙여넣듯이 하면 된다. 파이썬이라 다 작동한다.


urllib을 사용하여, 홈페이지의 급식 부분을 크롤링한뒤,  급식 내용이 있는 부분을 g 변수에 넣는다.


만약에, 휴일같은 경우 급식이 없다. 그럴 땐 없다고 표시를 하고, 그게 아니라면 코드를 깔끔하게 한 뒤 급식을 알려준다.



1
2
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=82)
cs


0.0.0.0 (즉, 모든 요청을 다 받는다.), 포트는 82번으로 설정했다.


플러스 친구 부분에서는 82번 포트로 연결하고, 방화벽은 당연히 열어두어야 한다.




위와 같은 방법은 상당히 비 효율적이다.


사용자가 누를 때 마다 계속 크롤링을 시도하니 말이다.


파일 저장 명령어를 이용한 방법으로 자동화를 한번 구현해봐야겠다..