Puppeteer
와 Playwright
는 모두 헤드리스 브라우저 자동화 도구입니다. 두 도구 모두 브라우저 자동화, 웹 스크래핑, UI 테스트 등에 널리 사용되지만, 목적과 철학, 기능에서 차이가 있습니다. n8n에서는 보통 Puppeteer
를 사용하지만, 두 도구의 차이를 알면 장단점을 더 잘 활용할 수 있습니다.
Puppeteer와 Playwright의 차이점 정리
항목 | Puppeteer | Playwright |
개발사 | Microsoft | |
지원 브라우저 | Chromium (Chrome, Edge), Firefox (일부 지원) | Chromium, Firefox, WebKit(=Safari 엔진까지 완전 지원) |
멀티 브라우저 지원 | 제한적 | 완전한 지원 |
자동화 안정성 | 상대적으로 낮음 | 더 안정적 (항상 waitFor 없이도 자동화 처리가 더 견고함) |
동시 작업 | 한정적 | 더 강력한 컨텍스트/세션 격리 기능 제공 |
다운로드/업로드 제어 | 제한적 | 더 세부적인 제어 가능 |
기능 | 기본적인 UI 조작 중심 | 네트워크 가로채기, 권한 설정, 사용자 에이전트 등 다양한 기능 포함 |
API 설계 | 간단하고 직관적 | 다소 복잡하지만 강력 |
n8n 연동성 | 기본적으로 puppeteer 노드에서 사용 가능 |
Playwright는 n8n에 기본 포함되지 않음(직접 설치 및 JS 코드 노드로 활용 가능) |
n8n에서 Puppeteer 사용 예시
n8n의 Execute Puppeteer Script
노드를 사용하면 다음과 같은 작업이 가능합니다.
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
await browser.close();
return [{ json: { title } }];
📌 n8n
의 기본 이미지에는 puppeteer
가 이미 포함되어 있어 별도 설치가 필요 없습니다.
보안 및 운영 가이드
- 브라우저 인젝션 방지
– 자동화된 페이지에서 외부 JS 코드가 삽입되지 않도록 CSP 설정 확인 - 자동화된 로그인 사용시 민감정보 암호화 저장
– 계정/비밀번호가 노출되지 않도록 암호화 또는 Vault에 저장 - 브라우저 캐시 비활성화
–page.setCacheEnabled(false)
적용 - 스크립트 검증 및 로깅
–page.on('console')
,page.on('error')
등의 이벤트를 활용해 로그 추적
언제 Puppeteer 대신 Playwright를 고려해야 할까?
- WebKit(Safari)까지 테스트가 필요할 때
- 다양한 브라우저 환경에서의 교차 테스트가 필요할 때
- 더 정교한 시나리오 (파일 업/다운로드, 네트워크 캡처 등)를 구성할 때
- 자동화의 안정성이 중요한 기업환경 테스트 또는 인증 흐름 자동화 시
n8n에서 Playwright 사용법 (고급 사용자용)
Playwright는 기본적으로 포함되어 있지 않지만, 다음 방식으로 사용할 수 있습니다.
- 커스텀 Docker 이미지로
playwright
설치 - n8n의
Execute Command
또는Execute JavaScript
노드를 활용해 호출 - 예
npm install playwright
const playwright = require('playwright'); const browser = await playwright.chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://example.com'); const title = await page.title(); await browser.close(); return [{ json: { title } }];
상황 | 추천 도구 |
---|---|
단순 웹 자동화, n8n 기본 사용 | ✅ Puppeteer |
복잡한 크로스 브라우저 테스트, 네트워크 가로채기, 안정성이 중요한 환경 | ✅ Playwright |
Playwright에서 headless 모드가 꺼져 있어서 실제 브라우저 창이 뜨는 경우가 발생될 수 있습니다. 원래는 headless 모드로 실행하면 브라우저 창 없이 내부적으로 실행되고 결과만 가져올 수 있습니다.
브라우저가 보이지 않게 실행하는 방법 (Headless 모드)
Playwright는 기본적으로 headless 모드로 작동하지만, 명시적으로 설정하지 않거나 개발 도구에서 설정이 꺼져 있으면 브라우저 창이 뜹니다. Playwright 실행 시 아래와 같이 headless: true
를 명시해야 합니다.
const browser = await playwright.chromium.launch({
headless: true, // 브라우저 창 없이 실행
});
Claude Desktop이나 MCP에서 Playwright를 호출하는 코드가 있다면, 해당 부분을 확인해 다음과 같이 수정하세요.
예시 (검색 결과 가져오기)
const playwright = require('playwright');
(async () => {
const browser = await playwright.chromium.launch({ headless: true }); // ✔️ headless 설정
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
await browser.close();
console.log('페이지 제목:', title);
})();
Claude + MCP 환경에서 주의할 점
- Claude 데스크톱에서 자동화 코드 또는 MCP 프롬프트가 내부적으로 Playwright 스크립트를 실행할 때,
headless: false
가 기본 설정이 되어 있는 경우가 있습니다. - 또는 GUI 디버깅을 위해 개발 환경에서는 브라우저 창을 일부러 띄우도록 설정했을 수 있습니다.
- Docker 컨테이너나 리눅스 서버 환경에서는 headless 모드가 기본이며,
DISPLAY
환경변수 없이도 실행됩니다.
추가 팁
- headless 모드 강제 설정
MCP나 Claude 프롬프트에 다음과 같이 명시:Launch browser with headless mode set to true.
- headless 모드 확인용 디버그 출력
console.log('Headless 모드:', browser._options.headless);
- 실행환경 확인
MCP가 내부적으로 Node.js 또는 Python에서 Playwright를 호출하는 구조라면, 해당 설정을 코드 또는 config에서 직접 바꾸어야 할 수 있습니다.
보안 측면에서 권장
- headless 모드를 사용하면 서버 리소스를 덜 사용하고, 외부 사용자에게 브라우저 실행이 노출되지 않아 보안적으로도 더 안전합니다.
- 다만 로그인, 2FA 등 시나리오에서는 일부 웹사이트가
headless
환경을 탐지하고 차단할 수 있으므로, 이 경우는headless: false
로 하고 사용자 에이전트, viewport 등도 함께 위장해야 합니다.
Playwright MCP 도구 목록
도구 이름 | 기능 | 설명 |
browser_snapshot | 페이지 스냅샷 | 현재 페이지의 접근성 스냅샷을 캡처합니다. (스크린샷보다 더 나은 방법일 수 있음) |
browser_click | 클릭 | 웹 페이지에서 클릭을 수행합니다. |
browser_drag | 마우스 드래그 | 두 요소 간 드래그 앤드 드롭을 수행합니다. |
browser_hover | 마우스 오버 | 페이지 요소 위에 마우스를 올립니다. |
browser_type | 텍스트 입력 | 편집 가능한 요소에 텍스트를 입력합니다. |
browser_select_option | 옵션 선택 | 드롭다운에서 옵션을 선택합니다. |
browser_take_screenshot | 스크린샷 찍기 | 현재 페이지의 스크린샷을 찍습니다. 조작은 불가능하며, 조작하려면 snapshot 사용 필요 |
browser_screen_capture | 스크린샷 찍기 | 현재 페이지를 시각적으로 캡처합니다. |
browser_screen_move_mouse | 마우스 이동 | 지정한 위치로 마우스를 이동합니다. |
browser_screen_click | 클릭 | 마우스 왼쪽 버튼 클릭을 수행합니다. |
browser_screen_drag | 마우스 드래그 | 마우스 왼쪽 버튼으로 드래그를 수행합니다. |
browser_screen_type | 텍스트 입력 | 텍스트를 입력합니다. |
browser_tab_list | 탭 목록 보기 | 열린 브라우저 탭을 나열합니다. |
browser_tab_new | 새 탭 열기 | 새 브라우저 탭을 엽니다. |
browser_tab_select | 탭 선택 | 인덱스로 탭을 선택합니다. |
browser_tab_close | 탭 닫기 | 현재 또는 지정된 인덱스의 탭을 닫습니다. |
browser_navigate | URL로 이동 | 지정된 URL로 이동합니다. |
browser_navigate_back | 뒤로 가기 | 이전 페이지로 이동합니다. |
browser_navigate_forward | 앞으로 가기 | 다음 페이지로 이동합니다. |
browser_press_key | 키 입력 | 키보드 키를 누릅니다. |
browser_console_messages | 콘솔 메시지 보기 | 콘솔 로그 메시지를 반환합니다. |
browser_file_upload | 파일 업로드 | 하나 이상의 파일을 업로드합니다. |
browser_pdf_save | PDF 저장 | 페이지를 PDF로 저장합니다. |
browser_close | 브라우저 닫기 | 현재 페이지를 닫습니다. |
browser_wait | 대기 | 지정한 시간(초) 동안 대기합니다. |
browser_resize | 브라우저 크기 조정 | 브라우저 창 크기를 조절합니다. |
browser_install | 브라우저 설치 | 명시된 브라우저를 설치합니다. (‘브라우저가 없다’는 오류가 발생할 때 호출) |
browser_handle_dialog | 다이얼로그 처리 | 브라우저 다이얼로그를 처리합니다. |
browser_network_requests | 네트워크 요청 목록 | 페이지 로딩 후 발생한 모든 네트워크 요청을 반환합니다. |
browser_generate_playwright_test | Playwright 테스트 생성 | 주어진 시나리오의 Playwright 테스트를 생성합니다. |
이 도구들은 Playwright MCP와 Claude, 또는 다양한 자동화 플랫폼에서 사용할 수 있으며, 고급 브라우저 자동화를 구현할 수 있도록 설계되었습니다.
"playwright": {
"command": "npx",
"args": [
"-y",
"@playwright/mcp@latest"
]
}
이 설정은 공식 Playwright MCP 모듈을 설치하고 실행하는 구조이며, 기본적으로 @playwright/mcp
는 headless 모드가 꺼진 상태(headless: false
)로 작동합니다.
@playwright/mcp
는 기본적으로 headless 모드를false
로 실행합니다.- 그래서 Claude Desktop에서 해당 MCP를 통해 명령을 내리면 실제 브라우저 창이 눈에 보이게 실행됩니다.
headless 모드 강제 설정
현재의 @playwright/mcp
는 커맨드라인 인자로 --headless
같은 옵션을 기본적으로 받지 않지만, MCP를 수정하거나 래퍼를 만들어 강제로 headless 모드를 적용하는 두 가지 방법이 있습니다.
방법 🅰️: 로컬 커스텀 MCP 서버 래핑 (추천)
@playwright/mcp
대신 커스텀 래퍼 스크립트를 작성하여 headless 모드가 항상 적용되도록 구성합니다.
예: my-playwright-mcp.js
파일 생성
const { createServer } = require('@playwright/mcp');
createServer({
launchOptions: {
headless: true, // 👈 브라우저가 보이지 않도록 설정
args: ['--no-sandbox'],
},
});
그리고 mcpServers
를 다음과 같이 수정
"playwright": {
"command": "node",
"args": [
"/Users/win10_original/Downloads/my-playwright-mcp.js"
]
}
방법 🅱️: system-level 가상 디스플레이 활용 (리눅스만 가능)
리눅스일 경우 xvfb
같은 가상 디스플레이 서버를 이용하여 눈에 보이지 않게 브라우저를 띄울 수 있습니다.
xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" npx -y @playwright/mcp
하지만 이건 macOS나 Windows에서는 사용할 수 없고, 리눅스 서버에서 headless 없이 GUI 환경을 우회하기 위해 사용하는 방식입니다.
Playwright MCP가 기본 headless 설정을 제공하지 않는 이유
@playwright/mcp
는 MCP 프로토콜의 일반적인 자동화 시나리오 테스트를 위해 시각적으로 디버깅 가능한 환경을 기본으로 제공하기 때문에 일부러 브라우저가 뜨게 설정되어 있습니다.
보안 및 자동화 환경에서는?
자동화·보안 테스트 목적으로 사용할 경우
- headless 모드를 반드시 설정해야 리소스 사용도 줄고, 실행이 감춰집니다.
- 로그인이나 CAPTCHA 우회 시에는 일부러 headful 모드로 실행해야 할 수도 있으나, 일반 검색이나 수집은
headless
가 더 적합합니다.
항목 | 설명 |
---|---|
현재 현상 | MCP Playwright가 브라우저 창을 띄우며 실행됨 |
원인 | @playwright/mcp 가 기본적으로 headless 모드를 꺼둔 상태로 동작 |
해결 방법 | 커스텀 MCP 서버 작성 → launchOptions: { headless: true } 명시 |
대안 | 리눅스 환경이라면 xvfb-run 을 사용해 가상 디스플레이 환경에서 실행 |
아래는 Claude Desktop
과 연동 가능한 커스텀 Playwright MCP 서버인 my-playwright-mcp.js
예제입니다. 이 스크립트는 브라우저를 눈에 띄우지 않고(headless) 내부적으로 검색·조작을 수행할 수 있도록 합니다.
my-playwright-mcp.js 예제 코드
// my-playwright-mcp.js
const { createServer } = require('@playwright/mcp');
createServer({
launchOptions: {
headless: true, // 👈 브라우저 창 없이 실행
args: ['--no-sandbox'], // (리눅스에서 root 사용자 실행 시 필수)
slowMo: 0 // 필요시 느리게 실행: 100~300ms
}
});
@playwright/mcp
는 MCP 표준을 따르는 Playwright 전용 서버입니다.launchOptions.headless: true
설정을 통해 브라우저 GUI가 절대 뜨지 않도록 보장합니다.
필요한 패키지 설치
해당 스크립트를 실행하기 위해 아래 명령어로 의존 패키지를 설치합니다.
npm install @playwright/mcp
npx playwright install
@playwright/mcp
: MCP 서버 실행용 라이브러리playwright install
: 필요한 브라우저 바이너리 설치 (Chromium, Firefox, WebKit 등)
파일 저장 위치 예시
예: macOS 또는 Windows에서
/Users/win10_original/Downloads/my-playwright-mcp.js
또는 프로젝트 루트 디렉토리에 두어도 무방합니다.
Claude Desktop 설정 예시
mcpServers
설정을 아래처럼 수정합니다.
{
"mcpServers": {
"playwright": {
"command": "node",
"args": [
"/Users/win10_original/Downloads/my-playwright-mcp.js"
]
}
}
}
"command"
는node
"args"
는my-playwright-mcp.js
파일의 전체 경로
Claude Desktop에서 사용하는 프롬프트 예시
Use the `playwright` MCP tool to go to https://example.com, search for "security automation", and return the page title. Make sure the browser runs in headless mode.
브라우저가 뜨지 않고 내부적으로 작동하면서 결과가 반환됩니다.
보안 우회 설정 예시 (User-Agent 등)
createServer({
launchOptions: {
headless: true,
args: ['--no-sandbox'],
},
contextOptions: {
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36',
viewport: { width: 1280, height: 800 },
}
});
이렇게 하면 Bot 탐지 우회, 디버깅 제한 우회에도 유리합니다.
항목 | 설명 |
---|---|
목적 | Claude에서 Playwright 자동화를 브라우저 없이(headless) 실행 |
주요 파일 | my-playwright-mcp.js |
핵심 옵션 | launchOptions.headless: true |
연결 방식 | Claude mcpServers 에 "command": "node" 로 등록 |
실행 방식 | Claude가 내부적으로 headless 브라우저로 실행 |
@playwright/mcp
는 MCP 서버 실행을 위한 CLI 기반 툴이지, 직접 createServer()
같은 함수를 JS 코드로 노출하지 않습니다. 앞서 드린 예시는 일반적인 MCP-compatible 모듈의 예시였고, @playwright/mcp
자체는 그렇게 동작하지 않습니다. 즉, createServer()
는 @playwright/mcp
가 아니라 다른 MCP 서버들(@modelcontextprotocol/server-*)에서 사용 가능한 API입니다.
MCP 호환 커스텀 서버 직접 제작 (고급)
직접 Playwright
와 MCP
통신을 이어주는 서버를 만드는 방법입니다. 그러나 이건 복잡하고, @modelcontextprotocol/server-playwright
같은 별도 모듈이 존재하지 않기 때문에 실질적으로 직접 TCP/JSON-RPC 서버 구현 → Playwright 조작을 해야 합니다.
@playwright/mcp
를 그대로 사용하되, headless 옵션 적용하는 사용자 정의 CLI 서버 만들기
mcp-playwright-wrapper.js (브라우저 직접 실행 MCP 래퍼)
const { chromium } = require('playwright');
const { startServer } = require('modelcontextprotocol'); // MCP용 JSON-RPC 통신 서버
startServer({
name: 'custom-playwright',
methods: {
async searchSite({ query }) {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://www.google.com');
await page.fill('input[name="q"]', query);
await page.keyboard.press('Enter');
await page.waitForTimeout(2000);
const title = await page.title();
await browser.close();
return { title };
}
}
});
👆 위 코드는 playwright
+ MCP 호환 서버
를 직접 엮는 방식입니다. 단점은 modelcontextprotocol
이라는 별도 통신 처리 라이브러리를 사용해야 하고, Claude에서 호출이 쉽지 않을 수 있습니다.
가장 현실적인 해결책 (추천)
➤ @playwright/mcp
는 내부적으로 headless 설정을 받을 수 있는 환경변수를 지원합니다.
✨ 환경변수로 headless 모드 강제 설정하기
Playwright MCP 서버를 실행할 때 다음과 같이 실행해보세요.
HEADLESS=true npx -y @playwright/mcp
혹은 Claude Desktop에서 mcpServers
설정을 아래처럼 수정합니다.
"playwright": {
"command": "bash",
"args": [
"-c",
"HEADLESS=true npx -y @playwright/mcp"
]
}
이 방식이 먹히는 이유는 MCP 서버 코드가 내부적으로 환경변수를 읽어서 Playwright를 설정할 수 있도록 구성된 경우가 많기 때문입니다.
접근법 | 설명 | 추천도 |
---|---|---|
createServer 방식 |
사용 불가 (@playwright/mcp 에서는 없음) |
❌ |
mcp-playwright-wrapper.js |
MCP + Playwright 서버 직접 구현 | ⚠️ 복잡 |
HEADLESS=true 환경변수 사용 |
기존 MCP CLI에 headless 적용 | ✅ 추천 |
--no-sandbox
는 Chromium 기반 브라우저(예: Chrome, Edge, Playwright의 chromium
)를 실행할 때 사용하는 보안 샌드박스 비활성화 옵션입니다. 이 옵션을 사용할 경우, 브라우저는 격리된 보호 모드(sandbox mode) 없이 실행되며, 이는 보안적으로는 위험하지만 실행에는 도움이 될 수 있는 설정입니다.
--no-sandbox
가 필요한 이유
1. 루트 권한 실행 환경에서 충돌 방지
- 대부분의 Linux 환경에서는 Playwright/Chromium이 sandbox 모드에서 실행될 수 없는 root 환경일 때 실행 오류를 발생시킵니다.
- 예시 오류:
[0517/122300.600071:ERROR:zygote_host_impl_linux.cc(90)] Running as root without --no-sandbox is not supported.
- 이를 피하기 위해
--no-sandbox
옵션을 사용합니다.
2. CI/CD 환경에서의 문제 해결
- GitHub Actions, GitLab CI, Jenkins 같은 환경에서는 사용자 권한 제한이 달라 샌드박스가 정상 동작하지 않을 수 있습니다.
- 그래서 보통 Playwright, Puppeteer 관련 예제나 공식 가이드에서도
--no-sandbox
를 같이 사용하는 경우가 많습니다.
3. 보안상 주의할 점
항목 | 설명 |
---|---|
🚫 보안 샌드박스 | 악성 코드나 브라우저 렌더링 오류로부터 시스템을 보호하는 OS 수준 격리 메커니즘입니다. |
❌ --no-sandbox |
이 기능을 끄는 것이며, 브라우저 내부 코드가 시스템에 더 많은 권한을 갖게 됩니다. |
🛡️ 의미 | 악성 사이트를 자동화하는 경우, 시스템 침투 위험이 상대적으로 높아집니다. 따라서 신뢰되지 않은 페이지에 대해선 사용 지양이 필요합니다. |
4. 권장 가이드
구분 | 설명 |
---|---|
기능 | Chromium 보안 샌드박스를 비활성화 |
사용 시점 | root 권한, Docker, CI/CD, MCP 서버 등 |
보안 영향 | 브라우저의 OS 격리 보호 기능 무효화 (보안 약화) |
Playwright에서 사용 예 | chromium.launch({ headless: true, args: ['--no-sandbox'] }) |
- 테스트 환경/개발 환경:
--no-sandbox
OK - 운영 환경/보안이 중요한 시스템: 사용 지양 또는 일반 사용자 계정으로 실행 + sandbox 유지
Windows에서는 --no-sandbox 옵션이 필수도 아니고, 보통은 필요하지도 않으며, 사용해도 무방합니다.
Windows에서의 --no-sandbox 사용 여부
1. 필요하지 않은 이유
- Windows는 Linux와 다르게 Chromium 기반 브라우저가 루트(root) 권한 문제로 실행이 막히는 환경이 아님.
- 따라서 Playwright나 Puppeteer로 자동화를 할 때도 sandbox 관련 오류가 거의 발생하지 않습니다.
2. 써도 문제는 없는가?
- 예,
--no-sandbox
를 Windows에서 명시적으로 넣더라도 에러가 발생하지 않습니다. - 단, Windows에서는 이 옵션이 사실상 아무 효과도 없습니다.
- 이유는: Chromium의 샌드박스 구현 방식이 Windows와 Linux에서 다르기 때문입니다.
3. 보안적으로 무해한가?
항목 | 내용 |
---|---|
기본 권한 체계 | Windows는 사용자 계정 권한 기반(UAC 등)으로 보호 |
샌드박스 우회 여부 | --no-sandbox 를 써도 Windows에서는 대부분 의미 없음 |
보안 위협 | 일반적인 자동화에서는 걱정할 수준이 아님, 단 악성 페이지를 자동화하거나 실행환경이 중요할 경우는 주의 |
4. OS별 비교
OS | --no-sandbox 필요 여부 |
보안 영향 |
---|---|---|
Linux (root) | ✅ 필요함 (안 쓰면 실행 안 됨) | 위험도 높음 (보호 우회됨) |
Linux (non-root) | ❌ 불필요 | 안전함 |
Windows | ❌ 불필요, 사용해도 무방 | 영향 없음 |
macOS | ❌ 거의 사용 안 함 | 영향 없음 (기본적으로 sandbox 잘 작동함) |
✔️ Windows에서는 --no-sandbox를 사용하지 않아도 됩니다.
❗ 사용해도 문제는 없지만, 굳이 필요하지 않으며 보안상 특별히 우려할 필요도 없습니다.
댓글