bluejoyq

Merge branch 'apiPR' into 'master'

search pr

까먹고 pull 안하고 
branch push 했으니ㅜㅜ
search만 merge 부탁합니다.

See merge request !7
1 +const rp = require("request-promise");
2 +const cheerio = require("cheerio");
3 +const Entities = require('html-entities').XmlEntities;
4 +const machineRead = require('./machineRead');
5 +
6 +const entities = new Entities();
7 +
8 +const searchURL = {
9 + "naver" : "https://search.naver.com/search.naver?",
10 + "google" : "https://www.google.com/search?"
11 +}
12 +
13 +/**
14 + * @param {string} keywordText 검색할 키워드
15 + * @param {cheerio} $ cheerio임.
16 + * @param {string} elem 내용을 찾을 html의 selector인거같음
17 + * @return {boolean} 찾았다면 true
18 + * @description 주어진 html의 selector에서 keyword의 내용을 찾아 여부를 반환
19 + */
20 +const keywordChecking = ( keywordText, $, elem ) => {
21 + let tempCheck = false;
22 + keywordText.split( ' ' ).forEach( ( Word ) => {
23 + if( $( elem ).text().indexOf( Word ) !== -1 ) {
24 + tempCheck = true;
25 + }
26 + });
27 +
28 + if( tempCheck ) {
29 + return true;
30 + }
31 + return false;
32 +}
33 +
34 +/**
35 + * @param {Object} searchResult 검색된 내용이 담긴 빈 오브젝트
36 + * @param {cheerio} $ cheerio임.
37 + * @param {string} elem 내용을 찾을 html의 selector인거같음
38 + * @param {string} defaultURL url이 없을 경우 달아주는 비상용 원래 링크
39 + * @description 구글용 title passage 찾기함수
40 + */
41 +const google = ( searchResult, $, elem , defaultURL ) => {
42 + searchResult.passage = entities.decode( $( elem ).parent().parent().parent().text()).trim(),
43 + searchResult.url = decodeURIComponent( $( elem ).attr( "href" ) );
44 + searchResult.title = entities.decode( $( elem ).children("div").text() ); // title 캐오기 수정 가능
45 +
46 + if( searchResult.url.indexOf( "/url?q=" ) === 0 ) {
47 + searchResult.url = searchResult.url.replace( "/url?q=", "" );
48 + } else if( searchResult.url.indexOf( "/search?" ) === 0 ) {
49 + searchResult.url = "https://google.com" + searchResult.url;
50 + } else {
51 + searchResult.url = defaultURL;
52 + }
53 +}
54 +
55 +/**
56 + * @param {object} searchResult 검색된 내용이 담긴 빈 오브젝트
57 + * @param {cheerio} $ cheerio임.
58 + * @param {string} elem 내용을 찾을 html의 selector인거같음
59 + * @param {string} defaultURL url이 없을 경우 달아주는 비상용 원래 링크
60 + * @description 네이버용 title passage 찾기함수
61 + */
62 +const naver = ( searchResult, $, elem , defaultURL ) => {
63 + searchResult.title = $( elem ).parent().attr( "title" );
64 + searchResult.passage = entities.decode( $( elem ).parent().parent().parent().text()).trim(),
65 + searchResult.url = $( elem ).parent().attr( "href" );
66 +
67 + if( searchResult.url === undefined ) {
68 + searchResult.url = defaultURL;
69 + }
70 +}
71 +
72 +/**
73 + * @param {{title:string,passage:string,ulr:string}} searchResult 검색 결과가 담긴 object
74 + * @param {[]} result 최종 결과가 담기는 어레이
75 + * @param {boolean} keywordCheck 키워드가 확인됐는지 여부
76 + * @description 타이틀이 없을 경우 달아주거나 중복된 것들 제거하는 등의 역활을 해 최종적으로 결과에 담아주는 함수
77 + */
78 +const searchToResult = (searchResult, result, keywordCheck) => {
79 + searchResult.passage = searchResult.passage.replace( /(http(s)?:\/\/)([a-z0-9\w]+\.*)+[a-z0-9]{2,4}/gi, ' ' ).replace( /\s{1,}|\s{1,}|\r\n|\r|\n/g, ' ' ).trim();
80 +
81 + if( searchResult.title === undefined || !searchResult.title.length ) {
82 + searchResult.title = searchResult.passage.split(' ').slice( 0, 3 ).toString().replace(/,/g,' ') + "..";
83 + } else {
84 + searchResult.title = searchResult.title.replace( /(http(s)?:\/\/)([a-z0-9\w]+\.*)+[a-z0-9]{2,4}/gi, ' ' ).replace( /\s{1,}|\s{1,}|\r\n|\r|\n/g, ' ' ).trim();
85 + searchResult.passage = searchResult.passage.replace( searchResult.title, '' );
86 + }
87 +
88 + if( !result.length ) {
89 + if( keywordCheck ) {
90 + result.push( searchResult );
91 + }
92 + } else if( keywordCheck ) {
93 + // 공백 제거하고 비교
94 + if( result[ result.length - 1 ].passage.replace( /\s/g, '' ) !== searchResult.passage.replace( /\s/g, '' ) ) {
95 + result.push( searchResult );
96 + }
97 + }
98 +}
99 +
100 +/**
101 + * @param {string} main 검색할 사이트의 메인 내용이 들어있는 셀렉터를 줘야합니다.
102 + * @param {string} keywordText 분석할 키워드의 내용
103 + * @param {string} html html 파싱한 내용
104 + * @param {string} defaultURL url이 없을 경우 달아주는 비상용 원래 링크
105 + * @param {()=>{}} findSearchResult search result를 찾아주는 함수
106 + * @returns {{url:string,title:string,passage:string}[]} object 여러 개를 가진 list를 준다. 각 json의 url, title, passage로 접근가능
107 + * @description html을 크롤링한 데이터에서 url title passage를 캐오는 함수이다.
108 + */
109 +const getHtmlMain = ( main, keywordText, html, defaultURL, findSearchResult ) => {
110 + const $ = cheerio.load( html );
111 + let result = [];
112 + $( main ).each( (i, elem ) => {
113 + let keywordCheck = keywordChecking( keywordText, $, elem );
114 + if( keywordCheck ) {
115 + let searchResult = {};
116 + findSearchResult( searchResult, $, elem , defaultURL );
117 + searchToResult( searchResult, result, keywordCheck );
118 + }
119 + });
120 + return result;
121 +}
122 +
123 +const search = {};
124 +
125 +/**
126 + * @param {string} keywordText 검색할 내용
127 + * @returns {{url:string,title:string,passage:string}[]} object 여러 개를 가진 list를 준다. 각 json의 url, title, passage로 접근가능
128 + * @description 네이버에서 키워드의 내용을 크롤링해온다.
129 + */
130 +search.naver = ( keywordText ) => {
131 + return new Promise( async ( resolve, reject ) => {
132 + let naverMain = "#main_pack strong",
133 + result = [],
134 + naverURL = searchURL.naver + "query=" + encodeURI( keywordText );
135 + rp( {
136 + "uri" : naverURL,
137 + } )
138 + .then( ( html ) => {
139 + result = getHtmlMain( naverMain, keywordText, html, naverURL, naver );
140 + resolve( result );
141 + })
142 + .catch( ( err ) => {
143 + throw new Error( err );
144 + });
145 + })
146 +}
147 +
148 +/**
149 + * @param {string} keywordText 검색할 내용
150 + * @returns {{url:string,title:string,passage:string}[]} object 여러 개를 가진 list를 준다. 각 json의 url, title, passage로 접근가능
151 + * @description 구글에서 키워드의 내용을 크롤링해온다.
152 + */
153 +search.google = ( keywordText ) => {
154 + return new Promise( ( resolve, reject ) => {
155 + let googleMain = "#main a",
156 + result = [],
157 + googleURL = searchURL.google + "q=" + encodeURI( keywordText )
158 +
159 + rp( {
160 + "uri" : googleURL,
161 + })
162 + .then( ( html ) => {
163 + result = getHtmlMain( googleMain, keywordText, html, googleURL, google );
164 + resolve( result );
165 + })
166 + .catch( ( err ) => {
167 + throw new Error( err );
168 + });
169 + })
170 +}
171 +
172 +module.exports = search;
...\ No newline at end of file ...\ No newline at end of file