Puppeteer 완벽 가이드 (v24.x 기준)
1. 소개 (Introduction)
Puppeteer는 Node.js 라이브러리로, DevTools 프로토콜을 통해 Chrome, Chromium 또는 Firefox 브라우저를 제어하는 고수준 API를 제공합니다. 주로 웹 사이트의 자동화된 테스트, 웹 크롤링(스크래핑), 스크린샷 및 PDF 생성 등의 작업에 사용됩니다.
주요 특징:
- 헤드리스(Headless) 및 논헤드리스(Non-headless) 모드 지원: UI 없이 백그라운드에서 실행하거나, 실제 브라우저 창을 띄워서 실행할 수 있습니다.
- 강력한 자동화 기능: 최신 자바스크립트가 적용된 SPA(Single-Page Application)를 포함하여 대부분의 웹사이트를 자동화하고 렌더링할 수 있습니다.
- Chrome 개발팀의 공식 지원: Google Chrome 팀이 직접 개발하여 안정성과 신뢰성이 높습니다.
- 네트워크 제어: 네트워크 요청을 가로채거나 응답을 수정하는 등 다양한 네트워크 관련 작업이 가능합니다.
- Firefox 지원: v23.0.0부터 WebDriver BiDi 프로토콜을 통해 Firefox도 안정적으로 지원합니다.
2. 설치 (Installation)
Node.js 환경에서 npm을 통해 간단하게 설치할 수 있습니다.
npm install puppeteer
이 명령어를 실행하면 Puppeteer 라이브러리와 함께 자동화에 사용될 Chrome for Testing 브라우저가 함께 다운로드됩니다.
3. puppeteer vs puppeteer-core
Puppeteer는 두 가지 패키지로 제공됩니다.
puppeteer
: 라이브러리 기능과 자동화를 위한 전용 브라우저(Chrome for Testing)가 함께 설치됩니다. 일반적으로 이 패키지를 사용하는 것이 편리합니다.puppeteer-core
: 전용 브라우저가 빠진, 순수한 제어 기능만 포함된 가벼운 버전입니다. 이미 시스템에 설치된 특정 버전의 Chrome을 사용하거나, 브라우저 다운로드 과정을 직접 관리하고 싶을 때 유용합니다.puppeteer-core
를 사용하는 경우,launch
옵션에서executablePath
나channel
을 반드시 지정해야 합니다.
4. 기본 사용법 (Basic Usage)
가장 기본적인 사용법은 브라우저를 실행하고, 새 페이지(탭)를 연 뒤, 원하는 주소로 이동하는 것입니다.
// puppeteer 또는 puppeteer-core 모듈을 가져옵니다.
const puppeteer = require('puppeteer');
// const puppeteer = require('puppeteer-core');
(async () => {
// 브라우저를 실행합니다.
const browser = await puppeteer.launch({
headless: false, // false로 설정하면 브라우저가 화면에 나타납니다.
// executablePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', // puppeteer-core 사용 시 필요
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage', // 공유 메모리 문제 방지
'--disable-gpu', // GUI가 없는 환경에서 GPU 비활성화
]
});
// 새로운 페이지(탭)을 엽니다.
const page = await browser.newPage();
// 특정 URL로 이동합니다.
await page.goto('https://www.google.com');
// 스크린샷을 찍습니다.
await page.screenshot({ path: 'example.png' });
// 브라우저를 닫습니다.
await browser.close();
})();
이제 page
객체의 다양한 기능을 활용하여 웹 페이지와 상호작용할 수 있습니다.
5. Page API 주요 기능
page
객체는 웹 페이지를 제어하는 데 필요한 대부분의 기능을 제공합니다.
5.1. 페이지 이동 및 대기 (Navigation & Waiting)
.goto(URL, options)
: 지정된 웹 주소로 페이지를 이동시킵니다.await page.goto('https://example.com', { waitUntil: 'networkidle0' // 네트워크 활동이 없을 때까지 대기 });
.waitForSelector(selector, options)
: 특정 CSS 선택자에 해당하는 요소가 나타날 때까지 기다립니다. 동적으로 생성되는 콘텐츠를 다룰 때 필수적입니다.await page.waitForSelector('#dynamic-content');
.waitForFunction(function, options, ...args)
: 브라우저 내에서 특정 JavaScript 조건이 참(True)이 될 때까지 기다립니다. AJAX 등으로 내용이 바뀌는 것을 기다릴 때 매우 유용합니다.// 특정 요소의 텍스트가 'Finished'로 바뀔 때까지 대기 await page.waitForFunction( 'document.querySelector("#status").innerText === "Finished"' );
.waitForNavigation(options)
: 사용자의 클릭 등으로 인해 페이지 URL이 바뀌거나 새로고침되는 것이 완료될 때까지 기다립니다.// 버튼 클릭과 페이지 이동을 동시에 처리 await Promise.all([ page.waitForNavigation(), page.click('#submit-button'), ]);
.waitForNetworkIdle(options)
: 네트워크 요청이 잠잠해질 때까지 기다립니다. 모든 리소스가 로드된 후 작업을 수행하고 싶을 때 유용합니다.
5.2. 요소 정보 획득 및 조작 (Element Handling)
.evaluate(pageFunction, ...args)
: 브라우저의 콘솔에서 직접 JavaScript 코드를 실행한 후, 그 결과를 Node.js 환경으로 가져옵니다. 직렬화 가능한 값만 반환할 수 있습니다.const pageTitle = await page.evaluate(() => document.title);
.$eval(selector, pageFunction, ...args)
: 특정 요소 하나를 찾아, 그 요소에 대한 정보를 가져옵니다.const buttonText = await page.$eval('#my-button', el => el.textContent);
.$$eval(selector, pageFunction, ...args)
: 특정 조건을 만족하는 모든 요소들을 찾아 배열로 처리한 후, 결과를 가져옵니다.const allButtonTexts = await page.$$eval('.btn', buttons => buttons.map(btn => btn.textContent) );
.$(selector)
/.$$(selector)
: 선택자에 해당하는ElementHandle
(요소에 대한 참조)을 하나 또는 배열로 가져옵니다. 이후 다른 메서드와 연계하여 사용할 수 있습니다.const button = await page.$('#submit-button'); await button.click();
- Locator API (v20.6.0+): Playwright 스타일의 새로운 API로, 요소가 나타날 때까지 자동으로 기다리는 기능을 내장하고 있어 코드가 간결해집니다.
// 자동으로 #submit-button이 나타날 때까지 기다린 후 클릭 await page.locator('#submit-button').click();
5.3. 사용자 행동 시뮬레이션 (User Actions)
.click(selector, options)
: 특정 요소를 클릭합니다.await page.click('#login-button');
.type(selector, text, options)
: 특정 입력 필드에 키보드로 글자를 타이핑하듯 입력합니다.await page.type('#username', 'my_user_id', { delay: 100 }); // 각 키 입력 사이에 100ms 지연
.hover(selector)
: 특정 요소에 마우스 커서를 올립니다..select(selector, ...values)
: 드롭다운 메뉴(<select>
)에서 특정 옵션을 선택합니다..uploadFile(selector, ...filePaths)
: 파일 업로드(<input type="file">
) 기능을 구현합니다.
5.4. 기타 유용한 기능
.setViewport({ width, height })
: 브라우저 창(뷰포트)의 크기를 지정합니다. 반응형 웹 테스트에 유용합니다..setUserAgent(userAgent)
: User-Agent 문자열을 변경하여 다른 브라우저나 기기인 것처럼 위장할 수 있습니다..screenshot({ path, fullPage })
: 현재 보이는 화면이나 전체 페이지를 스크린샷으로 저장합니다..pdf({ path, format })
: 페이지를 PDF 파일로 저장합니다..on('dialog', handler)
:alert
,confirm
,prompt
같은 대화상자 이벤트가 발생했을 때 실행할 동작을 등록합니다.
6. 고급 활용 및 팁 (Advanced Usage & Tips)
- 봇 탐지 우회: 봇 탐지를 피하기 위해
puppeteer-extra
와puppeteer-extra-plugin-stealth
라이브러리를 함께 사용하는 것이 효과적입니다. 이는navigator.webdriver
플래그를 숨기는 등 다양한 기법을 적용하여 자동화된 브라우저의 특징을 숨겨줍니다. - 네트워크 요청 차단: 광고나 이미지, CSS 파일 등 불필요한 리소스 로딩을 차단하여 크롤링 속도를 향상시킬 수 있습니다.
await page.setRequestInterception(true); page.on('request', (request) => { if (['image', 'stylesheet', 'font'].includes(request.resourceType())) { request.abort(); } else { request.continue(); } });
- 성능 최적화: 대규모 스크래핑 시에는 하나의 브라우저 인스턴스에서 여러 페이지를 열어 병렬로 처리하고, 작업이 끝난 페이지는 바로 닫아 메모리 사용량을 관리하는 것이 중요합니다.
- 에러 핸들링:
try...catch
구문을 사용하여 타임아웃이나 요소 찾기 실패와 같은 예외 상황을 적절하게 처리해야 안정적인 스크립트를 만들 수 있습니다.