[DevOps] Chromeless 에서 Puppeteer로의 전환

[DevOps] Chromeless 에서 Puppeteer로의 전환

안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 Headless 브라우저를 통하여 웹을 제어 하는 내용에 대해서 소개를 하고자합니다. 필자가 속한 프로젝트에서는 협업툴로 Slack을 주로 사용하는데요. 장애 상황시에 모니터링에 대한 알람을 슬랙채널을 통해서 하고 있었습니다.

하지만, 운영자라고해서 누구든지 알람에 대해서 대응을 할 순 없습니다. 우리도 사람이니깐요.🤔

20분이 지나게 되면, 슬랙을 통하여 전화알람을 걸어주고 있는데요. 기존에 적용된 내용은 Chromeless로 작성된 코드였습니다. 단순히 웹에 접속하고, 해당 운영자에게 Direct call을 클릭하는 간단한 구조입니다.

위에 보시는 것은 슬랙 화면입니다. 실제로 슬랙은 협업툴로 굉장히 유명합니다. 필자가 속한 프로젝트에서도 많이 활용을 하고 있는데요. 채팅기능을 통해서 해당 사용의 유니크한 URL로 접속을 한 뒤(개인 메신저) 상단에 전화 아이콘을 클릭하게 되면, 전화가 되게 됩니다.

1. Headless Browser란 무엇인가요?

헤드리스 브라우저라고 보통 지칭하며, 말그대로 머리가 없는(?) 브라우저입니다. 통상 브라우저라고 생각을 하게되면, 크롬,IE, 사파리, 파이어폭스 등 여러가지 도구들이 있습니다. 헤드리스 브라우저는 GUI환경으로 눈에 보이는 것이 아니라, 가상의 브라우저를 띄워서 실제 브라우징을 하는것과 같이 행동을 하게끔 하는 것입니다.

즉, 프로그래밍이 가능하다는 것입니다.

Headless 브라우저 이미지 발췌

헤드리스 브라우저를 통해서 보통은 Crawling을 많이 하는 것 같습니다. 크롤링은 웹페이지를 돌아다니면서 정보들을 수집하는 것인데, 아무래도 GUI환경에서 직접 하게되면 많은 자원과 시간이 소모가 되니, headless를 통해서 하게 되면, 훨신 간편한것 같습니다.

2. Chromeless에서 Puppeteer로..

기존에 정리된 소스코드는 Chromless 기반으로 작성이 되어있었습니다. 사실 엄밀하게 말하자면, Puppeteer로 이전하게 된것은 좀더 낫은 Document와 좀더 낫은 API들로 구성이 되어있기 때문에 이전하게 되었습니다.

크롬리스 패키지

위에 접속하게 되면, 크롬리스의 npm 모듈을 확인할 수 있습니다. 간단한 소스코드 예제부터 try-it 화면까지 손쉽게 헤드리스 브라우저를 다뤄 볼 수 있습니다. 적용하면서 가장크게 아쉬웠던 것은, 브라우저를 켜고 끄는 부분에서 에러가 발생하거나, 예기치 못한 이슈로 인해서 문제가 발생했을 때, 브라우저가 꺼지지 않아서 memory 및 cpu를 점유한다는 문제가 있었습니다.

크롬리스는 아래에서 보시는 것처럼 2가지 방식으로 호출이 됩니다. 통상 local machine 에 chromium을 설치해서 사용하는 방식이 대게들 많이 사용하는 것 같습니다.

async function run() {
  var managersList=[
        'https://dotcomsystemworkspace.slack.com/?redir=%2Fmessages%2FDQJKV1H9Q',
        ];

  var manager = shuffle.pick(managersList);

  var msg = ''
  const chromeless = new Chromeless()

  const call = await chromeless
    .setViewport({width: 2000, height: 1400, scale: 1})
    .clearCookies()
    .clearCache()
    .setUserAgent('Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36')
    .goto(manager)
    .type('{ID}', 'input[id="email"]')
    .type('{PASSWORD}', 'input[id="password"]')
    .click('#signin_btn')
    .wait(6000)
    .wait('button.c-button-unstyled.p-classic_nav__model__button')
    .evaluate(()=>{
        $('button.c-button-unstyled.p-classic_nav__model__button').click();
    })
    .wait(30000)

  await chromeless.end()
}

위의 코드가 크롬리스로 작성된 코드인데요. 굉장히 간결해보입니다. id/pw를 입력하고, sign-in 한다음에 전화표기 버튼을 눌러서 전화를 거는 것입니다.

3. Puppeteer란 무엇인가요?

푸피티어라고 보통 한글로 읽는데, 정확하게 이야기하면 꼭두각시 라는 표현이 맞습니다. 꼭두각시는 실로 연결해서 인형을 움직이게 하는 것을 생각해 볼수 있는데요. 푸피티어는 헤드리스 브라우저를 이용해서 브라우저의 웬만한 모든 기능들을 활용 할 수 있는 것으로 볼때, 작명은 정말 잘한 것 같습니다.

푸피티어 공식 깃헙

위의 공식 URL을 접속하게 되면, 설치부터 활용방법 예제 까지 다양하게 볼 수 있습니다. 아무래도 구글에서 크롬 브라우저를 만든데다가 푸피티어까지 만들었으니, 가장 신뢰하고 사용할 수 있는 오픈 소스 인것 같습니다.

(async () => {

                var managersList=[
          'https://dotcomsystemworkspace.slack.com/?redir=%2Fmessages%2FDQXDS0JDB'
        ];

            var manager = shuffle.pick(managersList);
            console.log(manager);

            var msg = ''

        //** Create Browser
        const browser = await puppeteer.launch({args: ['--no-sandbox'], timeout: 50000});

        //** Create page and settings
        const page = await browser.newPage();
        await page.setCacheEnabled(false);
        await page.setViewport({width: 2000, height: 1400, deviceScaleFactor: 1});
        await page.setUserAgent('Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36');

        try{

                //** Test Scenario
                console.log("::: Start Test :::");
                                response = await page.goto(manager, {timeout: 50000});
                                await page.type('#email', "{아이디}" );
                                await page.type('#password', "{패스워드}" );
                                await wait(3000);

                                await page.waitForSelector("#signin_btn", {timeout : 2000}),
                                await page.click('#signin_btn'),
                                await wait(6000);

                                const element_call = await page.$('button.p-classic_nav__model__button');
                                await element_call.click();
                                await wait(3000);
                                await page.screenshot({path: 'full.png', fullPage: true});

                                 //await page.evaluate(() => console.log(`url is ${location.href}`));

        }catch(e){
                //** Catch error and take screenshot
                console.log("Error : " + e);
        }finally{
                //** Close all resource
                console.log("::: Close All Resource :::");
                await page.close();
                await browser.close();
        }
})();

소스상으로는 크게 차이는 없어보입니다. 다만, Puppeteer에서 제공해주는 다양한 API들을 활용할 수 있고, 특히나 console.log등에서 나오는 문구도 볼수 있고, console창 자체를 제어도 가능합니다.

4. 마치며…

슬랙을 통해서 알람에 대응을 하기 위해 전화기능을 추가했습니다. 직접 브라우징을 하는것보다는 헤드리스를 통해서 하는 것이 효율적이라고 생각했고, 현재는 잘 동작하고 있습니다. 헤드리스를 통해서 크롤링 하는 기능을 좀더 학습을 해봐야될 것 같습니다.

2 Replies to “[DevOps] Chromeless 에서 Puppeteer로의 전환”

  1. 워니즈님 포스팅 늘 잘 읽고 있습니다. ^^
    다음 포스팅도 기대할께요!
    푸피티어 라고 읽는군요 (퍼펫이어로 알고 있었어요 ㅎㅎ)

    1. 푸피티어, 푸페티어라고 읽기도 하는거 같습니다^^ ㅎㅎ 정확한 표현은 영문이라…….앞으로 다른 포스팅도 기대부탁드립니다!

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다