Chrome의 헤드리스 모드가 업그레이드됨: --headless=new

Chrome의 헤드리스 모드가 더욱 개선되었습니다.

Peter Kvitek
Peter Kvitek

Chrome의 헤드리스 모드가 더욱 개선되었습니다. 이 도움말에서는 Headless를 Chrome의 일반적인 'headful' 모드에 더 가깝게 제공하여 개발자에게 Headless를 더 유용하게 만들기 위한 최근 엔지니어링 노력을 간략하게 설명합니다.

배경

2017년에는 Chrome 59에 일명 헤드리스 모드가 도입되었습니다. 이 모드를 사용하면 UI가 표시되지 않은 상태에서 무인 환경에서 브라우저를 실행할 수 있습니다. 즉, Chrome 없이 Chrome을 실행하는 것입니다.

헤드리스 모드는 Puppeteer 또는 ChromeDriver와 같은 프로젝트를 통해 브라우저 자동화에 널리 사용되는 모드입니다. 다음은 헤드리스 모드를 사용하여 주어진 URL의 PDF 파일을 만드는 간단한 명령줄의 예입니다.

chrome --headless --print-to-pdf https://developer.chrome.com/

헤드리스의 새로운 기능

최근의 헤드리스 개선사항을 자세히 살펴보기 전에 '이전' 헤드리스의 작동 방식을 이해하는 것이 중요합니다. 앞서 보여드린 명령줄 스니펫은 --headless 명령줄 플래그를 사용하므로 헤드리스가 일반 Chrome 브라우저의 작업 모드일 뿐임을 알 수 있습니다. 놀랍게도 실제로는 그렇지 않았습니다. 기술적으로 이전 헤드리스는 별도의 대체 브라우저 구현으로서 동일한 Chrome 바이너리의 일부로 제공됩니다. //chrome의 Chrome 브라우저 코드를 공유하지 않습니다.

예상하셨겠지만, 별도의 헤드리스 브라우저를 구현하고 유지관리하는 데 많은 엔지니어링 오버헤드가 발생했지만, 이것이 유일한 문제는 아니었습니다. Headless는 별도로 구현되었기 때문에 헤드형 Chrome에는 없는 자체 버그와 기능이 있었습니다. 이로 인해 자동화된 브라우저 테스트가 헤드풀 모드에서는 통과되지만 헤드리스 모드에서는 실패하거나 그 반대의 상황이 발생할 수 있는 혼란스러운 상황이 발생했습니다. 이는 자동화 엔지니어에게 매우 중요한 고충입니다. 예를 들어 브라우저 확장 프로그램을 설치해야 하는 자동화된 테스트도 제외했습니다. 다른 브라우저 수준 기능도 마찬가지입니다. 헤드리스에 별도의 자체 구현이 없으면 지원되지 않았습니다.

2021년에 Chrome팀은 이 문제를 해결하고 헤드리스 모드와 헤드풀 모드를 한 번에 통합하는 작업에 착수했습니다.

새로운 Chrome 헤드리스는 더 이상 별도의 브라우저 구현이 아니며, 이제 대신 Chrome과 코드를 공유합니다.

이제 Chrome 112에서 새로운 헤드리스 모드를 사용할 수 있습니다. 이 모드에서는 Chrome이 플랫폼 창을 생성하지만 표시하지는 않습니다. 기존 기능과 향후의 다른 모든 기능을 제한 없이 사용할 수 있습니다.

새로운 Headless 사용해 보기

새로운 헤드리스 모드를 사용해 보려면 --headless=new 명령줄 플래그를 전달합니다.

chrome --headless=new

현재 이전 헤드리스 모드는 다음을 통해 계속 사용할 수 있습니다.

chrome --headless=old

현재는 명시적인 값 없이 --headless 명령줄 플래그를 전달하면 이전 헤드리스 모드가 계속 활성화되지만, 시간이 지남에 따라 이 기본값을 새로운 헤드리스로 변경할 계획입니다.

Google은 Chrome 바이너리에서 이전 헤드리스를 완전히 삭제하고 올해 말 Puppeteer에서 이 모드의 지원을 중단할 계획입니다. 이번 삭제의 일환으로 아직 업그레이드할 수 없는 사용자를 위해 기존 헤드리스를 별도의 독립형 바이너리로 제공할 예정입니다.

Puppeteer의 새로운 헤드리스 헤드리스

Puppeteer에서 새로운 헤드리스 모드를 선택하려면 다음 단계를 따르세요.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: 'new',
  // `headless: true` (default) enables old Headless;
  // `headless: 'new'` enables new Headless;
  // `headless: false` enables "headful" mode.
});

const page = await browser.newPage();
await page.goto('https://developer.chrome.com/');

// …

await browser.close();

Selenium-WebDriver의 새로운 헤드리스

Selenium-WebDriver에서 새로운 헤드리스 모드를 사용하려면 다음 단계를 따르세요.

const driver = await env
  .builder()
  .setChromeOptions(options.addArguments('--headless=new'))
  .build();

await driver.get('https://developer.chrome.com/');

// …

await driver.quit();

다른 언어 바인딩 사용 예시를 포함한 자세한 내용은 Selenium팀의 블로그 게시물을 참고하세요.

헤드리스별 명령줄 플래그

새로운 헤드리스 모드에서는 다음과 같은 명령줄 플래그를 사용할 수 있습니다.

--dump-dom

--dump-dom 플래그는 대상 페이지의 직렬화된 DOM을 stdout에 출력합니다. 예를 들면 다음과 같습니다.

chrome --headless=new --dump-dom https://developer.chrome.com/

이는 단순히 HTML 소스 코드를 출력 (curl로 실행 가능)하는 것과 다릅니다. --dump-dom의 출력을 가져오기 위해 Chrome은 먼저 HTML 코드를 DOM으로 파싱하고 DOM을 변경할 수 있는 <script>를 실행한 다음 DOM을 다시 HTML의 직렬화된 문자열로 변환합니다.

--screenshot

--screenshot 플래그는 타겟 페이지의 스크린샷을 찍어 현재 작업 디렉터리에 screenshot.png로 저장합니다. 특히 --window-size 플래그와 함께 사용하면 유용합니다. 예를 들면 다음과 같습니다.

chrome --headless=new --screenshot --window-size=412,892 https://developer.chrome.com/

--print-to-pdf

--print-to-pdf 플래그는 대상 페이지를 현재 작업 디렉터리에 output.pdf라는 PDF로 저장합니다. 예를 들면 다음과 같습니다.

chrome --headless=new --print-to-pdf https://developer.chrome.com/

원하는 경우 --no-pdf-header-footer 플래그를 추가하여 인쇄 헤더 (현재 날짜 및 시간 포함)와 바닥글 (URL 및 페이지 번호 포함)을 생략할 수 있습니다.

chrome --headless=new --print-to-pdf --no-pdf-header-footer https://developer.chrome.com/

--timeout

--timeout 플래그는 페이지가 아직 로드 중인 경우에도 --dump-dom, --screenshot, --print-to-pdf에서 페이지 콘텐츠를 캡처하기까지 걸리는 최대 대기 시간 (밀리초)을 정의합니다.

chrome --headless=new --print-to-pdf --timeout=5000 https://developer.chrome.com/

--timeout=5000 플래그는 Chrome에서 PDF를 인쇄하기 전에 최대 5초 동안 기다리도록 지시합니다. 따라서 이 프로세스를 실행하는 데 최대 5초가 걸립니다.

--virtual-time-budget

--virtual-time-budget를 사용하면 시간 이동이 가능합니다. 글쎄요, 어느 정도는요. 가상 시간은 시간에 종속되는 코드 (예: setTimeout/setInterval)에 대해 '빨리 감기' 역할을 합니다. 브라우저에서는 실제로 시간이 흘렀다고 생각하면서도 브라우저에서 페이지의 코드를 최대한 빠르게 실행하도록 합니다.

사용법을 설명하기 위해 setTimeout(fn, 1000)을 사용하여 매초 카운터를 증가시키고, 기록하고, 표시하는 데모 페이지를 살펴보세요. 관련 코드는 다음과 같습니다.

<output>0</output>
<script>
  const element = document.querySelector('output');
  let counter = 0;
  setInterval(() => {
    counter++;
    console.log(counter);
    element.textContent = counter;
  }, 1_000);
</script>

1초 후에는 페이지에 '1'이, 2초 후에는 '2'와 같은 식으로 표시됩니다. 다음은 42초 후에 페이지 상태를 캡처하여 PDF로 저장하는 방법입니다.

chrome --headless=new --print-to-pdf --virtual-time-budget=42000 https://mathiasbynens.be/demo/time

--allow-chrome-scheme-url

chrome:// URL에 액세스하려면 --allow-chrome-scheme-url 플래그가 필요합니다. 이 플래그는 Chrome 123부터 사용할 수 있습니다. 예를 들면 다음과 같습니다.

chrome --headless=new --print-to-pdf --allow-chrome-scheme-url chrome://gpu

디버깅

Chrome은 헤드리스 모드에서 사실상 보이지 않으므로 문제가 발생할 경우 무슨 일이 일어나는지 파악하기가 까다로울 수 있습니다. 다행히 헤드리스 Chrome을 헤드리스 Chrome과 매우 유사한 방식으로 디버그할 수 있습니다. 비결은 --remote-debugging-port 명령줄 플래그를 사용하여 헤드리스 모드에서 Chrome을 실행하는 것입니다.

chrome --headless=new --remote-debugging-port=0 https://developer.chrome.com/

이렇게 하면 고유한 WebSocket URL이 stdout에 출력됩니다. 예를 들면 다음과 같습니다.

DevTools listening on ws://127.0.0.1:60926/devtools/browser/b4bd6eaa-b7c8-4319-8212-225097472fd9

그런 다음 일반 헤드풀 Chrome 인스턴스에서 Chrome DevTools 원격 디버깅을 사용하여 헤드리스 타겟에 연결하고 검사할 수 있습니다. 이렇게 하려면 chrome://inspect로 이동하여 구성... 버튼을 클릭하고 WebSocket URL의 IP 주소와 포트 번호를 입력합니다. 위 예에서는 127.0.0.1:60926를 입력했습니다. 완료를 클릭하면 원격 대상이 나타나고 아래에 나열된 모든 탭과 기타 대상이 표시됩니다. inspect를 클릭하면 Chrome DevTools에 액세스하여 원격 헤드리스 타겟을 검사하며 inspect할 수 있습니다.

Chrome DevTools가 원격 헤드리스 대상 페이지를 검사할 수 있습니다.

의견

새로운 헤드리스 모드에 관한 의견을 기다리겠습니다. 문제가 발생하면 신고해 주세요.