본문으로 건너뛰기

Playwright로 웹사이트 스크린샷을 자동화하는 방법

JavaScript와 Playwright로 웹사이트 스크린샷을 자동화합니다. 한 페이지, 전체 페이지, 모바일 화면, URL 일괄 캡처를 재시도와 함께 다룹니다.

11분 분량웹사이트 캡처작성자: Temposhot Team

Playwright는 Microsoft가 만든 브라우저 자동화 라이브러리입니다. Node.js, Python, Java, .NET에서 Chromium, Firefox, WebKit을 제어합니다. 이 글은 Node.js 패키지로 스크린샷 스크립트를 만듭니다. 한 페이지 캡처에서 시작해, 실패한 URL을 재시도하는 URL 일괄 캡처로 마무리합니다.

Playwright가 적합한 경우

스크린샷이 더 큰 기술 작업의 일부일 때 스크립트를 설정할 가치가 있습니다.

  • 배포 후마다 CI에서 캡처를 실행함
  • URL 목록을 사이트맵, 데이터베이스 또는 API에서 가져옴
  • 파일을 고정된 폴더 구조나 스토리지 버킷에 저장해야 함
  • 스크린샷 단계가 테스트, 스크레이핑 또는 PDF 생성과 함께 실행됨

이미지가 필요한 사람이 코드를 작성하지 않거나 목록이 매주 바뀐다면 노코드 도구가 보통 더 빠릅니다. 이 선택의 트레이드오프는 글 끝에서 다룹니다.

이 글의 실습 예제

예제는 하나의 작업을 목표로 합니다. 배포 후마다 사이트맵에 나열된 페이지 200개를 데스크톱과 휴대폰 크기로 캡처하고, 실패한 페이지를 보고합니다. 이 작업에는 스크린샷 스크립트를 어렵게 만드는 요소가 모두 있습니다. 긴 목록, 느린 페이지, 지연 로딩 이미지, 쿠키 배너, 간헐적인 타임아웃입니다.

작업의 수치는 추정값입니다. 실제 소요 시간은 사이트, 네트워크, 기기에 따라 달라집니다.

예제 작업의 통계 네 가지: URL 200개, 데스크톱과 휴대폰을 합친 스크린샷 400장, 병렬 워커 4개, 실행당 예상 10-20분.
추정은 워커 4개로 페이지당 3-6초를 가정함.

스크립트를 직접 운영하는 비용

스크립트는 무료이지만 유지보수가 필요 없는 것은 아닙니다. 사이트를 리뉴얼하면 쿠키 배너, 준비 완료 신호로 쓰는 요소, 스크롤 컨테이너가 바뀔 수 있고, 변경될 때마다 일괄 작업의 일부가 실패합니다.

Node.js 또는 다른 언어

네 가지 언어 바인딩의 스크린샷 API는 거의 같습니다. Python의 page.screenshot(path=..., full_page=True)는 Node.js의 fullPage: true와 같은 동작을 합니다. 파이프라인의 나머지 부분이 쓰는 언어를 고르면, 스크린샷 단계가 주변 코드와 같은 저장소와 CI 작업에 들어갑니다.

이 비용은 미리 계획에 넣습니다. 배포 후마다 실행하는 일괄 작업은 유지보수 비용을 금방 회수합니다. 1년에 두 번 실행하는 작업은 그 사이에 무엇인가 바뀌어서, 첫 실행부터 실패하는 경우가 많습니다.

스크린샷 스크립트용 Playwright 설치

mkdir site-shots && cd site-shots
npm init -y
npm install -D playwright
npx playwright install chromium

마지막 명령은 설치된 Playwright 버전과 맞는 Chromium 빌드를 내려받습니다. 아래 스크립트는 .mjs 확장자를 사용합니다. 번들러나 추가 설정 없이 최상위 await를 쓸 수 있습니다.

패키지 버전과 브라우저 버전 고정

각 Playwright 릴리스는 특정 브라우저 빌드를 요구합니다. playwright 패키지를 업그레이드한 뒤에는 npx playwright install chromium을 다시 실행합니다. 그렇지 않으면 스크립트가 실행 파일이 없다는 메시지와 함께 실패합니다.

package-lock.json을 커밋하면 모든 기기가 같은 버전을 설치합니다. Linux CI 러너에서는 npx playwright install --with-deps chromium이 브라우저에 필요한 시스템 라이브러리도 함께 설치합니다.

명령 목록: npx playwright install chromium은 브라우저를 내려받고, install with-deps는 Linux 라이브러리를 추가하며, npx playwright screenshot은 일회성 캡처를 찍고, npx playwright codegen은 로케이터를 기록합니다.

screenshot 명령은 일괄 작업에 넣기 전에 URL 하나를 확인할 때 유용합니다. --device와 --wait-for-selector 옵션도 받으므로, 느린 페이지를 터미널에서 테스트할 수 있습니다.

웹사이트 스크린샷 한 장 캡처

// one.mjs
import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1920, height: 1080 } });

await page.goto('https://example.com');
await page.screenshot({ path: 'example.png' });

await browser.close();

node one.mjs로 실행합니다. 브라우저는 헤드리스 모드로 시작하며, 창을 열지 않고 페이지를 렌더링합니다. 헤드리스 브라우저 항목에서 이 동작 방식을 설명합니다.

다른 옵션을 지정하지 않으면 파일은 정확히 1920×1080픽셀의 뷰포트 스크린샷입니다.

반복 가능한 캡처를 만드는 옵션

페이지가 바뀌지 않았다면 같은 페이지를 두 번 실행한 결과는 같은 이미지여야 합니다. 몇 가지 스크린샷 옵션으로 흔한 잡음 원인을 제거합니다. 애니메이션이 중간에 캡처되는 경우, 깜박이는 텍스트 커서, 기기마다 다른 픽셀 밀도가 여기에 해당합니다.

Playwright 스크린샷 옵션 설정 패널: fullPage는 true, type은 jpeg, quality는 80, animations는 비활성화, caret은 숨김, scale은 css, mask에는 로케이터 목록, timeout은 30000.
await page.screenshot({
  path: 'example.jpg',
  type: 'jpeg',
  quality: 80,
  animations: 'disabled',
  caret: 'hide',
  scale: 'css',
  mask: [page.locator('.ad-slot'), page.locator('.live-chat')],
});

mask는 일치하는 각 요소 위에 상자를 덮어 그립니다. 회전하는 광고, 실시간 타임스탬프, 채팅 위젯 때문에 실행마다 결과가 달라지는 것을 막는 가장 단순한 방법입니다.

빈 화면이나 잘못된 캡처 디버깅

스크린샷이 비어 있거나, 오류 페이지를 보여 주거나, 봇 검사 화면을 보여 준다면 브라우저가 실제로 본 내용을 확인해야 합니다. headless: false와 slowMo 옵션으로 실행하면 각 단계를 볼 수 있습니다. 또는 트레이스를 기록한 뒤 트레이스 뷰어에서 엽니다.

번호가 붙은 다섯 단계: 한 URL만 headless false로 다시 실행, page.goto의 응답 상태 기록, 스크린샷과 스냅샷을 포함한 트레이스 기록, npx playwright show-trace로 열기, 대기 조건이나 셀렉터 수정.

트레이스에는 페이지의 필름스트립과 각 동작의 네트워크 요청이 표시됩니다. 필름스트립에서는 페이지가 완전히 렌더링됐지만 캡처 결과가 비어 있다면, 스크린샷이 페이드인이 끝나기 전에 실행된 것입니다. animations: 'disabled'로 해결됩니다.

전체 페이지 스크린샷 캡처

스크롤 가능한 문서 전체를 캡처하려면 fullPage: true를 추가합니다.

await page.screenshot({ path: 'example-full.png', fullPage: true });

너비는 뷰포트 너비로 유지되고, 높이는 페이지에 맞게 늘어납니다. 매우 긴 페이지는 아주 높은 이미지를 만들며, 일부 이미지 뷰어는 이를 크게 축소해 보여 줍니다. 고정 헤더가 있는 페이지에서는 헤더가 맨 위에 한 번만 나타납니다. Playwright는 스크롤한 화면을 이어 붙이지 않고 문서를 한 번에 캡처하기 때문입니다.

대신 한 요소만 캡처하려면 로케이터에서 screenshot을 호출합니다. 예: page.locator('main').screenshot({ path: 'main.png' }).

고정 영역 캡처

clip은 CSS 픽셀 단위로 x, y, width, height를 받아 페이지의 사각형 영역을 저장합니다. 페이지의 처음 1200픽셀만 중요한 경우에 적합합니다. 예를 들어 첫 화면과 첫 번째 섹션만 담은 랜딩 페이지가 있습니다.

await page.screenshot({ path: 'hero.png', clip: { x: 0, y: 0, width: 1920, height: 1200 } });

짧은 페이지의 바닥을 넘어가는 clip은 페이지 끝에서 잘립니다. 모든 페이지에서 clip 크기가 같아야 한다면 이미지 높이를 확인합니다.

배치 스크립트에 대상 URL 넣기

URL을 텍스트 파일에 보관하면 목록을 바꿀 때 코드를 수정할 필요가 없습니다.

// batch.mjs
import { readFile, mkdir } from 'node:fs/promises';
import { chromium } from 'playwright';

const urls = (await readFile('urls.txt', 'utf8'))
  .split('\n').map((l) => l.trim()).filter(Boolean);

await mkdir('shots', { recursive: true });
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1920, height: 1080 } });

for (const [i, url] of urls.entries()) {
  const name = `shots/${String(i + 1).padStart(3, '0')}.png`;
  await page.goto(url, { waitUntil: 'load', timeout: 30000 });
  await page.screenshot({ path: name, fullPage: true });
  console.log('saved', url, name);
}

await browser.close();

0으로 채운 파일 이름(001.png 등)은 Finder에서 파일을 목록 순서대로 정렬합니다.

사이트맵으로 목록 만들기

예제 작업에서 목록은 sitemap.xml에서 가져옵니다. 실행을 시작할 때 한 번 가져와서 모든 loc 항목을 추출합니다. 이렇게 하면 urls.txt를 수정하지 않아도 새 페이지가 캡처됩니다.

const xml = await (await fetch('https://example.com/sitemap.xml')).text();
const urls = [...xml.matchAll(/<loc>(.*?)<\/loc>/g)].map((m) => m[1].trim());

위치 대신 페이지별로 파일 이름 짓기

001.png 같은 인덱스 이름은 사이트맵에 페이지가 추가되면 깨집니다. 그 뒤의 모든 파일이 하나씩 밀리기 때문입니다. URL 경로로 만든 이름은 실행 사이에도 유지됩니다. 예를 들어 /pricing/teams는 pricing-teams.png가 됩니다. 검토할 때 목록 순서가 중요한 경우에만 인덱스를 접두사로 유지합니다.

두 URL이 같은 이름으로 매핑될 수 있습니다. 예를 들어 끝에 슬래시가 있는 경로와 없는 경로가 그렇습니다. 실행 전에 중복 이름을 확인하고, 인덱스를 추가해 충돌을 해결합니다.

큰 사이트는 사이트맵을 여러 사이트맵을 가리키는 인덱스로 나눕니다. 이 링크를 한 단계 아래까지 따라가고, PDF 같은 파일 URL은 걸러냅니다. 파일은 페이지로 렌더링되지 않습니다.

여섯 개 상자가 화살표로 연결된 흐름도: sitemap.xml 가져오기, URL 큐 만들기, 워커가 페이지를 열고 준비 요소 대기, 지연 로딩 이미지를 위해 스크롤, 0으로 채운 이름으로 스크린샷 저장, failed.txt와 보고서 작성.

대규모 일괄 작업을 위한 동시 실행

한 번에 한 페이지씩 처리하면 URL이 수백 개일 때 느립니다. 각자 자기 페이지 객체를 가진 여러 페이지를 병렬로 실행하고, 메모리를 제어하도록 개수를 제한합니다.

const LIMIT = 4;
const queue = [...urls.entries()];

async function worker() {
  const page = await browser.newPage({ viewport: { width: 1920, height: 1080 } });
  while (queue.length) {
    const [i, url] = queue.shift();
    await page.goto(url);
    await page.screenshot({ path: `shots/${i + 1}.png`, fullPage: true });
  }
  await page.close();
}

await Promise.all(Array.from({ length: LIMIT }, worker));

노트북에서는 워커 4개로 시작하는 것이 적절합니다. 메모리 사용량을 확인한 뒤에만 한도를 올리고, 운영하지 않는 사이트에는 요청 빈도를 낮게 유지합니다.

워커 수에 따른 실행 시간 변화

기계나 사이트가 병목이 되기 전까지 실행 시간은 워커 수에 거의 비례해 줄어듭니다. 페이지당 4초로 추정하면 200페이지는 워커 1개로 약 13분, 워커 4개로 약 3.5분이 걸리며, 워커 8개로는 그보다 조금 더 적게 걸립니다.

그 지점을 넘으면 워커를 늘려도 대부분 메모리 부담과 서버 부하만 늘어납니다. 워커 수를 올렸을 때 스크린샷이 타임아웃되기 시작하면 사이트나 기계가 포화 상태이므로, 워커 수를 다시 줄입니다.

요청 빈도를 낮게 유지

페이지를 열 때마다 스크립트, 이미지, 폰트도 함께 로드되므로, 워커 4개는 한 서버에 초당 수십 건의 요청을 보낼 수 있습니다. 운영하지 않는 사이트에서는 워커를 1개나 2개로 두고, 페이지 사이에 1-2초 쉬는 시간을 둡니다. 큰 일괄 작업은 사이트의 사용량이 많은 시간을 피해 실행하고, 응답이 429 Too Many Requests로 바뀌면 중단합니다.

페이지 또는 컨텍스트

위 워커는 브라우저 컨텍스트 하나를 공유하므로 모든 페이지가 쿠키를 공유합니다. 한 페이지가 동의 쿠키를 설정하면 이후 페이지는 배너를 건너뛰고, 워커 순서에 따라 캡처 결과가 달라집니다. 모든 캡처를 깨끗한 상태에서 시작해야 한다면 browser.newContext()로 워커마다 별도 컨텍스트를 만듭니다.

모바일 또는 태블릿 스크린샷 캡처

Playwright는 뷰포트, 사용자 에이전트, 터치 지원, 픽셀 비율을 함께 설정하는 기기 디스크립터를 제공합니다.

import { chromium, devices } from 'playwright';

const browser = await chromium.launch();
const context = await browser.newContext({ ...devices['iPhone 13'] });
const page = await context.newPage();

기기마다 컨텍스트를 하나씩 사용하면 쿠키와 저장소가 분리됩니다. 태블릿은 같은 devices 목록에서 iPad 항목을 고르거나, 768×1024 같은 일반 뷰포트를 직접 설정합니다.

픽셀 비율과 파일 크기

휴대폰 디스크립터는 deviceScaleFactor를 2 또는 3으로 설정합니다. 너비 390픽셀 휴대폰 뷰포트를 배율 3으로 캡처하면 이미지 너비는 1170픽셀이 되고, 긴 페이지는 높이가 수만 픽셀에 이를 수 있습니다. 배율 1인 같은 페이지보다 픽셀이 아홉 배 많습니다.

레이아웃을 검토할 때는 스크린샷 옵션의 scale: 'css'로 이미지 픽셀 1개가 CSS 픽셀 1개에 대응하게 합니다. 휴대폰 화면에서 선명하게 보여야 할 때만 기기 배율을 유지합니다.

모바일 레이아웃이 로드됐는지 확인

일부 사이트는 서버에서 사용자 에이전트를 보고 레이아웃을 정하고, 다른 사이트는 CSS의 뷰포트 너비를 보고 정합니다. 디스크립터는 둘 다 설정하지만, 단순한 viewport 변경은 너비만 설정합니다. 휴대폰 캡처가 찌그러진 데스크톱 레이아웃으로 나오면, 단순 뷰포트 대신 전체 기기 디스크립터로 바꿉니다.

Safari에 가까운 렌더링을 위한 WebKit

대부분의 스크립트는 기본적으로 Chromium을 사용하지만, 실제 기기에서 iPhone 레이아웃은 WebKit으로 렌더링됩니다. Safari 고유의 렌더링이 중요하면 npx playwright install webkit으로 설치하고 webkit.launch()로 실행합니다.

두 열 비교표: chromium과 webkit을 나란히 두고, 설치 명령, iPhone의 Safari와의 근접성, page.pdf 지원 여부, 스크린샷 일괄 작업의 일반적 용도를 행으로 나눔.

지연 로딩 콘텐츠 처리

많은 페이지는 이미지를 화면에 들어올 때만 로드합니다. 로드 직후에 찍은 전체 페이지 캡처에는 아래쪽의 빈 상자가 보일 수 있습니다. 스크린샷 전에 페이지를 한 번 스크롤합니다.

await page.evaluate(async () => {
  for (let y = 0; y < document.body.scrollHeight; y += window.innerHeight) {
    window.scrollTo(0, y);
    await new Promise((r) => setTimeout(r, 200));
  }
  window.scrollTo(0, 0);
});

지연 로딩 항목에서 이 현상의 원인을 설명합니다.

이미지 디코딩이 끝날 때까지 대기

스크롤은 이미지 요청을 시작하지만, 이미지가 도착하기 전에 스크린샷이 실행될 수 있습니다. 스크롤 후에는 페이지의 모든 이미지가 완료됐다고 보고할 때까지 기다립니다.

await page.waitForFunction(() =>
  [...document.images].every((img) => img.complete && img.naturalWidth > 0)
);

깨진 이미지 URL은 완료되지 않으므로, 파일이 없는 페이지에서는 이 대기가 타임아웃될 수 있습니다. 타임아웃을 잡아서 그래도 캡처하고, 보고서에 해당 페이지를 표시합니다.

적절한 대기 전략 고르기

waitUntil 옵션은 goto가 언제 반환하는지 정합니다.

값반환 시점
loadload 이벤트가 발생함. 기본값임.
domcontentloaded이미지가 끝나기 전에 HTML 파싱이 끝남.
networkidle최소 500ms 동안 네트워크 요청이 없음.

Playwright 문서는 테스트에 networkidle 사용을 권장하지 않습니다. 폴링이나 분석 도구가 있는 페이지는 네트워크가 영영 조용해지지 않을 수 있기 때문입니다. 더 안정적인 방법은 페이지가 준비됐음을 나타내는 요소를 기다리는 것입니다. 예: await page.locator('main img').first().waitFor().

페이지 하나의 예시 타임라인: goto가 0.0초에 시작, 약 1.8초에 load 이벤트, 약 2.1초에 준비 요소 표시, 약 3.4초에 스크롤 종료, 약 3.9초에 page.screenshot이 파일 작성, 어떤 단계든 멈추면 30초 타임아웃이 상한.
예시 값이며 측정값이 아님.
do와 dont 행: 페이지 준비를 나타내는 로케이터 대기, goto 기본값으로 load 사용, goto와 screenshot에 30초 타임아웃 설정. dont 행: 모든 페이지에 page.waitForTimeout(5000) 추가, 분석이나 채팅이 있는 페이지에 networkidle 사용, 웹 폰트 로드 전에 캡처.

고정 대기 5초를 200페이지에 적용하면 워커 하나로 약 17분의 유휴 시간이 추가되며, 6초가 필요한 페이지 하나에서는 여전히 실패합니다. 로케이터 대기는 페이지가 준비되는 즉시 반환합니다. 폰트 문제는 await page.evaluate(() => document.fonts.ready)가 처리합니다.

재시도 추가

네트워크는 실패할 수 있고, 일부 페이지는 한 번 타임아웃되었다가 이후에 정상 로드됩니다. 캡처를 작은 재시도 헬퍼로 감쌉니다.

async function capture(page, url, path, tries = 3) {
  for (let attempt = 1; attempt <= tries; attempt++) {
    try {
      await page.goto(url, { timeout: 30000 });
      await page.screenshot({ path, fullPage: true });
      return true;
    } catch (error) {
      console.warn(`attempt ${attempt} failed for ${url}: ${error.message}`);
    }
  }
  return false;
}

false를 반환한 URL을 모아 failed.txt에 기록하면, 그 URL만 따로 다시 실행할 수 있습니다.

바뀌지 않는 실패는 재시도하지 않음

재시도는 타임아웃과 끊어진 연결에 도움이 됩니다. 404나 500을 반환하는 페이지에는 도움이 되지 않으며, 없는 페이지 20개를 세 번씩 시도하면 몇 분이 낭비됩니다. page.goto는 응답 객체를 반환하므로 response.status()를 확인하고, 상태 코드가 400 이상이면 재시도를 건너뜁니다.

보고서에는 URL 옆에 상태 코드를 기록합니다. 사이트맵에서 나온 404 목록은 그것만으로도 유용합니다. 오래된 사이트맵 항목을 가리키기 때문입니다.

충돌한 페이지 복구

무거운 사이트에서는 페이지가 충돌할 수 있으며, 그 페이지 객체의 이후 모든 goto는 예외를 던집니다. 재시도 헬퍼 안에서 오류 후 페이지를 닫고, 다음 시도를 위해 새 페이지를 엽니다. 워커는 계속 실행되며, 실패한 URL 하나가 큐의 나머지 작업을 망치지 않습니다.

실용적인 폴더 구조

site-shots/
  urls.txt
  batch.mjs
  shots/
    2026-03-24/
      desktop/001.png
      mobile/001.png
  failed.txt

실행마다 날짜 폴더를 만들면 이전 캡처가 그대로 남습니다. 기기별 하위 폴더를 만들면 나란히 놓고 검토하기가 쉬워집니다.

CI 실행이 업로드해야 하는 것

CI에서는 작업이 끝나면 러너가 삭제되므로, 스크린샷을 빌드 아티팩트로 업로드해야 합니다. 날짜 폴더, 실패 목록, 각 페이지의 URL, 상태, 파일 이름, 소요 시간을 담은 작은 JSON 보고서를 업로드합니다.

CI 아티팩트의 파일 트리: 데스크톱과 휴대폰 이미지 폴더를 담은 날짜별 실행 폴더, URL마다 항목 하나가 있는 report.json, failed.txt 목록.
여섯 항목의 체크리스트: Playwright 버전이 lockfile에 고정됨, 브라우저가 의존성과 함께 설치됨, 기준 기기와 같은 폰트가 러너에 설치됨, 컨텍스트에 locale과 timezoneId가 설정됨, 실행 폴더가 빌드 아티팩트로 업로드됨, failed.txt가 비어 있지 않으면 작업이 실패로 표시됨.

이전 실행과 비교

날짜 폴더가 두 개 있어도 누군가 차이를 살펴봐야 의미가 있습니다. 페이지가 몇 개뿐이면 Compare Images에서 같은 이름의 파일을 엽니다. 이 도구는 슬라이더와 픽셀 차이 보기를 제공합니다. 페이지가 수백 개라면 Playwright Test의 toHaveScreenshot 어서션이 각 캡처를 저장된 기준 이미지와 비교하고, 차이가 임계값을 넘으면 실패합니다.

노트북 실행과 CI 실행의 차이에서 가장 흔한 원인은 폰트입니다. 사이트의 대체 폰트가 없는 Linux 러너는 텍스트 너비를 다르게 렌더링하므로, 줄바꿈과 페이지 높이가 바뀝니다.

흔한 실수

  1. await를 빠뜨림. 파일이 쓰이기 전에 스크립트가 종료됩니다.
  2. 충돌 후 같은 페이지를 재사용함. goto가 target closed 오류를 던지면 새 페이지를 엽니다.
  3. 모든 페이지에서 networkidle에 의존함. 일부 페이지는 이 상태에 도달하지 않으며, 그 행은 모두 타임아웃됩니다.
  4. 쿠키 배너를 캡처함. 로케이터로 동의 버튼을 클릭하거나, page.addStyleTag로 배너를 숨깁니다.
  5. 사이트 이용 약관을 무시함. 운영하지 않는 사이트는 이용 약관과 robots 규칙을 확인하고 요청 빈도를 낮게 유지합니다.

쿠키 배너를 안정적으로 닫기

배너는 사이트마다 다르므로, 목록 전체에 하나의 셀렉터가 맞는 경우는 드뭅니다. 알려진 동의 버튼 목록을 순서대로 시도하며 버튼마다 2초 타임아웃을 두고, 실패하면 CSS로 배너 컨테이너를 숨깁니다.

const consent = page.getByRole('button', { name: /accept|agree|reject all/i });
if (await consent.first().isVisible({ timeout: 2000 }).catch(() => false)) {
  await consent.first().click();
}

동의 버튼을 클릭하면 해당 컨텍스트의 쿠키가 바뀌어 이후 작업에 영향을 줍니다. 워커마다 컨텍스트를 하나씩 쓰면 문제가 없지만, 컨텍스트를 공유하면 순서에 따라 캡처가 달라지는 또 다른 원인이 됩니다.

Playwright 스크린샷 스크립트의 대안

  • Puppeteer는 Chrome과 Firefox용으로 비슷한 API를 제공합니다. Puppeteer로 웹사이트 스크린샷을 자동화하는 방법을 참고합니다.
  • Playwright Test는 스크린샷을 기준 이미지와 비교합니다. Playwright 스크린샷 테스트 가이드를 참고합니다.
  • 호스팅 스크린샷 API는 브라우저를 대신 실행하고 HTTP로 이미지를 반환합니다.
  • Temposhot Website Capture는 Mac에서 URL 목록을 코드 없이 로컬로 실행합니다. Desktop 1920×1080, Tablet 768×1024 또는 Mobile 390×844 중에서 고르고, Viewport 또는 Full page를 선택하며, 브라우저를 최대 10개까지 동시에 실행합니다. 행마다 Retry를 사용할 수 있습니다.

스크립트 옵션과 노코드 대응 설정

이 글의 대부분의 선택에는 Website Capture의 직접적인 설정이 있습니다. 차이는 누가 선택하느냐입니다. 개발자는 코드로 선택하고, 목록을 붙여 넣을 수 있는 사람은 설정으로 선택합니다. Website Capture에는 스케줄러와 로그인 지원이 없으므로, CI 실행과 로그인 뒤의 페이지는 스크립트에 남습니다.

두 열 비교표: Playwright 스크립트와 Website Capture를 열로 두고, 뷰포트, 전체 페이지, 대기 조건, 고정 지연, 이미지 형식과 품질, 워커 수를 행으로 나눔.

FAQ

Playwright에 보이는 브라우저 창이 필요합니까?

아니요. 브라우저는 기본적으로 헤드리스로 실행됩니다. 디버깅 중 페이지를 보고 싶다면 chromium.launch에 headless: false를 전달합니다.

Playwright는 PNG 대신 JPEG로 저장할 수 있습니까?

예. 스크린샷 옵션에 type: 'jpeg'와 0-100 사이의 quality 값을 설정하거나, .jpg 파일 이름을 사용합니다.

전체 페이지 스크린샷이 잘리는 이유는 무엇입니까?

일부 페이지는 문서가 아니라 내부 요소 안에서 스크롤합니다. 그 요소를 로케이터 스크린샷으로 캡처하거나, 캡처 전에 CSS 높이를 바꿉니다.

Playwright로 로그인 뒤의 페이지를 캡처할 수 있습니까?

예. 한 번 로그인한 뒤 context.storageState({ path: 'auth.json' })으로 세션을 저장하고, 이후 컨텍스트를 storageState: 'auth.json'으로 만듭니다. 이 파일에는 세션 쿠키가 들어 있으므로 버전 관리에서 제외합니다.

광고와 타임스탬프가 캡처마다 바뀌지 않게 하려면 어떻게 합니까?

mask 옵션에 해당 로케이터를 전달합니다. Playwright는 각 요소 위에 단색 상자를 덮어 그리므로, 실행 결과를 잘못된 차이 없이 비교할 수 있습니다.

CI 스크린샷이 노트북과 다르게 보이는 이유는 무엇입니까?

폰트, 픽셀 비율, 로케일이 보통 다릅니다. 러너에 같은 폰트를 설치하고, scale: 'css'를 설정하고, 컨텍스트의 locale과 timezoneId를 고정해 날짜와 숫자 형식을 맞춥니다.

참고 자료

노코드 웹사이트 스크린샷 자동화

Temposhot Website Capture는 붙여 넣은 URL 목록을 받아, 관리할 스크립트 없이 Mac에서 모든 페이지를 캡처합니다. 웹사이트 스크린샷 자동화 페이지를 보거나 Website Capture 빠른 시작부터 시작할 수 있습니다.

playwrightwebsite-captureautomationjavascript

여기서 사용한 용어: full page screenshot, playwright, puppeteer, screenshot api, screenshot automation, viewport screenshot

반복되는 스크린샷을 완성된 결과물로 만듭니다

Temposhot은 타이머 또는 클릭할 때마다 캡처하고, 결과를 PDF, 이미지, ZIP 또는 MP4로 내보냅니다.

관련 글