Skip to content

Instantly share code, notes, and snippets.

@ho4040
Created December 9, 2018 23:56
Show Gist options
  • Select an option

  • Save ho4040/45f031c359665520729d315cb7f4bae8 to your computer and use it in GitHub Desktop.

Select an option

Save ho4040/45f031c359665520729d315cb7f4bae8 to your computer and use it in GitHub Desktop.
Puppeteer

Pupeteer?

어디에 사용 ?

  • 웹페이지의 를 캡춰하여 PDF 생성
  • UI 테스트를 자동화 할 수 있음
  • timline trace 를 캡춰하여 사이트 성능파악에 활용 할 수 있음
  • 웹스크래핑을 할 수 있음

인스톨

npm 을 사용하여 간단히 설치 가능. Node v6.4 이상 버젼 설치. async/await 를 사용하려면 Node v7.6 이상부터.

npm install puppeteer

개발자 도구를 사용하나, 크롬익스텐션을 사용 하고 싶다면 다음을 추가로 설치

npm install puppeteer-core

비동기 동작

대부분의 Puppeteer 코드는 비동기로 작동하기 때문에 async await 키워드를 사용하거나, .then() 을 활용하여야 함. async, await를 활용하는게 코드가 깨끗해짐.

주요 클래스

Browser

Puppeteer 를 사용함에 있어서 가장 기본이 되는 클래스

const puppeteer = require('puppeteer')
(async ()=>{
	const browser = await puppeteer.launch();
	const page = await browser.newPage();
	await page.goto("http://www.naver.com");
	await page.pdf({path:'naver.pdf', format:'A4'});
	await browser.close();
})();

이처럼 puppeteer.launch() 함수를 이용하여 생성 launch 함수 인자로 {headless : flase} 를 넣으면 GUI 모드로 켜지게 됨.

모든 사용이 끝나면 close 메소드를 이용하여 자원 해제.

Page

크롬에서 하나의 탭과 상호작용 하는 목적으로 사용된다. 하나의 브라우져에서 여러개의 페이지를 만들어 사용 하는 것도 가능하다.

노드의 EventEmitter 를 확장한 클래스로, 기본 on, once , removeListener 등을 사용 가능하다.

page.once('load', ()=>{console.log('page loaded!')})

사용 가능한 이벤트는 (https://pptr.dev/#?product=Puppeteer&version=master&show=api-class-page) 에서 확인 가능.

주요 메소드

자주 쓰이는 함수에 대한 설명, 전체 내용은 공식 문서를 통해서 확인이 가능 https://pptr.dev/#?product=Puppeteer&version=master

$(selector)

document.querySelector 를 수행하여 selector 에 해당하는 DOM 엘리먼트 의 EventHandle을 가져온다. 없는경우에는 null 이 resolve 된다.

$$(selector)

document.querySelectorAll 을 수행하여 얻은 DOM 엘리먼트의 EventHandle 배열을 가져온다. 해당하는 항목이 없는 경우에는 []을 resolve 한다. page.mainFrame().$$(selector) 와 동일한 기능을 수행

$$eval(selector, pageFunction[, ...args])

브라우져 컨텍스트 상에서 함수를 실행하여 값을 돌려준다. pageFunction 에 추가인자를 전달하고 싶을때 args 를 사용하여 전달 할 수 있다.

사용예:

const divCounts = await page.$$eval('div', divs=>divs.length );

위 코드의 divs 에 브라우져에서 Array.from(document.querySelectorAll(div)) 한 값이 들어오게 된다.

$eval(selector, pageFunction[, ...args])

$$eval 과 유사하지만 document.querySelector 를 활용하여 한개의 엘리먼트 만을 대상으로 동작한다.

사용예:

const html = await page.$eval('.main-container', e=>e.outerHTML);

waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])

selectorOrFunctionOrTimeout 인자로 뭘 넣느냐에 따라서 다르게 동작한다.

await  page.waitFor('.foo');  // wait for selector  
await  page.waitFor(1000);  // wait for 1 second  
await  page.waitFor(()  =>  !!document.querySelector('.foo')); // wait for predicate  

string을 넣는 경우에는 selector 로 취급하여 waitForSelector 를 호출한다. waitForSelector 는 해당 selector 에 해당하는 element 가 페이지에 나타날 때 까지 대기를 한다. 만약에 이미 있었다면 바로 리턴한다. 옵션에 지정된 timeout 밀리세컨드 만큼의 시간에 의해 타임아웃이 발생하면, throw 한다.

function 을 넣는 경우에는 waitForFunction 을 호출한다. 이 funtions 은 브라우져 컨텍스트에서 수행하여 대기한다.

number 를 넣는 경우 타임아웃 밀리세컨드로 가정하고 해당 시간만큼 기다린다.

사용예

const  selector  =  '.foo';  
await  page.waitForFunction(selector  =>  !!document.querySelector(selector),  {},  selector);

waitForNavigation([options])

load 이벤트가 발생 할 시점까지 기다린다.

사용예:

const  [response]  =  await  Promise.all([  
	page.waitForNavigation({timeout:30000, waitUntil:'load'})
	page.click('a.my-link'),  
]);

page.reload(options)

페이지를 새로고침 한다. options 로는 timeout 이나 waitUntil 값을 사용 할 수 있다. waitUntil 값의 기본값은 'load' 이다.

page.screenshot([options])

페이지 스크린샷을 찍어 저장한다. encoding 옵션을 통해 base64로도 저장이 가능하다.

사용예:

await page.screenshot({path:'ss.jpg', type:'jpeg', quality:100, fullpage:true})

setCookie(...cookies)

쿠키를 지정한다.

let cObj = {name:'PHPSSID', value:'b12jf', url:'https://bla.com', httpOnly:true, path:'/'};
await page.setCookie(cObj)

page.setUserAgent(userAgent)

유저 Agent를 지정한다. 크롤링시 사이트에서 블록을 하는 기준이 되므로 잘 지정해서 사용해야 한다.

ElementHandle

ElementHandle 은 DOM-element 의 node 쪽 핸들이다. page.$ 메소드를 이용하여 얻어진다. 이 ElementHandle 또한 $, $$ 등의 메소드를 통해서 하위 엘리먼트 핸들을 얻어올 수 있다.

const  puppeteer  =  require('puppeteer');  
  
puppeteer.launch().then(async  browser  =>  {  
const  page  =  await  browser.newPage();  
await  page.goto('https://google.com');  
const  inputElement  =  await  page.$('input[type=submit]');  
await  inputElement.click();  
// ...  
});

EventHandle 을 직접 page.evaluate 의 인자로 넣어줄 수도 있다.

사용예:

const  bodyHandle  =  await  page.$('body');  
const  html  =  await  page.evaluate(body  =>  body.innerHTML,  bodyHandle);

주요 메소드

자주 사용하는 메소드를 나열한다. 전체 목록은 문서(https://pptr.dev/#?product=Puppeteer&version=master&show=api-class-elementhandle) 를 참고.

click([options])

해당 DOM 엘리먼트를 클릭한다.

type(text[, options])

문자열을 입력한다. delay 옵션을 이용해서 키입력에 딜레이를 줄 수 있다. page.keyboard 를 통해 접근하는 것도 가능하다.

사용예:

const  elementHandle  =  await  page.$('input');  
await  elementHandle.type('some text', {delay:100});  
await  elementHandle.press('Enter');

Request / Response

page 클래스에서 발생하는 request, response 이벤트를 통해서 얻을 수 있는 객체이다.

사용예:

page.on('request',  logRequest(interceptedRequest)  {  
console.log('A request was made:',  interceptedRequest.url());  
});  
// Sometime later...  
page.removeListener('request',  logRequest);

주요 메소드

request.url(), response.url()

해당 HTTP 통신의 URL 을 얻어올 수 있다.

request.headers(), response.headers()

HTTP 통신에 사용한 Header 정보를 얻어 올 수 있다.

request.postData()

HTTP 통신시 보내진 postData 를 얻어올 수 있다.

response.text()

body로 전달된 값을 string 형태로 얻어온다. JSON 인 경우에는 response.json() 을 사용하는게 편할 수 있다.

response.status()

http status code 를 얻어온다. (예: success 인 경우는 200)

response.fromCache()

서버에서 온 데이터인지 캐싱되어 있던 데이터인지 알려주는 값이다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment