성준영

Global 모듈 크롤링 정보 추가, 챕터 선택 기능 추가

...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
2 * Created by junyoung on 2017. 4. 2.. 2 * Created by junyoung on 2017. 4. 2..
3 */ 3 */
4 4
5 -var request = require('request'); 5 +let request = require('request');
6 -var cheerio = require('cheerio'); 6 +let cheerio = require('cheerio');
7 -var Promise = require('promise'); 7 +let Promise = require('promise');
8 -var readline = require('readline'); 8 +let readline = require('readline');
9 -var https = require('https'); 9 +let https = require('https');
10 -var querystring = require('querystring'); 10 +let querystring = require('querystring');
11 -var fs = require('fs'); 11 +let fs = require('fs');
12 12
13 13
14 -var j = request.jar(); 14 +let j = request.jar();
15 request = request.defaults({jar: j}); 15 request = request.defaults({jar: j});
16 16
17 17
...@@ -33,7 +33,11 @@ exports.login = function (id, pw) { ...@@ -33,7 +33,11 @@ exports.login = function (id, pw) {
33 timeout: 3000 33 timeout: 3000
34 }, function (err, res, body) { 34 }, function (err, res, body) {
35 if (err) { 35 if (err) {
36 - reject('클라스 요청 응답시간이 너무 길어요.'); 36 + if(err.code === 'ESOCKETTIMEDOUT'){
37 + reject('클라스 요청 응답시간이 너무 길어요... ㅠㅠ');
38 + } else {
39 + reject('알수없는 에러가 발생했어요!.');
40 + }
37 } else if (j.getCookies("https://klas.khu.ac.kr").length === 0) { 41 } else if (j.getCookies("https://klas.khu.ac.kr").length === 0) {
38 reject('로그인에 실패했습니다!'); 42 reject('로그인에 실패했습니다!');
39 } else { 43 } else {
...@@ -76,11 +80,11 @@ exports.getLecture = function () { ...@@ -76,11 +80,11 @@ exports.getLecture = function () {
76 exports.getLectureLink = function (getLectureBody) { 80 exports.getLectureLink = function (getLectureBody) {
77 81
78 return new Promise(function (resolve, reject) { 82 return new Promise(function (resolve, reject) {
79 - var $ = cheerio.load(getLectureBody); 83 + let $ = cheerio.load(getLectureBody);
80 - var lectureLinks = $('.gomy_class'); 84 + let lectureLinks = $('.gomy_class');
81 - var tableTrs = $('#tbl > tbody > tr > td'); 85 + let tableTrs = $('#tbl > tbody > tr > td');
82 86
83 - var lectureLinkList = []; 87 + let lectureLinkList = [];
84 88
85 tableTrs.each(function (i) { 89 tableTrs.each(function (i) {
86 if (i % 7 === 1) { 90 if (i % 7 === 1) {
...@@ -94,7 +98,6 @@ exports.getLectureLink = function (getLectureBody) { ...@@ -94,7 +98,6 @@ exports.getLectureLink = function (getLectureBody) {
94 lectureLinkList[i].link = 'https://klas.khu.ac.kr' + $(this).attr('href') 98 lectureLinkList[i].link = 'https://klas.khu.ac.kr' + $(this).attr('href')
95 }); 99 });
96 100
97 - console.log(lectureLinkList);
98 resolve(lectureLinkList); 101 resolve(lectureLinkList);
99 102
100 }) 103 })
...@@ -114,13 +117,13 @@ exports.selectLecture = function (lectureLinkList) { ...@@ -114,13 +117,13 @@ exports.selectLecture = function (lectureLinkList) {
114 input: process.stdin, 117 input: process.stdin,
115 output: process.stdout 118 output: process.stdout
116 }); 119 });
117 - var selectQuestion = ''; 120 + let selectQuestion = '';
118 - selectQuestion += '\n 강의자료를 다운받을 강의를 선택해 주세요 \n'; 121 + selectQuestion += '\n 강의자료를 다운받을 강의를 선택해 주세요 :D\n\n';
119 - var count = 0; 122 + let count = 0;
120 123
121 return new Promise(function (resolve, reject) { 124 return new Promise(function (resolve, reject) {
122 125
123 - for (var i in lectureLinkList) { 126 + for (let i in lectureLinkList) {
124 count += 1; 127 count += 1;
125 selectQuestion += ' ' + count + '. ' + lectureLinkList[i].lectureName + '\n'; 128 selectQuestion += ' ' + count + '. ' + lectureLinkList[i].lectureName + '\n';
126 } 129 }
...@@ -139,13 +142,19 @@ exports.selectLecture = function (lectureLinkList) { ...@@ -139,13 +142,19 @@ exports.selectLecture = function (lectureLinkList) {
139 142
140 }; 143 };
141 144
145 +/**
146 + * @author sungjunyoung
147 + * @description 강의실 링크의 url 을 받아서 HTML 를 리턴해주는 함수
148 + * @param {String} lectureLink - 강의실 URL
149 + * @returns {*|Promise}
150 + */
142 exports.getClassPageBody = function (lectureLink) { 151 exports.getClassPageBody = function (lectureLink) {
143 152
144 return new Promise(function (resolve, reject) { 153 return new Promise(function (resolve, reject) {
145 154
146 - var url = lectureLink.link; 155 + let url = lectureLink.link;
147 156
148 - var headers = { 157 + let headers = {
149 'Cookie': 'COURSE_MENU_NAME=%uAC15%uC758%uC2E4', 158 'Cookie': 'COURSE_MENU_NAME=%uAC15%uC758%uC2E4',
150 'User-Agent': 'request' 159 'User-Agent': 'request'
151 }; 160 };
...@@ -154,10 +163,15 @@ exports.getClassPageBody = function (lectureLink) { ...@@ -154,10 +163,15 @@ exports.getClassPageBody = function (lectureLink) {
154 url: url, 163 url: url,
155 mothod: 'GET', 164 mothod: 'GET',
156 jar: j, 165 jar: j,
157 - headers: headers 166 + headers: headers,
167 + timeout: 3000
158 }, function (err, res, body) { 168 }, function (err, res, body) {
159 if (err) { 169 if (err) {
160 - reject(err); 170 + if(err.code === 'ESOCKETTIMEDOUT'){
171 + reject('클라스 요청 응답시간이 너무 길어요... ㅠㅠ');
172 + } else {
173 + reject('알수없는 에러가 발생했어요!.');
174 + }
161 } else { 175 } else {
162 resolve(body); 176 resolve(body);
163 } 177 }
...@@ -165,46 +179,64 @@ exports.getClassPageBody = function (lectureLink) { ...@@ -165,46 +179,64 @@ exports.getClassPageBody = function (lectureLink) {
165 }); 179 });
166 }; 180 };
167 181
182 +/**
183 + * @author sungjunyoung
184 + * @description 강의실 URL 페이지 HTML 을 받아와서 파일 다운로드 링크의 URL 어레이를 리턴 chapterFilesArr[{chapter, files[{link, fileName}]}]
185 + * @param {String} classPageBody - 강의실 URL 의 페이지 HTML
186 + * @returns {*|Promise}
187 + */
168 exports.findFiles = function (classPageBody) { 188 exports.findFiles = function (classPageBody) {
169 189
170 return new Promise(function (resolve, reject) { 190 return new Promise(function (resolve, reject) {
171 - var $ = cheerio.load(classPageBody); 191 + let $ = cheerio.load(classPageBody);
172 - var fileDownAnchors = $('.mycl_listbox.today'); 192 + let fileDownAnchors = $('.mycl_listbox.today');
173 -
174 - var fileArr = [];
175 193
194 + let chapterFilesArr = [];
176 195
177 fileDownAnchors.each(function (i) { 196 fileDownAnchors.each(function (i) {
178 - var tempFileArr = []; 197 + let chapter = $(this).find('.lf').text();
198 + let tempChapterObj = {chapter: chapter, files: []};
179 $(this).find('.mycl_veiw_learnig').find('.file-downbox-list').find('a').each(function (j) { 199 $(this).find('.mycl_veiw_learnig').find('.file-downbox-list').find('a').each(function (j) {
180 - var link = 'https://klas.khu.ac.kr' + $(this).attr('href').split('..')[1]; 200 + let link = 'https://klas.khu.ac.kr' + $(this).attr('href').split('..')[1];
181 - tempFileArr.push(link); 201 + let fileName = $(this).text();
202 + tempChapterObj.files.push({link: link, fileName: fileName});
182 }); 203 });
183 - fileArr.push(tempFileArr); 204 + chapterFilesArr.push(tempChapterObj);
184 }); 205 });
185 206
186 - resolve(fileArr); 207 + resolve(chapterFilesArr);
187 }); 208 });
188 }; 209 };
189 210
190 -exports.getSelectedFiles = function (fileArr, lb) { 211 +/**
191 - 212 + * @author sungjunyoung
192 - return new Promise(function (resolve, reject) { 213 + * @description findFiles 의 chapterFilesArr[{chapter, files[{link, fileName}]}] 을 받아 사용자에게 선택하게 하고, 다운받아야 할 강의자료 리스트를 리턴
193 - 214 + * @param {String} chapterFilesArr - 챕터별로 파일들과 파일 명의 리스트를 가지고 있는 리스트
194 - var lectureBefore = 0; 215 + * @returns {*|Promise}
195 - if(!lb || lb === ''){ 216 + */
196 - lectureBefore = 0; 217 +exports.selectChapter = function (chapterFilesArr) {
197 - } else {
198 - lectureBefore = lb;
199 - }
200 -
201 - var downloadIndex = fileArr.length - lectureBefore - 1;
202 218
203 - if (downloadIndex < 0) { 219 + const rl = readline.createInterface({
204 - reject('이 날에는 강의자료가 없네요!'); 220 + input: process.stdin,
205 - } 221 + output: process.stdout
222 + });
223 + let selectQuestion = '';
224 + selectQuestion += '\n 강의자료를 다운받을 챕터를 선택해 주세요 :) \n\n';
225 + let counter = 0;
226 + for (let i in chapterFilesArr) {
227 + counter = i * 1 + 1;
228 + selectQuestion += ' ' + counter + '. ' + chapterFilesArr[i].chapter;
229 + selectQuestion += '\n';
230 + }
231 + selectQuestion += '\n';
232 + selectQuestion += ' 입력 (1 ~ ' + counter + ') : ';
206 233
207 - resolve(fileArr[downloadIndex]); 234 + return new Promise(function (resolve, reject) {
235 + rl.question(selectQuestion, (answer) => {
236 + answer = parseInt(answer) - 1;
237 + resolve(chapterFilesArr[answer]);
238 + rl.close();
239 + });
208 }); 240 });
209 }; 241 };
210 242
...@@ -212,8 +244,8 @@ exports.downloadSelectedFile = function (selectedFile, path) { ...@@ -212,8 +244,8 @@ exports.downloadSelectedFile = function (selectedFile, path) {
212 244
213 return new Promise(function (resolve, reject) { 245 return new Promise(function (resolve, reject) {
214 246
215 - var downloadPath; 247 + let downloadPath;
216 - if(!path || path === ''){ 248 + if (!path || path === '') {
217 downloadPath = ''; 249 downloadPath = '';
218 //TODO Default Path 설정하기 250 //TODO Default Path 설정하기
219 } else { 251 } else {
...@@ -221,12 +253,12 @@ exports.downloadSelectedFile = function (selectedFile, path) { ...@@ -221,12 +253,12 @@ exports.downloadSelectedFile = function (selectedFile, path) {
221 //TODO 사용자가 지정한 path 리포맷하기 253 //TODO 사용자가 지정한 path 리포맷하기
222 } 254 }
223 255
224 - var count = 0; 256 + let count = 0;
225 selectedFile.forEach(function (value, index) { 257 selectedFile.forEach(function (value, index) {
226 258
227 request = https.get(value, function (response) { 259 request = https.get(value, function (response) {
228 - count ++; 260 + count++;
229 - var file = fs.createWriteStream("./file_" + index + ".pdf"); 261 + let file = fs.createWriteStream("./file_" + index + ".pdf");
230 response.pipe(file); 262 response.pipe(file);
231 263
232 if (index === count) { 264 if (index === count) {
......
...@@ -11,7 +11,7 @@ if(require.main === module){ ...@@ -11,7 +11,7 @@ if(require.main === module){
11 11
12 args 12 args
13 .option('id', '[필수] 학번을 입력합니다.') 13 .option('id', '[필수] 학번을 입력합니다.')
14 - .option('pw', '[필수] 비밀번호를 입력합니다. 로컬 PC 에서만 사용하기 때문에 안전합니다 ^^.') 14 + .option('pw', '[필수] 비밀번호를 입력합니다. 로컬 PC 에서만 사용하기 때문에 안전합니다 :).')
15 .option('downloadPath', '[선택] 자료를 다운받을 경로를 입력합니다. (default 는 ~/Downloads 입니다.)'); 15 .option('downloadPath', '[선택] 자료를 다운받을 경로를 입력합니다. (default 는 ~/Downloads 입니다.)');
16 16
17 const flags = args.parse(process.argv); 17 const flags = args.parse(process.argv);
...@@ -29,12 +29,9 @@ if(require.main === module){ ...@@ -29,12 +29,9 @@ if(require.main === module){
29 .then(functions.selectLecture) 29 .then(functions.selectLecture)
30 .then(functions.getClassPageBody) 30 .then(functions.getClassPageBody)
31 .then(functions.findFiles) 31 .then(functions.findFiles)
32 - .then(function (fileArr) { 32 + .then(functions.selectChapter)
33 - return functions.getSelectedFiles(fileArr, flags.lectureBefore); 33 + .then(function(res){
34 - }) 34 + console.log(res);
35 - .then(function (selectedFile) {
36 - // console.log(selectedFile);
37 - functions.downloadSelectedFile(selectedFile);
38 }) 35 })
39 .catch(function (err) { 36 .catch(function (err) {
40 console.log(err); 37 console.log(err);
......
1 { 1 {
2 "name": "klas-file-downloader", 2 "name": "klas-file-downloader",
3 - "version": "0.0.3", 3 + "version": "0.0.4",
4 "description": "Project that download lecture reference files from Klas", 4 "description": "Project that download lecture reference files from Klas",
5 "main": "index.js", 5 "main": "index.js",
6 "scripts": { 6 "scripts": {
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
22 "url": "https://github.com/sungjunyoung/klas-file-downloader/issues" 22 "url": "https://github.com/sungjunyoung/klas-file-downloader/issues"
23 }, 23 },
24 "bin": { 24 "bin": {
25 - "klasFileDownloader": "./index.js" 25 + "klasFD": "./index.js"
26 }, 26 },
27 "homepage": "https://sungjunyoung.github.io", 27 "homepage": "https://sungjunyoung.github.io",
28 "dependencies": { 28 "dependencies": {
......