PhantomJS로 GRID&CHART를 PDF 출력하기 (1편 : 시작하기)

웹포넌트 그리드차트는 웹 상에서 표현된 데이터를 Excel, CSV, PDF 등의 파일로 추출하는 기능을 가지고 있습니다.


데모 보러가기 클릭!!


그 중 PDF를 추출하는 기능은 PhantomJS 라는 툴을 이용하여 만들었는데요, PDF추출 기능을 구현하며 처음 사용해  된 PhantomJS!

세상 모든것들이 그렇듯 잘 사용하기만 하면 아주 유용한 녀석입니다.

만들면서 많은 시행착오를 겪게 되었는데요, 앞으로 몇 회에 걸친 글을 통해 구현하면서 얻게 된 Know How와 Tip들을 공유해보도록 하겠습니다. 

그 첫 시간으로 PhantomJS란 과연 무엇인지에 대한 간략한 설명과 함께 기본적인 Screen capture에 대해 설명하도록 하겠습니다.



1. PhantomJS 란?


PhantomJS 공식 홈페이지에 있는 설명입니다. 대강 해석해보면 

"JavaScript, DOM, CSS, JSON, Canvas, SVG와 같은 웹 표준을 Control할 수 있는 Headless Webkit Utility"

정도 될 것 같군요. 쉽게 설명하면 "브라우저 화면없이 웹을 컨트롤 할 수있는 도구" 정도로 이해하시면 큰 무리가 없으실 겁니다.



PhantomJS가 어디어디에 쓰일 수 있는지 설명하고 있습니다. 이 또한 공식 홈페이지에 있는 내용인데요, 웹사이트 테스팅, 페이지 자동화, 네트워크 모니터링 등 여러가지로 사용될 수 있지만 나머지는 다 패스하고 저희는 스크린 캡쳐에 관한 내용만 집중적으로 살펴보겠습니다.



2. 설치

본격적으로 Screen Capture에 대해 이야기하기 전에 PhantomJS 설치방법을 간략해 설명드리겠습다.



Windows나 Mac에서의 설치방법은 비교적 간단합니다. 위 페이지의 다운로드 링크를 통해 zip파일을 다운로드 후 압축만 풀어주시면 실행파일이 생성되서 바로 사용하실 수 있는데요, Linux같은 경우는 아직 Binary package가 없다고 하네요(2015. 06. 24기준). 어쩔수 없이 소드코드를 다운받아서 빌드하셔야 합니다. 빌드방법은 홈페이지에 잘 나와있으니 요기로 가셔서 확인하시면 될 것 같네요.



3. Screen Capture

약간은 지루한 설치과정을 다 마치셨으면, 이제야 드디어 실제로 웹 화면을 캡쳐해보도록 하겠습니다!!!

복잡한 설정과 이미지, 스타일적용은 다음편 포스팅에서 자세히 다루기 위해 조금 미뤄두고, 이번편에서는 간단히 캡쳐결과만 나오는 js파일을 작성해 보도록 할게요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Web Page를 Control 하기 위한 Web Page Module 객체 생성
var page = require('webpage').create();
 
// PhantomJS에서 화면을 어떤 사이즈로 출력할 것인지에 대한 값
// 미디어 쿼리도 동작
page.viewportSize = { width: 1024, height: 768 };
 
// 페이지 오픈
page.open('http://www.naver.com'function(status) {
 
    // status 인자를 통해 성공, 실패여부 확인
    if (status !== 'success') {
        console.log('Cannot open site');
        phantom.exit();
 
    } else {
        // 페이지가 렌더링 되는 시간(2초) 기다린 후
        window.setTimeout(function () {
            page.render('screenshot.pdf');    // 스크린 캡쳐파일 생성
              phantom.exit();
        }, 2000);
    }
});
cs

아주아주 간단한 캡쳐 코드입니다. 실제 웹포넌트 그리드&차트에 사용된 코드의 아주일부분을 차용해서 작성한 것인데요, PhantomJS는 JavaScript코드를 통해 동작하기 때문에 위와같이 우리에게 익숙한 JavaScript코드를 통해 작성하시면 됩니다.

실제로 위의 코드를 capture.js로 저장하신 후에 PhantomJS가 설치된 경로에서

> phantomjs capture.js

명령어를 입력하시면 screenshot.pdf파일이 생성되는것을 확인하실 수 있습니다.

이 시점에 첫번째 고민이 시작됩니다.

18 line에 보시면 페이지렌더링 때문에 setTimeout() 함수를 사용해서 2초를 기다리고 있죠. 그런데 이런 방식으로 사용하다보면 리소스가 많아질 경우 페이지가 완전히 렌더링 되지 않았는데도 스크린샷이 찍히거나, 리소스가 완전히 로딩이 되었는데 timeout을 기다려서 시간이 낭비가 될 경우가 생기더라구요.

이제 이 부분을 해결해 보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Web Page를 Control 하기 위한 Web Page Module 객체 생성
var page = require('webpage').create();
 
// PhantomJS에서 화면을 어떤 사이즈로 출력할 것인지에 대한 값
// 미디어 쿼리도 동작
page.viewportSize = { width: 1024, height: 768 };
 
page.onLoadFinished = function(status) {
    console.log('onLoadFinished Status: ' + status);
 
    page.render('screenshot.pdf');    // 스크린 캡쳐파일 생성
      phantom.exit();
}
 
// 페이지 오픈
page.open('http://www.google.com'function(status) {
    // status 인자를 통해 성공, 실패여부 확인
    if (status !== 'success') {
        console.log('Cannot open site');
        phantom.exit();
    } 
});
cs

setTimeout() 함수를 없애고 대신에 page.onLoadFinished 이벤트 리스터를 추가했습니다(8 line). 이제 페이지의 요소들의 로딩이 끝나는 시점에 Event listener를 통해서 페이지를 캡쳐 할 것입니다.



이렇게 해서 기본적인 PDF를 출력하는 Script가 완성되었습니다. 하지만 이것만으로는 많이 부족하죠.

실제로 PDF출력 기능을 구현하면서 CSS적용, 폰트, 페이지 설정, PDF Header, Footer 삽입 등 여러가지 문제에 직면했었습니다.


이어지는 글에서 그 직면했던 문제들을 어떻게 해결했는지 계속 포스팅 하겠습니다. 그러면 다음 포스팅을 기다리며 이만~~



capture.js  -> 첨부파일 확인 해 보셔요~
















New Multi-Channel Dynamic CMS