String15

Add japannine crawling method

1 const Discord = require("discord.js"); 1 const Discord = require("discord.js");
2 exports.run = async (client, msg, args, prefix) => { 2 exports.run = async (client, msg, args, prefix) => {
3 if (args[0]) { // 명령어 뒤에 입력값이 있을 경우 (ex. !<명령어> <채팅>) 3 if (args[0]) { // 명령어 뒤에 입력값이 있을 경우 (ex. !<명령어> <채팅>)
4 - // 검색어 한 문장으로 합치기
5 - const search = args.join(' ');
6 - // console.log(search);
7 -
8 // 각 사이트별 제품 검색 4 // 각 사이트별 제품 검색
9 const puppeteer = require('puppeteer'); //include Puppeteer Library 5 const puppeteer = require('puppeteer'); //include Puppeteer Library
10 puppeteer.launch({headless:true}).then(async browser => { 6 puppeteer.launch({headless:true}).then(async browser => {
...@@ -17,10 +13,10 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -17,10 +13,10 @@ exports.run = async (client, msg, args, prefix) => {
17 console.log("bestpen crawling"); 13 console.log("bestpen crawling");
18 await page .goto('http://www.bestpen.kr'); 14 await page .goto('http://www.bestpen.kr');
19 15
20 - // 검색창으로 이동 & search 검색 16 + // 검색창으로 이동 & args[0] 검색
21 await page.waitForSelector('#header > div.headerBtm > div > p.searchOpen > i'); 17 await page.waitForSelector('#header > div.headerBtm > div > p.searchOpen > i');
22 await page .click('#header > div.headerBtm > div > p.searchOpen > i'); 18 await page .click('#header > div.headerBtm > div > p.searchOpen > i');
23 - await page .type('#keyword', search); 19 + await page .type('#keyword', args[0]);
24 await page .keyboard.press( "Enter" ); 20 await page .keyboard.press( "Enter" );
25 // await page.screenshot({ path : "screenshot.png" }); 21 // await page.screenshot({ path : "screenshot.png" });
26 } catch { ; } // 사이트 링크에 이상이 생겼거나 검색에 문제가 생겼을 경우 프로그램이 종료되는 것을 방지 22 } catch { ; } // 사이트 링크에 이상이 생겼거나 검색에 문제가 생겼을 경우 프로그램이 종료되는 것을 방지
...@@ -68,9 +64,9 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -68,9 +64,9 @@ exports.run = async (client, msg, args, prefix) => {
68 console.log("pencafe crawling"); 64 console.log("pencafe crawling");
69 await page .goto('http://www.pencafe.co.kr'); 65 await page .goto('http://www.pencafe.co.kr');
70 66
71 - // search 검색 67 + // args[0] 검색
72 await page.waitForSelector('#header > div.hd_mib > div.hd_sch.f_left > form > fieldset > input'); 68 await page.waitForSelector('#header > div.hd_mib > div.hd_sch.f_left > form > fieldset > input');
73 - await page .type('#header > div.hd_mib > div.hd_sch.f_left > form > fieldset > input', search); 69 + await page .type('#header > div.hd_mib > div.hd_sch.f_left > form > fieldset > input', args[0]);
74 await page .keyboard.press( "Enter" ); 70 await page .keyboard.press( "Enter" );
75 // await page.screenshot({ path : "screenshot.png" }); 71 // await page.screenshot({ path : "screenshot.png" });
76 } catch { ; } // 사이트 링크에 이상이 생겼거나 검색에 문제가 생겼을 경우 프로그램이 종료되는 것을 방지 72 } catch { ; } // 사이트 링크에 이상이 생겼거나 검색에 문제가 생겼을 경우 프로그램이 종료되는 것을 방지
...@@ -86,7 +82,7 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -86,7 +82,7 @@ exports.run = async (client, msg, args, prefix) => {
86 // 펜카페 구조상 제품명 앞에 할인률(ex. 17%)이 붙는 경우가 많음 -> 제거 82 // 펜카페 구조상 제품명 앞에 할인률(ex. 17%)이 붙는 경우가 많음 -> 제거
87 if (pencafe_title.indexOf('%') != -1) { pencafe_title = pencafe_title.slice(pencafe_title.indexOf('%')+1); } 83 if (pencafe_title.indexOf('%') != -1) { pencafe_title = pencafe_title.slice(pencafe_title.indexOf('%')+1); }
88 // 펜카페 구조상 제품명 뒤에 사족(ex. (색상선택/금장~~~))이 붙는 경우가 많음 -> 제거 84 // 펜카페 구조상 제품명 뒤에 사족(ex. (색상선택/금장~~~))이 붙는 경우가 많음 -> 제거
89 - if (pencafe_title.indexOf('(') != -1) { pencafe_title = pencafe_title.slice(0, pencafe_title.lastIndexOf('(')); } 85 + if (pencafe_title.lastIndexOf(')') == pencafe_title.length-1) { pencafe_title = pencafe_title.slice(0, pencafe_title.lastIndexOf('(')); }
90 86
91 var link = await page.waitForSelector('#searchWrap > div > div.item-wrap > div:nth-child(2) > dl:nth-child('+i+') > dd > ul > li.prd-name > a'); 87 var link = await page.waitForSelector('#searchWrap > div > div.item-wrap > div:nth-child(2) > dl:nth-child('+i+') > dd > ul > li.prd-name > a');
92 var pencafe_link = await page.evaluate( link => link.href, link ); 88 var pencafe_link = await page.evaluate( link => link.href, link );
...@@ -109,7 +105,7 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -109,7 +105,7 @@ exports.run = async (client, msg, args, prefix) => {
109 } catch { 105 } catch {
110 if (i == 1) { 106 if (i == 1) {
111 // 제품 정보가 아예 없을 경우 "검색결과 없음"으로 표시 107 // 제품 정보가 아예 없을 경우 "검색결과 없음"으로 표시
112 - pencafe += "검색결과 없음" + '\n' 108 + pencafe += "검색결과 없음" + '\n';
113 break; 109 break;
114 } else { 110 } else {
115 // 제품 개수가 4개 이하인 경우 111 // 제품 개수가 4개 이하인 경우
...@@ -123,9 +119,9 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -123,9 +119,9 @@ exports.run = async (client, msg, args, prefix) => {
123 console.log("blueblack crawling"); 119 console.log("blueblack crawling");
124 await page .goto('https://blueblack.co.kr'); 120 await page .goto('https://blueblack.co.kr');
125 121
126 - // search 검색 122 + // args[0] 검색
127 await page.waitForSelector('#keyword'); 123 await page.waitForSelector('#keyword');
128 - await page .type('#keyword', search); 124 + await page .type('#keyword', args[0]);
129 await page .keyboard.press( "Enter" ); 125 await page .keyboard.press( "Enter" );
130 // await page.screenshot({ path : "screenshot.png" }); 126 // await page.screenshot({ path : "screenshot.png" });
131 } catch { ; } // 사이트 링크에 이상이 생겼거나 검색에 문제가 생겼을 경우 프로그램이 종료되는 것을 방지 127 } catch { ; } // 사이트 링크에 이상이 생겼거나 검색에 문제가 생겼을 경우 프로그램이 종료되는 것을 방지
...@@ -142,9 +138,9 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -142,9 +138,9 @@ exports.run = async (client, msg, args, prefix) => {
142 var blueblack_link = await page.evaluate( link => link.href, link ); 138 var blueblack_link = await page.evaluate( link => link.href, link );
143 // console.log("블루블랙 검색 링크 : ", blueblack_link); 139 // console.log("블루블랙 검색 링크 : ", blueblack_link);
144 140
145 - var price = await page.waitForSelector('#contents > div:nth-child(4) > ul > li:nth-child('+i+') > div.description > ul > li:nth-child(3) > span:nth-child(2)'); 141 + // 링크 구조상 &search 뒷부분은 제품 링크를 띄우는데 영향을 미치지 않음
146 - var blueblack_data = await page.evaluate( price => price.textContent, price ); 142 + // -> 글자수 제한(1024)도 있으므로 제거
147 - // console.log("블루블랙 검색 결과 가격 : ", blueblack_data); 143 + pencafe_link = pencafe_link.slice(0, pencafe_link.indexOf('&cate_no'));
148 144
149 try { 145 try {
150 // 품절 아이콘이 있는지 확인 146 // 품절 아이콘이 있는지 확인
...@@ -152,14 +148,85 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -152,14 +148,85 @@ exports.run = async (client, msg, args, prefix) => {
152 return element.getAttribute("src"); 148 return element.getAttribute("src");
153 }); 149 });
154 150
155 - blueblack_data = 'SOLD OUT' 151 + blueblack_data = 'SOLD OUT';
156 - } catch { ; } 152 + } catch {
153 + // 품절 아이콘이 없을 경우
154 + var price = await page.waitForSelector('#contents > div:nth-child(4) > ul > li:nth-child('+i+') > div.description > ul > li:nth-child(3) > span:nth-child(2)');
155 + var blueblack_data = await page.evaluate( price => price.textContent, price );
156 + // console.log("블루블랙 검색 결과 가격 : ", blueblack_data);
157 + }
157 158
158 blueblack += `[${blueblack_title}](${blueblack_link}) - ${blueblack_data}` + '\n'; 159 blueblack += `[${blueblack_title}](${blueblack_link}) - ${blueblack_data}` + '\n';
159 } catch { 160 } catch {
160 if (i == 1) { 161 if (i == 1) {
161 // 제품 정보가 아예 없을 경우 "검색결과 없음"으로 표시 162 // 제품 정보가 아예 없을 경우 "검색결과 없음"으로 표시
162 - blueblack += "검색결과 없음" + '\n' 163 + blueblack += "검색결과 없음" + '\n';
164 + break;
165 + } else {
166 + // 제품 개수가 4개 이하인 경우
167 + break;
168 + }
169 + }
170 + }
171 +
172 + // 4. 재팬나인
173 + try {
174 + console.log("japannine crawling");
175 + await page .goto('http://www.japan9.co.kr');
176 +
177 + // args[0] 검색
178 + await page.waitForSelector('body > center > table:nth-child(7) > tbody > tr > td > table:nth-child(1) > tbody > tr > td:nth-child(2) > table > tbody > tr > td:nth-child(2) > input');
179 + await page .type('body > center > table:nth-child(7) > tbody > tr > td > table:nth-child(1) > tbody > tr > td:nth-child(2) > table > tbody > tr > td:nth-child(2) > input', args[0]);
180 + await page .keyboard.press( "Enter" );
181 + // await page.screenshot({ path : "screenshot.png" });
182 + } catch { ; } // 사이트 링크에 이상이 생겼거나 검색에 문제가 생겼을 경우 프로그램이 종료되는 것을 방지
183 +
184 + // 검색 결과 가져오기 (최대 4개)
185 + var japannine = '';
186 + for (var i = 1; i <= 4; i++) {
187 + try {
188 + var title = await page.waitForSelector('#mk_search_production > tbody > tr:nth-child('+(5+((i-1)*4))+') > td:nth-child(3) > a');
189 + var japannine_title = await page.evaluate( title => title.textContent, title );
190 + // console.log("재팬나인 검색 결과 제품명 : ", japannine_title);
191 +
192 + // 재팬나인 구조상 제품명 앞에 항상 '/n'이 붙는다 -> 제거
193 + japannine_title = japannine_title.slice(1);
194 + // 재팬나인 구조상 제품명 앞과 뒤에 [쿠폰적용 || 주문예약상품]이 붙는 경우가 많음 -> 제거
195 + if (japannine_title.indexOf('[') == 0) { japannine_title = japannine_title.slice(japannine_title.indexOf(']')+1); }
196 + if (japannine_title.lastIndexOf(']') == japannine_title.length-1) { japannine_title = japannine_title.slice(0, japannine_title.lastIndexOf('[')); }
197 + if (japannine_title.indexOf('{') == 0) { japannine_title = japannine_title.slice(japannine_title.indexOf('}')+1); }
198 + if (japannine_title.lastIndexOf('}') == japannine_title.length-1) { japannine_title = japannine_title.slice(0, japannine_title.lastIndexOf('{')); }
199 +
200 + var link = await page.waitForSelector('#mk_search_production > tbody > tr:nth-child('+(5+((i-1)*4))+') > td:nth-child(3) > a');
201 + var japannine_link = await page.evaluate( link => link.href, link );
202 + // console.log("재팬나인 검색 링크 : ", japannine_link);
203 +
204 + // 링크 구조상 &search 뒷부분은 제품 링크를 띄우는데 영향을 미치지 않음
205 + // -> 글자수 제한(1024)도 있으므로 제거
206 + japannine_link = japannine_link.slice(0, japannine_link.indexOf('&search'));
207 +
208 + try {
209 + // 품절 아이콘이 있는지 확인
210 + var img_src = await page.$eval('#mk_search_production > tbody > tr:nth-child('+(5+((i-1)*4))+') > td:nth-child(6) > img', element => {
211 + return element.getAttribute("src");
212 + });
213 +
214 + if (img_src.indexOf('no_amount0') != -1) { japannine_data = 'SOLD OUT'; }
215 + } catch {
216 + // 품절 아이콘이 없을 경우
217 + var price = await page.waitForSelector('#mk_search_production > tbody > tr:nth-child('+(5+((i-1)*4))+') > td.brandprice > span');
218 + var japannine_data = await page.evaluate( price => price.textContent, price );
219 + // console.log("재팬나인 검색 결과 가격 : ", japannine_data);
220 +
221 + // 재팬나인 구조상 금액 뒤에 (옵션에 따라 변동)이 붙는 경우가 있다 -> 제거
222 + if (japannine_data.indexOf('(') != -1) { japannine_data = japannine_data.slice(0, japannine_data.indexOf('원')+1); }
223 + }
224 +
225 + japannine += `[${japannine_title}](${japannine_link}) - ${japannine_data}` + '\n';
226 + } catch {
227 + if (i == 1) {
228 + // 제품 정보가 아예 없을 경우 "검색결과 없음"으로 표시
229 + japannine += "검색결과 없음" + '\n';
163 break; 230 break;
164 } else { 231 } else {
165 // 제품 개수가 4개 이하인 경우 232 // 제품 개수가 4개 이하인 경우
...@@ -174,7 +241,7 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -174,7 +241,7 @@ exports.run = async (client, msg, args, prefix) => {
174 241
175 // 검색 결과 챗봇에 출력 242 // 검색 결과 챗봇에 출력
176 let Commands = new Discord.MessageEmbed() 243 let Commands = new Discord.MessageEmbed()
177 - .setTitle(`${search}에 대한 검색 결과`) 244 + .setTitle(`${args[0]}에 대한 검색 결과`)
178 .setColor("E5D49A") 245 .setColor("E5D49A")
179 // 베스트펜 검색 결과 (ex. 제품명(링크) - 금액) 246 // 베스트펜 검색 결과 (ex. 제품명(링크) - 금액)
180 .addField('베스트펜', `${bestpen.slice(0, 1023)}`) 247 .addField('베스트펜', `${bestpen.slice(0, 1023)}`)
...@@ -182,6 +249,8 @@ exports.run = async (client, msg, args, prefix) => { ...@@ -182,6 +249,8 @@ exports.run = async (client, msg, args, prefix) => {
182 .addField('펜카페', `${pencafe.slice(0, 1023)}`) 249 .addField('펜카페', `${pencafe.slice(0, 1023)}`)
183 // 블루블랙 검색 결과 250 // 블루블랙 검색 결과
184 .addField('블루블랙', `${blueblack.slice(0, 1023)}`) 251 .addField('블루블랙', `${blueblack.slice(0, 1023)}`)
252 + // 재팬나인 검색 결과
253 + .addField('재팬나인', `${japannine.slice(0, 1023)}`)
185 msg.reply({ embeds: [Commands] }); 254 msg.reply({ embeds: [Commands] });
186 }); 255 });
187 256
......