Developing/Python

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

TSK 2017. 9. 2. 21:06
파이썬과 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번 포트로 연결하고, 방화벽은 당연히 열어두어야 한다.




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


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


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