본문 바로가기
프로그램 (PHP,Python)

n8n에서 Puppeteer와 Playwright 헤드리스 브라우저 자동화 도구

by 날으는물고기 2025. 7. 1.

n8n에서 Puppeteer와 Playwright 헤드리스 브라우저 자동화 도구

728x90

PuppeteerPlaywright는 모두 헤드리스 브라우저 자동화 도구입니다. 두 도구 모두 브라우저 자동화, 웹 스크래핑, UI 테스트 등에 널리 사용되지만, 목적과 철학, 기능에서 차이가 있습니다. n8n에서는 보통 Puppeteer를 사용하지만, 두 도구의 차이를 알면 장단점을 더 잘 활용할 수 있습니다.

Puppeteer와 Playwright의 차이점 정리

항목 Puppeteer Playwright
개발사 Google 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가 이미 포함되어 있어 별도 설치가 필요 없습니다.

보안 및 운영 가이드

  1. 브라우저 인젝션 방지
    – 자동화된 페이지에서 외부 JS 코드가 삽입되지 않도록 CSP 설정 확인
  2. 자동화된 로그인 사용시 민감정보 암호화 저장
    – 계정/비밀번호가 노출되지 않도록 암호화 또는 Vault에 저장
  3. 브라우저 캐시 비활성화
    page.setCacheEnabled(false) 적용
  4. 스크립트 검증 및 로깅
    page.on('console'), page.on('error') 등의 이벤트를 활용해 로그 추적

언제 Puppeteer 대신 Playwright를 고려해야 할까?

  • WebKit(Safari)까지 테스트가 필요할 때
  • 다양한 브라우저 환경에서의 교차 테스트가 필요할 때
  • 더 정교한 시나리오 (파일 업/다운로드, 네트워크 캡처 등)를 구성할 때
  • 자동화의 안정성이 중요한 기업환경 테스트 또는 인증 흐름 자동화 시

n8n에서 Playwright 사용법 (고급 사용자용)

Playwright는 기본적으로 포함되어 있지 않지만, 다음 방식으로 사용할 수 있습니다.

  1. 커스텀 Docker 이미지로 playwright 설치
  2. n8n의 Execute Command 또는 Execute JavaScript 노드를 활용해 호출
  3. 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 환경변수 없이도 실행됩니다.

추가 팁

  1. headless 모드 강제 설정
    MCP나 Claude 프롬프트에 다음과 같이 명시: Launch browser with headless mode set to true.
  2. headless 모드 확인용 디버그 출력
    console.log('Headless 모드:', browser._options.headless);
  3. 실행환경 확인
    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/mcpheadless 모드가 꺼진 상태(headless: false)로 작동합니다.

  • @playwright/mcp는 기본적으로 headless 모드를 false로 실행합니다.
  • 그래서 Claude Desktop에서 해당 MCP를 통해 명령을 내리면 실제 브라우저 창이 눈에 보이게 실행됩니다.

headless 모드 강제 설정

현재의 @playwright/mcp는 커맨드라인 인자로 --headless 같은 옵션을 기본적으로 받지 않지만, MCP를 수정하거나 래퍼를 만들어 강제로 headless 모드를 적용하는 두 가지 방법이 있습니다.

방법 🅰️: 로컬 커스텀 MCP 서버 래핑 (추천)

@playwright/mcp 대신 커스텀 래퍼 스크립트를 작성하여 headless 모드가 항상 적용되도록 구성합니다.

300x250

예: 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 호환 커스텀 서버 직접 제작 (고급)

직접 PlaywrightMCP 통신을 이어주는 서버를 만드는 방법입니다. 그러나 이건 복잡하고, @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-sandboxWindows에서 명시적으로 넣더라도 에러가 발생하지 않습니다.
  • 단, 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를 사용하지 않아도 됩니다.
❗ 사용해도 문제는 없지만, 굳이 필요하지 않으며 보안상 특별히 우려할 필요도 없습니다.

728x90
그리드형(광고전용)

댓글