임승현

Merge branch 'Chatbot' into 'feature/Chatbot_megabox'

Chatbot



See merge request !30
1 +const chatbot = require("./app.js");
2 +const request = require('request');
3 +const cheerio = require('cheerio');
4 +const puppeteer = require('puppeteer');
5 +require('chromedriver');
6 +const {Builder,until} = require('selenium-webdriver'); //모듈 불러오기
7 +var webdriver = require('selenium-webdriver');
8 +var By = webdriver.By;
9 +const chrome = require('selenium-webdriver/chrome');//크롬 사용시
10 +const async = require('async')
11 +let express = require('express');
12 +let app = express();
13 +let bodyParser = require('body-parser');
14 +const { timeout } = require('async');
15 +app.use(bodyParser.urlencoded({ extended: false }));
16 +app.use(bodyParser.json());
17 +const booking_url = "https://megabox.co.kr/booking?";
18 +exports.booking_url = booking_url;
19 +const rate_url = "https://www.megabox.co.kr/movie";
20 +let r =0;
21 +let movie_data = [];
22 +exports.movie_data = movie_data;
23 +let location_data = [];
24 +exports.location_data = location_data;
25 +let index = 0;
26 +exports.init = ()=>{async.waterfall([//for 동기적 처리
27 + async () => {
28 + const driver = new webdriver.Builder().forBrowser('chrome').setChromeOptions(new chrome.Options().headless()).build();//
29 + driver.get(booking_url);
30 + driver.switchTo().frame(0)//frameBokdMBooking 프레임 가져옴
31 + let seoul = await driver.wait(until.elementsLocated(By.css('#mCSB_4_container>ul>li>#btn')));
32 + let Gyeonggi = await driver.wait(until.elementsLocated(By.css('#mCSB_5_container>ul>li>#btn')));
33 + const Incheon = await driver.wait(until.elementsLocated(By.css('#mCSB_6_container>ul>li>#btn')));
34 + const DCS = await driver.wait(until.elementsLocated(By.css('#mCSB_7_container>ul>li>#btn')));//Daejeon Chungcheong Sejong
35 + const BDG = await driver.wait(until.elementsLocated(By.css('#mCSB_8_container>ul>li>#btn')));//Busan Daegu Gyeongsang
36 + const GJ= await driver.wait(until.elementsLocated(By.css('#mCSB_9_container>ul>li>#btn')));//gwangju_jeonla
37 + const Gangwon = await driver.wait(until.elementsLocated(By.css('#mCSB_10_container>ul>li>#btn')));
38 + const location_list = [seoul, Gyeonggi, Incheon, DCS, BDG, GJ, Gangwon]//
39 + for(let i = 0; i < location_list.length; i++){
40 + for (item of location_list[i]) {
41 + location_data[index++] = {
42 + 'LocationName':await item.getAttribute("brch-nm"),
43 + 'LocationNum' : await item.getAttribute("brch-no")
44 + }
45 + // let location_name = await item.getAttribute("brch-nm");
46 + // let location_num = await item.getAttribute("brch-no");
47 + // let obj = {};
48 + // obj[location_name]= location_num
49 + // location_data[index++] = obj;
50 + }
51 + }
52 + let movie_list = await driver.wait(until.elementsLocated(By.css('#mCSB_1_container>ul>li>.btn')));
53 + r = 0;
54 + for (item of movie_list) {
55 + //Using getAttribute to get the data
56 + movie_data[r++] = {
57 + 'rank' : r,
58 + 'title' : await item.getAttribute("movie-nm"),
59 + 'movie_num':await item.getAttribute("movie-no"),
60 + }
61 + }
62 +
63 + driver.close();
64 +
65 + },
66 + async () => {
67 + r = 0;
68 + const browser = await puppeteer.launch({
69 + headless: true
70 + });
71 + const page = await browser.newPage();
72 + await page.goto(rate_url);
73 + const content = await page.content();
74 +
75 + const $ = cheerio.load(content);
76 + const $rate_lists = $("ol.list>li");
77 + $rate_lists.each((index, list) => {
78 + const name = $(list).find('div.tit-area > p.tit').attr('title');
79 + const rate = $(list).find('div.rate-date > span.rate').text();
80 +
81 + if(movie_data[r].title === name){
82 + movie_data[r++]['rate'] = rate;
83 + }
84 + });
85 + for(i of movie_data){
86 + if(Object.keys(i).length==3){
87 + movie_data[r++]['rate'] = '예매율 0%';
88 + }
89 + }
90 +
91 + browser.close();
92 + console.log("Comepleted!");
93 + },
94 +
95 +])}
96 +
97 +let appdriver;
98 +exports.using_PlayingMovieURL = async(PlayingMovieURL) => {
99 + appdriver = new webdriver.Builder().forBrowser('chrome').setChromeOptions(new chrome.Options().headless()).build();
100 + appdriver.get(PlayingMovieURL);
101 + //appdriver.switchTo().frame(0)
102 + //frameBokdMBooking 프레임 가져옴
103 +}
104 +exports.geting_PlayingMovie= async() => {
105 + let movie_list = await appdriver.wait(until.elementsLocated(By.css('#mCSB_1_container>ul>li>.btn')));
106 + let n = 0;
107 + console.log(movie_list);
108 + for (item of movie_list) {
109 + console.log(item.getAttribute('form-at'))
110 + movie_data[n++]['running'] = await item.getAttribute('form-at');
111 + }
112 + console.log("Completed get Running");
113 +}
114 +
115 +app.listen(5000);
...\ No newline at end of file ...\ No newline at end of file
1 +const megabox = require('./Megabox.js');
2 +//const SearchingTheaterAPI = require('./SearchingTheaterAPI');
3 +const async = require('async');
4 +megabox.init(); //메가박스 코드 시작(영화관 리스트 가져오기)
5 +const PUSH_TARGET_URL = 'https://api.line.me/v2/bot/message/push'
6 +const REPLY_TARGET_URL = 'https://api.line.me/v2/bot/message/reply'
7 +const asyncHandler = require('express-async-handler')
8 +const bodyParser = require('body-parser');
9 +const request = require('request');
10 +const moment = require("moment");
11 +const HTTPS = require('https');
12 +const path = require('path');
13 +const fs = require('fs');
14 +const sslport = 23023;
15 +var express = require('express');
16 +var app = express();
17 +app.use(bodyParser.json());
18 +/////////////////////////////////////////////////
19 +// commit 할때 지워야 할것들
20 +const USER_ID = ''
21 +const TOKEN = ''
22 +const domain = ""
23 +
24 +let MEGA_date;
25 +let MEGA_TheaterLocation;
26 +let MEGA_TheaterLocationCode;
27 +let MEGA_PlayingMovieList = [];
28 +let MEGA_title;
29 +let MEGA_PlayingMovieURL;
30 +let initFlag = false; //브랜드 선택 flag
31 +let MEGA_flag = -1; //메가박스 인지 확인하는 flag
32 +let MEGA_count; //메가박스에서 영화관 판단하는 count
33 +let MEGA_AbleLocationList = []; //메가박스에서 영화관 이름 매치하는 것 저장하는 list
34 +exports.MEGA_PlayingMovieURL = MEGA_PlayingMovieURL;
35 +////////////////////////////////////////////////
36 +//처음 영화관을 가져오는 것까지 대략 30초가 걸림 => 30초 기다리고 메세지 전송
37 +
38 +setTimeout(function () {
39 + PushSingleMessage("원하시는 브랜드의 번호를 입력해주세요.\n1: CGV\n2: LotteCinema\n3: Megabox\n언제든 브랜드를 바꾸고 싶으시다면 '브랜드'를 입력해주세요.");
40 +}, 30000);
41 +
42 +//app.post('/hook', function (req, res) {
43 +app.post('/hook', asyncHandler(async (req, res, next) => {
44 + var eventObj = req.body.events[0];
45 + var source = eventObj.source;
46 + var message = eventObj.message;
47 + // request log
48 + console.log('======================', new Date(), '======================');
49 + console.log('[request]', req.body);
50 + console.log('[request source] ', eventObj.source);
51 + console.log('[request message]', eventObj.message);
52 + //어느 순간에서든 "브랜드"를 입력해 원하는 브랜드 선택
53 + //initFlag : false ==> 브랜드 선택 전
54 + //initFlag : true ==> 브랜드 선택 됨
55 + if (eventObj.message.text == "브랜드") {
56 + initFlag = false;
57 + MEGA_flag = -1;
58 + PushSingleMessage("원하시는 브랜드의 번호를 입력해주세요.\n1: CGV\n2: LotteCinema\n3: Megabox\n언제든 브랜드를 바꾸고 싶으시다면 '브랜드'를 입력해주세요.");
59 + }
60 + //브랜드 선택- 메가박스 인 경우 MEGA_flag를 0으로 두어 메가박스 임을 확인
61 + if (initFlag == false && eventObj.message.text == 3) {
62 + initFlag = true;
63 + MEGA_flag = 0;
64 + }
65 + //메가박스로 브랜드 선택된 경우
66 + if (initFlag == true && MEGA_flag != -1) {
67 + if (MEGA_flag == 0) {
68 + const text1 = "영화관 위치를 입력해주세요";
69 + const text2 = "ex1)강남";
70 + SendMessage(eventObj, text1, text2);
71 + MEGA_flag++;
72 + //PusbuttonhMessage("https://developers.line.biz/en/reference/messaging-api/#message-common-properties");
73 + //console.log(MEGA_flag)
74 + }else if (MEGA_flag === 1) {
75 + MEGA_count = 0; //MEGA_count 초기화
76 + MEGA_AbleLocationList.length = 0; //MEGA_AbleLocationList 초기화
77 + for (i of megabox.location_data) {
78 + if (i['LocationName'].includes(message.text)) {
79 + MEGA_AbleLocationList[MEGA_count++] = i;
80 + }
81 + }
82 +
83 + if (MEGA_count == 1) { //결과 1개 => 바로 다음 단계 넘어가기
84 + MEGA_TheaterLocation = MEGA_AbleLocationList[0].LocationName;
85 + MEGA_TheaterLocationCode = MEGA_AbleLocationList[0].LocationNum;
86 + console.log(MEGA_TheaterLocation, MEGA_TheaterLocationCode);
87 + MEGA_flag++;
88 + } else if (MEGA_count > 1) { //결과 2개 이상 => 리스트 출력해주고 번호로 입력받아 넘어가기
89 + console.log(MEGA_AbleLocationList[0], MEGA_AbleLocationList[1]);
90 + let MEGA_OutputString = "원하시는 상영관의 번호를 정확히 입력해주세요\n"; //메가박스 영화관 가능 정보 string
91 + //PushSingleMessage("원하시는 상영관의 번호를 정확히 입력해주세요");
92 + for (let x = 0; x < MEGA_count; x++) {
93 + //PushSingleMessage(String(x + 1) + ": " + MEGA_AbleLocationList[x].LocationName);
94 + MEGA_OutputString += String(x + 1) + ": " + MEGA_AbleLocationList[x].LocationName + "\n";
95 + console.log(String(x + 1), MEGA_AbleLocationList[x].LocationName);
96 + }
97 + MEGA_OutputString += String(MEGA_count + 1) + ": 다시 검색하기";
98 + PushSingleMessage(MEGA_OutputString);
99 + MEGA_flag = 101;
100 + } else {
101 + PushSingleMessage("다시 입력해주세요.");
102 + }
103 + //원본 코드
104 + //console.log(MEGA_flag);
105 + // for (i of megabox.location_data) {
106 + // if (i['LocationName'] === message.text) {
107 + // MEGA_TheaterLocationCode = i['LocationNUm'];
108 + // console.log(MEGA_TheaterLocationCode);
109 + // MEGA_flag++;
110 + // console.log(MEGA_flag)
111 + // break;
112 + // }
113 + // }
114 + } else if (MEGA_flag == 101) {
115 + // 0< input || input > MEGA_count+1 : 다시 검색
116 + let tempNum = parseInt(message.text);
117 + if (tempNum > 0 && tempNum < MEGA_count + 1) {
118 + //번호에 맞는 LocationCode 전달
119 + MEGA_TheaterLocation = MEGA_AbleLocationList[tempNum - 1].LocationName;
120 + MEGA_TheaterLocationCode = MEGA_AbleLocationList[tempNum - 1].LocationNum;
121 + console.log(MEGA_TheaterLocation, MEGA_TheaterLocationCode);
122 + MEGA_flag = 2;
123 + } else {
124 + //다시 장소 입력받기
125 + const text1 = "영화관 위치를 입력해주세요";
126 + const text2 = "ex1)강남";
127 + SendMessage(eventObj, text1, text2);
128 + MEGA_flag = 1;
129 + }
130 + }
131 + //날짜 입력 받기
132 + if (MEGA_flag == 2) {
133 + const text1 = "현재 영화관은 " + MEGA_TheaterLocation + " 입니다.\n영화를 보실 날짜를 입력해주세요.";
134 + const text2 = "ex)20020409";
135 + SendMessage(eventObj, text1, text2);
136 + MEGA_flag = 3;
137 + }
138 + //날짜 확인 및 날짜, 장소에 대해 상영중인 영화 리스트 가져오기
139 + if (moment(message.text, "YYYYMMDD", true).isValid() && MEGA_flag == 3) {
140 + MEGA_date = parseInt(message.text);
141 + //console.log(MEGA_date, MEGA_TheaterLocation);
142 + if (MEGA_date && MEGA_TheaterLocationCode) {
143 + const text1 = "현재상영작을 가져오는 중입니다.";
144 + const text2 = "잠시만 기다려주세요.";
145 + PushMessage(text1, text2);
146 + MEGA_PlayingMovieURL = "https://megabox.co.kr/on/oh/ohb/SimpleBooking/simpleBookingPage.do" + '?brchNo1=' + MEGA_TheaterLocationCode + '&playDe=' + MEGA_date;
147 + megabox.using_PlayingMovieURL(MEGA_PlayingMovieURL);
148 + await megabox.geting_PlayingMovie();
149 + console.log(MEGA_PlayingMovieURL, megabox.movie_data);
150 + MEGA_flag = 4;
151 + }
152 + //원본 코드
153 + // MEGA_date = parseInt(eventObj.message.text);
154 + // if (MEGA_date && MEGA_TheaterLocationCode) {
155 + // MEGA_PlayingMovieURL = "https://megabox.co.kr/on/oh/ohb/SimpleBooking/simpleBookingPage.do" + '?brchNo1=' + MEGA_TheaterLocationCode + '&playDe=' + MEGA_date;
156 + // console.log(MEGA_PlayingMovieURL)
157 + // async.waterfall[
158 + // megabox.using_PlayingMovieURL(MEGA_PlayingMovieURL),
159 + // megabox.geting_PlayingMovie()
160 + // ]
161 + // MEGA_flag++
162 + // console.log(MEGA_flag);
163 + // }
164 + }
165 + if (MEGA_flag == 4) {
166 + let obj = {};
167 + let n;
168 + let PlayingMovie = "-현재 상영작-\n\n";
169 + let movietitle;
170 + console.log(megabox.movie_data);
171 + for (n = 0; n < Object.keys(megabox.movie_data).length; n++) {
172 + if (megabox.movie_data[n].running == 'Y') {
173 + console.log(megabox.movie_data[n]);
174 + movietitle = megabox.movie_data[n].title;
175 + MEGA_PlayingMovieList[movietitle] = megabox.movie_data[n].movie_num;
176 + }
177 + }
178 + console.log(Object.keys(megabox.movie_data).length);
179 + if (Object.keys(megabox.movie_data).length == 0) {
180 + PushMessage("현재상영작이 없습니다.","영화관 선택 단계로 이동합니다.");
181 + setTimeout(function () {
182 + PushMessage("영화관 위치를 입력해주세요", "ex1)강남");
183 + }, 1000);
184 + MEGA_flag = 1;
185 + }else if (Object.keys(MEGA_PlayingMovieList).length == 1) {
186 + PlayingMovie += '1. ' + Object.keys(MEGA_PlayingMovieList)[0];
187 + PushMessage(PlayingMovie, "바로 링크가 보내집니다.");
188 + MEGA_title = MEGA_PlayingMovieList[Object.keys(MEGA_PlayingMovieList)[0]];
189 + setTimeout(function () {
190 + const final_URL = "https://www.megabox.co.kr/booking?rpstMovieNo=" + MEGA_title + "&brchNo1=" + MEGA_TheaterLocationCode + '&playDe=' + MEGA_date;
191 + console.log(final_URL)
192 + PushMessage(final_URL, "링크를 누르면 예매창으로 바로 이동합니다.");
193 + }, 1000);
194 + setTimeout(function () {
195 + initFlag = false;
196 + MEGA_flag = -1;
197 + MEGA_PlayingMovieList = [];
198 + PushSingleMessage("원하시는 브랜드의 번호를 입력해주세요.\n1: CGV\n2: LotteCinema\n3: Megabox\n언제든 브랜드를 바꾸고 싶으시다면 '브랜드'를 입력해주세요.");
199 + }, 1000);
200 + } else {
201 + let index = 0;
202 + for (let playingmovie = 0; playingmovie < Object.keys(MEGA_PlayingMovieList).length; playingmovie++) {
203 + PlayingMovie += (playingmovie + 1).toString() + '. ' + Object.keys(MEGA_PlayingMovieList)[index++];
204 + PlayingMovie += "\n";
205 + }
206 + console.log(PlayingMovie);
207 + await PushMessage(PlayingMovie, "예매할 영화 번호를 입력해주세요.\n ex)1 (영화 앞 숫자만 입력)");
208 + MEGA_flag = 5;
209 + }
210 + }else if (MEGA_flag == 5) {
211 + const index = parseInt(message.text) - 1;
212 + MEGA_title = MEGA_PlayingMovieList[Object.keys(MEGA_PlayingMovieList)[index]];
213 + const final_URL = "https://www.megabox.co.kr/booking?rpstMovieNo=" + MEGA_title + "&brchNo1=" + MEGA_TheaterLocationCode + '&playDe=' + MEGA_date;
214 + console.log(final_URL);
215 + PushMessage(final_URL, "링크를 누르면 예매창으로 바로 이동합니다.");
216 + setTimeout(function () {
217 + MEGA_PlayingMovieList = [];
218 + initFlag = false;
219 + MEGA_flag = -1;
220 + PushSingleMessage("원하시는 브랜드의 번호를 입력해주세요.\n1: CGV\n2: LotteCinema\n3: Megabox\n언제든 브랜드를 바꾸고 싶으시다면 '브랜드'를 입력해주세요.");
221 + }, 1000);
222 + }
223 + }
224 +
225 + res.sendStatus(200);
226 +}))
227 +//});
228 +try {
229 + const option = {
230 + ca: fs.readFileSync('/etc/letsencrypt/live/' + domain + '/fullchain.pem'),
231 + key: fs.readFileSync(path.resolve(process.cwd(), '/etc/letsencrypt/live/' + domain + '/privkey.pem'), 'utf8').toString(),
232 + cert: fs.readFileSync(path.resolve(process.cwd(), '/etc/letsencrypt/live/' + domain + '/cert.pem'), 'utf8').toString(),
233 + };
234 + HTTPS.createServer(option, app).listen(sslport, () => {
235 + console.log(`[HTTPS] Server is started on port ${sslport}`);
236 + });
237 +} catch (error) {
238 + console.log('[HTTPS] HTTPS 오류가 발생하였습니다. HTTPS 서버는 실행되지 않습니다.');
239 + console.log(error);
240 +}
241 +//메세지 전송하는 function 모음
242 +function SendMessage(eventObj, text1, text2 = "") { //reply message
243 + request.post(
244 + {
245 + url: REPLY_TARGET_URL,
246 + headers: {
247 + 'Authorization': `Bearer ${TOKEN}`
248 + },
249 + json: {
250 + "replyToken": eventObj.replyToken,
251 + "messages": [
252 + {
253 + "type": "text",
254 + "text": text1
255 + },
256 + {
257 + "type": "text",
258 + "text": text2
259 + }
260 + ]
261 + }
262 + }, (error, response, body) => {
263 + console.log(body);
264 + });
265 +}
266 +function PushMessage(text1, text2 = "") { //push two message
267 + request.post(
268 + {
269 + url: PUSH_TARGET_URL,
270 + headers: {
271 + 'Authorization': `Bearer ${TOKEN}`
272 + },
273 + json: {
274 + "to": `${USER_ID}`,
275 + "messages": [
276 + {
277 + "type": "text",
278 + "text": text1
279 + },
280 + {
281 + "type": "text",
282 + "text": text2
283 + }
284 + ]
285 + }
286 + }, (error, response, body) => {
287 + console.log(body)
288 + });
289 +}
290 +function PushSingleMessage(text1) {//push single message
291 + request.post(
292 + {
293 + url: PUSH_TARGET_URL,
294 + headers: {
295 + 'Authorization': `Bearer ${TOKEN}`
296 + },
297 + json: {
298 + "to": `${USER_ID}`,
299 + "messages": [
300 + {
301 + "type": "text",
302 + "text": text1
303 + }
304 + ]
305 + }
306 + }, (error, response, body) => {
307 + console.log(body)
308 + });
309 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "name": "megabox",
3 + "version": "1.0.0",
4 + "description": "",
5 + "main": "app.js",
6 + "scripts": {
7 + "test": "echo \"Error: no test specified\" && exit 1"
8 + },
9 + "keywords": [],
10 + "author": "",
11 + "license": "ISC",
12 + "dependencies": {
13 + "async": "^3.2.3",
14 + "body-parser": "^1.20.0",
15 + "cheerio": "^1.0.0-rc.11",
16 + "chromedriver": "^101.0.0",
17 + "express": "^4.18.1",
18 + "express-async-handler": "^1.2.0",
19 + "puppeteer": "^14.1.1",
20 + "selenium-webdriver": "^4.1.2"
21 + }
22 +}