node.js - phantomjs, http (210223)
node - 스크래핑( 크롤링 ) - html과 결합됨
http client
urllib -> axios
html, xml, json
striptags
cheerio
…
*PhantomJS / Selenium = ajax로 가져오는 내용을 추출
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() {
setTimeout( function() {
page.render( 'google.png' );
phantom.exit();
}, 200 );
});
|
cs |
ES6 -> ES5 버전 사용해야함
ajax 방식의 데이터는 시간을 두고 데이터를 가져와야함
처음에 구조만 만들고 데이터를 나중에 가져오는 방식이기 때문에
setTimeout으로 시간을 두고 데이터를 가져오도록 코드 구성
phantom2.js
데이터를 가져와서 출력 (크롤링)
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' ) {
setTimeout( function() {
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으로 접속해서 실행 확인
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방식은 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 = "";
for( let 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 = "";
for( let 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 |