Javascript/node.js

node.js - phantomjs, http (210223)

꿀먹는매미 2021. 2. 23. 09:55

node - 스크래핑( 크롤링 ) - html 결합됨

http client

 

urllib -> axios

html, xml, json

striptags

cheerio

*PhantomJS / Selenium = ajax 가져오는 내용을 추출

 https://phantomjs.org

 

http server - webserver(tomcat)

socket

 

http / http2

 

 

 

 

 

 

phantom 설치하기

 

mkdir phantomex1

cd phantomex1

su - root

 

mkdir /usr/local/phantom

cd /usr/local/phantom

wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2

yum -y install bzip2

yum -y install fontconfig

tar xvf https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2

 

ls

ln -sf /usr/local/phantom/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/phantomjs

cat ./phantomjs-2.1.1-linux-x86_64/examples/hello.js

phantomjs --version

phantomjs /usr/local/phantom/phantomjs-2.2.1-linux-x86_64/examples/hello.js

 

exit

phantomjs --version

pwd

ls

npm install phantomjs

npm init -y

 

 

 

 

가상의 브라우저에서 캡쳐해서 이미지 가져옴

phantom1.js

1
2
3
4
5
6
7
8
9
10
11
// phantom1.js
"use strict";
 
var page = require( 'webpage' ).create();
 
page.open( 'https://www.google.com'function() {
      setTimeoutfunction() {
            page.render( 'google.png' );
            phantom.exit();
      }, 200 );
});
cs

 

ES6 -> ES5 버전 사용해야함

ajax 방식의 데이터는 시간을 두고 데이터를 가져와야함

처음에 구조만 만들고 데이터를 나중에 가져오는 방식이기 때문에

setTimeout으로 시간을 두고 데이터를 가져오도록 코드 구성

 

phantom2.js

https://cleanair.seoul.go.kr

데이터를 가져와서 출력 (크롤링)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// phantom2.js
"use strict";
 
// ES6 -> ES5
var page = require( 'webpage' ).create();
 
page.open( 'https://cleanair.seoul.go.kr/airquality/localAvg'function( status) {
      if( status == 'success' ) {
            setTimeoutfunction() {
                  var html = page.evaluate( function() {
                        return document.getElementById( 'localAvg-table' ).innerHTML;
                  });
 
                  console.log( html );
 
                  phantom.exit();
                  
            }, 200);
      }
} );
cs

 

 

 

 


http

 

 

cd

mkdir httpex1

cd httpex1/

npm init -y

 

httpex1.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// httpex1.js
"use strict";
 
const http = require( 'http' );
 
// server 실행
http.createServer( (req, res) => {
      //console.log( req );
 
      //res.end( 'Hello Node Server!!!' );
 
      //res.end( '<html><head></head><body><h2>Hello Node Sever!!!</h2></body></html> );
 
      const html = `<html>
      <head></head>
      <body><h2>Hello Node Server!!!</h2>
      </body>
      </html>
      `;
      res.end( html );
 
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ... ' );
});
cs

터미널에서

node httpex1.js

종료는 ctrl+c

 

브라우저에서 localhost:8080으로 접속해서 실행 확인

localhost:8080

 

 

httpex2.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//httpex2.js
"use strict";
 
const http = require( 'http' );
 
// server 실행
const server = http.createServer( (req, res) => {
      const html = `<html>
      <head></head>
      <body><h2>Hello Node Server2!!!</h2>
      </body>
      </html>
      `;
      res.end( html );
}); 
server.listen( 8080 );
server.on( 'listening', () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
});
server.on( 'error', err => {
      console.log( err.message );
});
cs

html을 템플릿으로 만들어서 사용하면 반복적인 html 코드 사용 줄일수 있음

template1.html

1
2
3
4
5
6
7
8
9
10
<!-- template1.html -->
<!DOCTYPE html>
<html>
      <head>
            <meta charset="utf-8" />
      </head>
      <boad>
            <h1>Node.js 웹 서버</h1>
      </boad>
</html>
cs

 

httpex3.js

jsp처럼 파일 받아오기

서버설정과 실행 분리

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
// httpex3.js
"use strict";
 
const http = require( 'http' );
const fs = require( 'fs' );
 
// server 실행
const server = http.createServer( (req, res) => {
      const filename = './template1.html';
      fs.readFile( filename, ( err, data ) => {
            if!err ) {
                  res.write( data );
                  res.end();
                  
                  //res.end( data );
            } else {
                  console.err( err.message );
            }
      } );
}); 
server.listen( 8080 );
server.on( 'listening', () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
});
server.on( 'error', err => {
      console.log( err.message );
});
cs

 

 

httpex4.js

파일검사하고 파일 받아오기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// httpex4.js
"use strict";
 
const http = require( 'http' );
const fs = require( 'fs' );
 
// server 실행
const server = http.createServer( (req, res) => {
      const filename = './template1.html';
      fs.access( filename, fs.constants.F_OK, err => {
            if!err ) {
                  fs.readFile( filename, ( err, data ) => {
                        res.write( data );
                        res.end();
                  } );
            }
      });
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

실행결과는 같음

 

 

 

 

httpex5.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// htmlex5.js
"use strict";
 
const http = require( 'http' );
 
const server = http.createServer( (req, res) => {
 
      console.log( req.method );
      
      console.log( req.url );
      //console.log( req.headers );
      console.log( req.headers[ 'user-agent' ] );
 
      res.end();
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

 

 

다른 환경에서 접속해보기

window의 브라우저에서 접속해보려면 방화벽을 개방해야 한다.

cd /usr/lib/firewalld/services/

vi http.xml

<port protocol="tcp" port="8080"/> 추가

firewall-cmd --zone=public --add-service=http --permanent

firewall-cmd --reload

 

그 다음 리눅스서버의 ip주소:8080 으로 윈도우(다른클라이언트)의 브라우저 에서 접속해보기

소스를 실행후 브라우저로 접속하면 

콘솔 로그가 출력된다.

 

요청 url 분리하기

httpex6.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// htmlex6.js
"use strict";
 
const { copyFileSync } = require( 'fs' );
const http = require( 'http' );
 
const server = http.createServer( (req, res) => {
      console.log( req.url );
 
      if( req.url == '/' ) {
            res.end( 'page /' );
      } else if( req.url == '/test1' ) {
            res.end( 'page /test1' );
      } else if( req.url == '/test2' ) {
            res.end( 'page /test2' );
      } else {
            res.end ('page /etc' );
      }
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

 

 

 

url에 페이지 주소 입력하면 그 페이지 파일을 열도록 하기

 

요청에 따른 페이지 표시

  public_html  
/ index.html  
  site  
/test1   test1.html
/test2   test2.html
에러 error.html  

 

터미널에서

[master@localhost httpex1]$ pwd
/home/master/httpex1

인 상태에서

 

mkdir public_html

mkdir -p public_html/site

touch public_html/index.html

touch public_html/error.html

touch public_html/site/test1.html

touch public_html/site/test2.html

 

template1.html 복사해서 

index.html / error.html / test1.html / test2.html 붙여넣고 내용만 파일이름 따라서 만듬

 

 

httpex6.js 수정

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
// htmlex6.js
"use strict";
 
const fs = require( 'fs' );
const http = require( 'http' );
 
const server = http.createServer( (req, res) => {
      //console.log( req.url );
 
      if( req.url == '/' ) {
            fs.readFile( './public_html/index.html', ( err, data ) => {
                  if!err ) {
                        res.end( data );
                  } else {
                        console.err( err.message );
                  }
            } );
      } else if( req.url == '/test1' ) {
            fs.readFile( './public_html/site/test1.html', ( err, data ) => {
                  if!err ) {
                        res.end( data );
                  } else {
                        console.err( err.message );
                  }
            } );
      } else if( req.url == '/test2' ) {
            fs.readFile( './public_html/site/test2.html', ( err, data ) => {
                  if!err ) {
                        res.end( data );
                  } else {
                        console.err( err.message );
                  }
            } );
      } else {
            fs.readFile( './public_html/error.html', ( err, data ) => {
                  if!err ) {
                        res.end( data );
                  } else {
                        console.err( err.message );
                  }
            } );
      }
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

 

 

url주소 값대로 html파일을 보여줌

=> controller 처럼 사용

 

 

위 소스를 간단하게 줄이기

htmlex7.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// htmlex7.js
"use strict";
 
const fs = require( 'fs' );
const http = require( 'http' );
 
const server = http.createServer( (req, res) => {
      if( req.url == '/' ) {
            fs.createReadStream( './public_html/index.html' ).pipe(res);
      } else if( req.url == '/test1' ) {
            fs.createReadStream( './public_html/site/test1.html' ).pipe(res);
      } else if( req.url == '/test2' ) {
            fs.createReadStream( './public_html/site/test2.html' ).pipe(res);
      } else {
            fs.createReadStream( './public_html/error.html' ).pipe(res);
      }
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

 

출력 결과는 같음

 

 

post방식 / get방식

 

/form           form.html

/form_ok       get          - form_ok.html

                   post        - 

 

jsp             - tomcat

node.js       서버 - coding           => 최신언어

 

웹서버(nginx)      - node.js - 코딩

 

htmlex8.js

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
// httpex8.js
"use strict";
 
const fs = require( 'fs' );
const http = require( 'http' );
const url = require( 'url' );
 
const server = http.createServer( (req, res) => {
 
      // querystring 있다면
      let parsed = url.parse( req.url, true );
      console.log( parsed.pathname, ' / ', req.url );
 
      if( parsed.pathname == '/form' ) {
            fs.createReadStream( './public_html/form.html' ).pipe(res);
      } else if( parsed.pathname == '/form_ok' ) {
            if( req.method.toLocaleLowerCase() == 'post' ) {
                  console.log( 'post' );
                  //fs.createReadStream( './public_html/form_ok.html' ).pipe(res);
                  req.on( 'data', chuck => {
                        console.log( 'processing' );
                  } );
 
                  req.on( 'end', () => {
                        console.log( 'end' );
                  } );
            } else {
                  console.log( 'get' );
                  //fs.createReadStream( './public_html/form_ok.html' ).pipe(res);
 
                  // event
                  req.on( 'data', chuck => {
                        console.log( 'processing' );
                  } );
 
                  req.on( 'end', () => {
                        console.log( 'end' );
                  } );
            }
      } else {
            fs.createReadStream( './public_html/error.html' ).pipe(res);
      }
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

 

public_html 폴더에

form.html 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// form.html
<!DOCTYPE html>
<html>
      <head>
            <meta charset="utf-8" />
      </head>
      <boad>
            <h1>form.html</h1>
            <form action="./form_ok" method="get">
                  data : <input type="text" name="data" />
                  <input type="submit" value="전송" />
            </form>
            <form action="./form_ok" method="post">
                  data : <input type="text" name="data" />
                  <input type="submit" value="전송" />
            </form>
      </boad>
</html>
cs

 

form_ok.html 생성

1
2
3
4
5
6
7
8
9
10
// form_ok.html
<!DOCTYPE html>
<html>
      <head>
            <meta charset="utf-8" />
      </head>
      <boad>
            <h1>form_ok.html</h1>
      </boad>
</html>
cs

 

결과

각각 전송을 누르면

 

 

post / get 방식의 데이터 처리 (데이터 가져오기)

 

post는 스트림처럼 '누적'된 데이터를 받아서

query로 뽑아서 보는 방식

get 방식은 url을 분리해서 데이터를 보면 됨

 

htmlex9.js

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
// httpex9.js
"use strict";
 
const fs = require( 'fs' );
const http = require( 'http' );
const url = require( 'url' );
const querystring = require( 'querystring' );
 
const server = http.createServer( (req, res) => {
 
      // querystring 있다면
      let parsed = url.parse( req.url, true );
      console.log( parsed.pathname, ' / ', req.url );
 
      if( parsed.pathname == '/form' ) {
            fs.createReadStream( './public_html/form.html' ).pipe(res);
      } else if( parsed.pathname == '/form_ok' ) {
            if( req.method.toLocaleLowerCase() == 'post' ) {
                  // post 방식의 데이터 처리
                  let data = '';
                  req.on( 'data', ( chuck ) => {
                        data += chuck;       
                  } );
 
                  req.on( 'end', () => {
                        console.log( 'end :', data );
                        
                        const query = querystring.parse( data );
                        console.log( query.data );
                  } );
            } else {
                  // get 방식의 데이터 처리
                  req.on( 'end', () => {
                        //console.log( 'end', req.url );
 
                        let query = parsed.query;
                        console.log( 'data :', query.data );
                  } );
 
            }
            fs.createReadStream( './public_html/form_ok.html' ).pipe(res);
      } else {
            fs.createReadStream( './public_html/error.html' ).pipe(res);
      }
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

get방식
post방식

get방식은 url에 데이터가 표시됨

post방식은 url에 표시 X

 

 

 

get방식으로 구구단 출력하기

 

public_html 폴더에 생성

gugudan.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//gugudan.html
<!DOCTYPE html>
<html>
      <head>
            <meta charset="utf-8" />
      </head>
      <boad>
            <h1>gugudan.html</h1>
            <form action="./gugudan_ok" method="get">
                  dan : <input type="text" name="dan" />
                  <input type="submit" value="전송" />
            </form>
      </boad>
</html>
cs

 

${ gugudanString }을 넘겨 받아서 구구단 출력

gugudan_ok.html

1
2
3
4
5
6
7
8
9
10
11
//gugudan_ok.html
<!DOCTYPE html>
<html>
      <head>
            <meta charset="utf-8" />
      </head>
      <boad>
            <h1>gugudan_ok.html</h1>
            ${ gugudanString }
      </boad>
</html>
cs

 

 

template literal화 해서 구구단 출력 문자열을 넘겨줌

gugudan1.js

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
//gugudan1.js
"use strict";
 
const fs = require( 'fs' );
const http = require( 'http' );
const url = require( 'url' );
const querystring = require( 'querystring' );
 
const server = http.createServer( (req, res) => {
      let parseUrl = url.parse( req.url, true );
 
      if( parseUrl.pathname == '/gugudan' ) {
            fs.createReadStream( './public_html/gugudan.html' ).pipe(res);
      } else if( parseUrl.pathname == '/gugudan_ok' ) {
            if( req.method.toLocaleLowerCase() == 'get' ) {
                  // 단수
                  let query = parseUrl.query;
                  console.log( query.dan );
 
                  let gugudanString = "";
                  forlet i=1; i<=9; i++ ) {
                        gugudanString += query.dan + " X " + i + " = " + query.dan * i + "<br />";
                  }
                  //fs.createReadStream( './public_html/gugudan_ok.html' ).pipe(res);
 
                  const data = fs.readFileSync( './public_html/gugudan_ok.html' );
                  // template literal화
                  const tpldata = eval'`' + data.toString().replace( /`/g, '\\`' ) + '`' );
                  
                  res.end( tpldata );
                 
            } else {
 
            }
      } else {
            fs.createReadStream( './public_html/error.html' ).pipe(res);
      }
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
cs

 

 

post 방식으로 구구단 출력하기

gugudan.html 에

post방식 form 추가

 

gugudan2.js

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
// gugudan2.js
"use strict";
 
const fs = require( 'fs' );
const http = require( 'http' );
const url = require( 'url' );
const querystring = require( 'querystring' );
 
const server = http.createServer( (req, res) => {
      let parseUrl = url.parse( req.url, true );
 
      if( parseUrl.pathname == '/gugudan' ) {
            fs.createReadStream( './public_html/gugudan.html' ).pipe(res);
      } else if( parseUrl.pathname == '/gugudan_ok' ) {
            if( req.method.toLocaleLowerCase() == 'post' ) {
                  // post 방식의 데이터 처리
                  let data = '';
                  req.on( 'data', ( chuck ) => {
                        data += chuck;       
                  } );
 
                  req.on( 'end', () => {
                        console.log( 'end :', data );
                        
                        const query = querystring.parse( data );
                        console.log( query.dan );
 
                        let gugudanString = "";
                        forlet i=1; i<=9; i++ ) {
                              gugudanString += query.dan + " X " + i + " = " + query.dan * i + "<br />";
                        }
 
                        const html = fs.readFileSync( './public_html/gugudan_ok.html' );
                        //console.log( html.toString() );
                        const tpldata = eval'`' + html.toString().replace( /`/g, '\\`' ) + '`' );
                        
                        res.end( tpldata );
                  } );
            } else {
            }
            fs.createReadStream( './public_html/gugudan_ok.html' ).pipe(res);
      } else {
            fs.createReadStream( './public_html/error.html' ).pipe(res);
      }
}).listen( 8080, () => {
      console.log( '8080 포트에서 요청 대기중 ...' );
} );
//gugudan_ok.html
<!DOCTYPE html>
<html>
      <head>
            <meta charset="utf-8" />
      </head>
      <boad>
            <h1>gugudan_ok.html</h1>
            ${ gugudanString }
      </boad>
</html>
cs