Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Puppeteer: Headless Chrome용 Node.js 라이브러리

지난달에 Headless Chrome으로 AWS Lambda에서 웹사이트 스크린샷 찍기에 대해서 글을 올렸는데 이때는 Chrome Launcherchrome-remote-interface를 조합해서 사용했다. 동작 방식을 이해하기는 좋지만 간단한 기능을 위해서 손이 많이 가서 불편하다.

Puppeteer

Puppeteer는 Headless Chrome을 쉽게 사용할 수 있도록 Google Chrome팀에서 공개한 Node.js 라이브러리다. 크롬 팀에서 직접 만들었기 때문에 믿고 쓸 수 있고 사용해본 결과 꽤 잘 만들었다.

앞에서 언급한 Chrome Launcherchrome-remote-interface와는 달리 Puppeteer은 올인원 라이브러리라고 생각하면 된다. 그래서 크롬 버전이나 Chrome Devtools Protocol에 대해 몰라도 그냥 사용할 수 있다. 크롬을 조작하는 API도 잘 구성되어 있다.

설치

npm i puppeteer로 설치해서 사용할 수 있는데 puppeteer은 호환되는 최신 Chromium을 다운받아서 사용한다. 그래서 로컬에 설치된 Chrome 버전과 상관없이 항상 잘 동작할 수 있다. Peppeteer은 Headless Chrome만 사용할 수 있는 것은 아니지만 이 목적으로 만들어졌으므로 기본적으로 Headless Chrome으로 동작한다.

온라인에서 사용해 볼 수 있는 데모 페이지도 제공하므로 여기서 테스트해볼 수 있다.

사용방법

Puppeteer는 문서가 잘 되어 있어서 쉽게 사용방법을 배울 수 있다. 처음 공개될 때는 Node.js 7.6.0 이상만 지원했지만, 지금은 6.4.0도 지원한다. 문서의 예제 코드는 대부분 async/await로 되어 있으므로 여기서는 Promise 기반의 코드로 설명하겠다.(코드는 거의 같다.)

// run.js
const puppeteer = require('puppeteer');

puppeteer.launch()
  .then((browser) => {
    return browser.newPage()
      .then((page) => {
        return page.goto('https://github.com/')
          .then(() => page.screenshot({path: 'github.png'}))
      })
      .then(() => browser.close());
  });

이 코드를 node run.js로 실행하면 https://github.com/ 사이트를 띄워서 스크린샷을 찍고 현 위치에 github.png로 저장한다.(기본 사이즈는 800x600이다.) 깔끔한 async/await를 Promise로 변경해서 좀 보기 안 좋게 되어 있지만 잘 동작한다. 이전 글에서 복잡한 코드로 Headless Chrome을 다루던 것에 비해 내부 동작을 추상화해서 아주 쉽게 사용할 수 있다. 비슷하게 page.pdf() 함수를 사용하면 이미지 대신 PDF로 저장할 수 있다.

// run.js
const puppeteer = require('puppeteer');

puppeteer.launch()
  .then((browser) => {
    return browser.newPage()
      .then((page) => {
        return page.goto('https://google.com/', { waitUnitl: 'networkidle' })
          .then(() => page.$('#lst-ib'))
          .then((search) => search.click())
          .then(() => page.type('puppeteer'))
          .then(() => page.$('input[type="submit"]'))
          .then((submit) => submit.click())
          .then(() => page.waitForNavigation())
          .then(() => page.screenshot({path: 'google.png'}))
      })
      .then(() => browser.close());
  });

이번에는 페이지를 조작하는 예제이다. https://google.com/에 접속해서 검색 칸에 puppeteer를 입력하고 검색하기 버튼을 누른 결과화면을 google.png로 캡쳐한 것이다. 코드를 보면 직관적이라서 Selenium 식의 브라우저를 다루는 코드를 작성해 본 적이 있다면 쉽게 이해할 수 있는 코드이고 상세 메서드와 옵션은 API 문서를 참고하면 된다.

Puppeteer는 기본적으로 Headless 모드로 동작하므로 디버깅이나 확인의 목적으로 실제 브라우저 동작을 보려면 puppeteer.launch({ headless: false })처럼 headless 옵션을 꺼주어야 한다. 이렇게 하면 실제 Chromium이 실행되면서 동작하는 것을 볼 수 있다.(엄청 빠르지만!!)

Puppeteer를 사용해 본 결과 너무 잘 만들어져 있고 편해서 Chrome Launcherchrome-remote-interface를 사용할 이유가 그다지 없어 보였다. 크롬 팀이 직접 만들어서 안정성도 좋아 보인다.

2017/09/27 19:31 2017/09/27 19:31