캡쳐, 스크린샷은 화면에 보이는 부분을 이미지로 저장 하는 것입니다.
웹사이트 스크린샷은, 브라우저에 보이는 웹사이트의 이미지를 저장 하는 것이죠.
뭐 어려운 기술인가요? 아니오. 누구나 할수 있습니다.
스크린샷을 만드는 과정을 한번 생각해봅시다.
네. 하나부터 열까지 전부 수동 입니다.
내 손으로 하지 않으면 캡쳐도 없는 것입니다.
그런데요.
캡쳐해야할 사이트가 1000개 라면?
5분 마다 캡쳐 해야 한다면?
여러분은 수동으로 할 수 있습니까?
너무 너무 힘들겠죠.
그래서 자동 스크린샷이 필요합니다.
자동으로 스크린샷을 만드려면 다음의 조건을 충족 해야 합니다.
자동화는 그다지 어렵지 않습니다.
하지만 자동 스크린샷의 핵심은 방법이 아니고 유지하는 기술 입니다.
캡쳐할 양이 많아지고, 시간이 흐르면 많은 문제가 튀어나옵니다.
이런 문제를 관리하고 해결하는 것이 이 기술의 핵심 입니다.
여러분이 보고 계신 크롬과 동일한 스크린샷을 얻으려면 제일 좋은 방법은 그냥 크롬을 쓰는 것입니다.
그런데 크롬은 사람이 쓰도록 만들어졌기 때문에 사람에게만 편리합니다.
사람은 웹페이지가 다 준비되지 않아도 보이는 부분을 먼저 읽을 수 있습니다.
또, 뭔가 이상하다고 느끼면 새로고침을 할 수 도 있죠.
“뭔가 이상하다”고 느끼는 것은 여러분이 사람이니까 할 수 있는 행동 입니다.
컴퓨터로 크롬을 사람 처럼 제어해서 캡쳐를 하려면 생각보다 쉽지 않아요.
하지만 세상이 좋아졌습니다.
크롬이 2020년부터 Headless Mode 를 지원하거든요.
이름 그대로 머리 없는 모드 입니다. 직역하면 그렇고
Headless 가 붙으면 보통 보이지 않는 것(invisible)과 동일하다고 보시면 됩니다.
그래서 크롬의 Headless 모드라는 것은
여러분 PC와 똑같은 크롬을 실행하는데
모니터나 화면이 필요없이 메모리 상에서만 화면을 그린다는 것이죠.
서버 환경에서 자동으로 크롬을 Healdless 모드로 띄운 후에
스크린샷을 만들거나, E2E 테스팅을 하기가 너무 좋아졌다는 뜻입니다.
(사실 서버용 크롬은 Chromium 이라는 크롬의 엔진 부분만 사용하는 브라우저가 따로 있습니다.)
이 기능을 적극적으로 사용 합니다.
하지만 어떻게?
대표적으로 puppeteer 가 있습니다.
puppeteer 는 구글 크롬의 devtools 개발팀에서 관리되는 오픈소스로
크롬 Headless 모드를 활용한 스크래핑, 스크린샷, 테스팅에 적합한 node.js 라이브러리 입니다.
또한 playwright 가 생겼는데, puppeteer 개발자가 Google에서 Microsoft로 이직하여 내놓은 라이브러리로
puppeteer 는 크롬만 지원하는 반면에 playwright 는 크롬, 파이어폭스, 엣지를 모두 지원 합니다.
또 이들 상위에 browserless 라는 상용 서비스도 생겨났는데,
이 라이브러리는 유료이긴 하지만 puppeteer, playwright, selenium 등 모두 통합하여 지원 합니다.
아무튼, 스크린샷 정도는 puppeteer 하나로도 충~분 합니다.
selenium 이라는 e2e 테스팅 도구를 이런 용도로 많이 사용 했지만요.
이 툴은 복잡하고 느립니다. 셀레니엄을 제대로 구동하기 위해서는 상당한 의존성이 필요합니다.
정말 허무할 정도로 초간단 합니다.
코드를 보겠습니다.
아! 아래 코드는 개발자가 아니어도 이해하는데 문제가 없을거에요.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
// 크롬에 새 탭을 열고 준비될 때 까지 기다립니다.
const page = await browser.newPage();
// 그 탭을 원하는 사이트로 이동 시키고 기다립니다.
await page.goto('https://imweb.me');
// 지금 보이는 화면을 imweb.png 로 고대로 저장 합니다.
await page.screenshot({ path: 'imweb.png' });
// 브라우저를 종료 합니다.
await browser.close();
})();
이게 전부 입니다.
headless 모드 이든 아니든 크롬은 일단 무겁습니다. (느립니다)
또한 소스 코드와 크롬이 별개의 프로세스로 돌아가며 websocket api 을 통한 네트워크 통신으로 크롬을 제어하기 때문에 동시성과 세션 관리가 참으로 난감 합니다.
사람은 크롬을 혼자 사용하니 동시에 구동하는 탭은 한개 뿐입니다.
(동시에 탭을 10개 열고 페이지 10개를 동시에 컨트롤 하는 분이 계신가요?)
하지만 서버는 다르죠. 이와 관련한 문제가 뻥뻥 터집니다.
사람이 쓰더라도 같은 도메인은 쿠키가 유지되기 때문에 세션 관리가 애매해 집니다.
구글 계정이 여러개일때 탭별로 로그인을 다르게 하기 어려운 이치와 같습니다.
서버에서 구동하는 크롬이라면? 서로 다른 유저로 같은 사이트에 2개의 탭? 역시 불가능 합니다.
이런 문제를 해결 한다고, 매번 크롬을 새로 띄워 캡쳐를 한다면
크롬이 부팅 되는데만 5초 이상 소요될 것이고
스크린 캡쳐 하나 하겠다고 CPU와 RAM을 왕창 써댈 것입니다.
매번 크롬을 켜고 끄는것은 정말로 심한 시간 낭비이며, 리소스 낭비 입니다.
따라서, 요청의 큐를 관리하고, 각 세션 별로 Incognito mode (시크릿 창) 를 사용하는 것이 가장 나은 대안일 것입니다.
하지만 이런 고급 기능은 오픈소스 라이브러리 기본 기능이 아닙니다.
프로덕션 레벨에서는 이런 문제를 해결해야 제대로 사용할 수 있습니다.
그래서 스크린샷을 활용 합니다.
아임웹은 고객사가 변경을 할 때마다 새로운 스크린샷이 준비되어 활용 됩니다.
위에 설명한 오픈소스를 대용량에 맞게 커스텀 하여
사용 한답니다.
이렇게 우리 고객을 바라보는 눈을 만들고, 더 나은 서비스를 위해 노력하고 있습니다.
댓글로 질문을 남겨주세요!
감사합니다.
안녕하세요. 예전에 잠시동안 매튜님께 개발을 배웠었는데, 기억하시려는지 모르겠네요.
여전히 재미있는 프로젝트를 하고 계시는군요!
위 작업은 배치성으로 이루어진 것이죠?
이벤트 드리븐으로 변경이 있을 때 마다 스크린샷 작업을 실행하는 방식도 있을 것 같은데요.
배치로 처리하신 이유와 장단점이 궁금합니다. :)
ps. 아임웹이 SaaS 이다보니, 고객이 웹사이트를 수정하려면 제공되는 기능을 실행하는 구조일 것 같아서 드린 질문입니다. :) 만약 고객이 임의대로 수정할 수 있는 구조라면 해당 사항이 없겠네요.