Playwright는 Microsoft의 브라우저 자동화 프레임워크입니다. Apache-2.0 라이선스를 따르는 TypeScript 중심 라이브러리로, 실제 브라우저를 띄운 뒤 하나의 API로 제어하고, JavaScript 실행이 끝난 페이지를 돌려줍니다. 공식적으로는 엔드투엔드 테스트 도구로 소개되지만, HTTP 요청만으로는 데이터가 있어야 할 자리가 빈 껍데기처럼 돌아올 때 많은 사람들이 조용히 선택하는 엔진이기도 합니다. 형태상으로는 Puppeteer와 Selenium의 경쟁자라고 볼 수 있는데, HTTP 응답을 파싱하는 대신 실제 브라우저를 스크립팅하는 방식입니다.
나는 microsoft/playwright 1.56.0을 정해둔 스크래핑 테스트 세트에 돌려봤습니다. 페이지네이션이 있는 정적 카탈로그, 기사 1개, JavaScript로 렌더링되는 카탈로그, JSON API, 깨진 500 응답, 작은 크롤 그래프, 그리고 공개 실습 사이트 2개를 대상으로 했고, 환경은 Node v22.22.3, macOS arm64, Chromium만 사용했습니다. 렌더링 쪽은 깔끔하게 잘 동작했습니다. 하지만 크롤링 쪽은 아예 포함되어 있지 않았고, 바로 그 점이 이 도구를 도입하기 전에 가장 먼저 이해해야 할 부분입니다.
가장 눈에 띈 점
결과 중 두 가지가 특히 인상적이었고, 각각 조금 다른 방향을 보여줬습니다.
첫 번째는 예상 가능한 브라우저 결과였습니다. 다만 내가 사용한 대기 조건 안에서만요. page.goto(..., { waitUntil: 'domcontentloaded' }) 이후 동적 fixture 테스트는 #dynamic-products article.product-card가 나타날 때까지 기다렸고, 공개 Quotes to Scrape 테스트는 .quote가 나올 때까지 기다렸습니다. 애플리케이션 전용 셀렉터가 뜬 뒤에는 실행이 이어졌고, 결과는 fixture 8/8개 아이템과 공개 사이트 인용구 10개를 반환했습니다. fixture 결과는 8개 정답과 비교했을 때 recall 1.0이었습니다. 별도의 폴링 루프는 필요하지 않았지만, Playwright가 준비 상태 문제를 없앤 것은 아니었습니다. 완료 조건은 테스트 코드가 제공한 셈입니다. 전체 페이지 스크린샷도 첫 호출에서 바로 저장됐습니다.
두 번째 결과는 browserContext.request를 사용한 것이었습니다. 정확히는 Chromium이 이미 실행되어 있고 browser context가 만들어진 뒤 ctx.request.get(...)를 호출한 방식입니다. 이 경우 fixture의 JSON 엔드포인트를 직접 호출해 페이지를 만들거나 렌더링하지 않고도 8/8개 제품을 받아왔습니다. 이 벤치마크 환경에서는 DOM 작업은 건너뛰었지만, 브라우저 프로세스 비용 자체는 그대로였습니다. context에 붙어 있는 request 클라이언트는 브라우저 페이지와 쿠키 상태를 공유할 수 있지만, 독립적인 playwright.request.newContext()는 브라우저 context를 요구하지 않는 대신 세션을 자동 공유하지는 않습니다. 이번 테스트는 앞의 경로만 확인했습니다.
또한 Playwright에는 크롤 큐, 데이터셋 작성기, 자동 스로틀링이 없습니다. 내가 작성한 crawl-graph 테스트는 내부 링크를 따라가며 depth를 추적하고 재방문을 피하는 방식이었는데, 12개 페이지에 도달했고 depth 분포는 {0:1, 1:4, 2:7}였습니다. 하지만 이 breadth-first traversal 로직은 전부 내가 직접 쓴 테스트 코드였습니다. Playwright는 페이지를 열고 살펴보는 역할까지만 해주며, frontier 저장, URL 정책, 재시도, 스케줄링은 다른 계층이 담당해야 합니다.
Playwright가 실제로 하는 일
GitHub의 microsoft/playwright는 TypeScript로 작성되었고 Apache-2.0 라이선스를 사용하며, Microsoft가 유지보수합니다. 이번에 테스트한 빌드는 2026년 7월 9일 기준 1.56.0입니다. 아래 결과는 이 빌드에 대한 것이며, 이후 버전까지 포괄하는 호환성 선언으로 보시면 안 됩니다.
공식 포지셔닝은 분명합니다. Chromium, Firefox, WebKit을 하나의 API로 제어하는 웹 테스트 및 자동화 프레임워크라는 점입니다. Playwright의 중심 경로는 fixture, assertion, trace viewer를 갖춘 테스트 러너입니다. 이를 스크래핑 도구처럼 사용하려면 문서에 있는 Library mode를 따라 chromium.launch(), 그다음 context, 그다음 page를 테스트 러너 바깥에서 직접 다뤄야 합니다. 이번 리뷰는 모두 이 공개 API 범위 안에서 진행했습니다. 버전 간 호환성 테스트는 하지 않았으므로, 여기서 검증한 동작이 릴리스마다 항상 같다고 주장하는 것은 아닙니다.
다른 어떤 글에서도 가장 크게 내세우는 부분이 바로 이 폭넓은 지원이므로, 분명하게 정리하겠습니다. Playwright는 하나의 API로 Chromium, Firefox, WebKit 세 브라우저 엔진을 제어하고, JavaScript 위에 Python, Java, .NET 클라이언트를 1급으로 제공합니다. 이는 문서화된 사실이고, 형태상 Playwright의 가장 큰 차별점이기도 합니다. 다만 이번 테스트에서 실제로 사용한 범위는 더 좁습니다.
| 기능 | 이번 리뷰에서의 상태 |
|---|---|
| Chromium 엔진 | 사용함 — 여기의 모든 테스트가 Chromium에서 실행됨 |
| Firefox 엔진 | 문서상 지원, 여기서는 검증하지 않음 |
| WebKit 엔진 | 문서상 지원, 여기서는 검증하지 않음 |
| 세 엔진 공통 API | 문서상 지원, 여기서는 검증하지 않음 |
| Python, Java, .NET 클라이언트 | 문서상 지원, 여기서는 검증하지 않음 |
| 프록시 | 테스트하지 않음 |
| 여러 context의 병렬 확장성 | 테스트하지 않음 |
| API 우선 스크래핑용 네트워크 가로채기 | 테스트하지 않음 |
대상이 Safari의 WebKit에서 다르게 렌더링되거나, 팀이 Python을 사용한다면 Playwright의 강점은 바로 그 폭넓은 지원에 있습니다. 다만 제 결과를 Firefox나 WebKit의 동일성 증거로 받아들이면 안 됩니다. 실제로 테스트하지 않았기 때문입니다.
내부 동작 방식
정신 모델은 스크립트로 조작하는 브라우저 엔진입니다. chromium.launch()가 브라우저 프로세스를 띄웁니다. context는 쿠키, 저장소, 캐시가 분리된 독립 세션이고, page는 그 안의 탭입니다. page.goto(url)로 이동한 뒤 애플리케이션 준비 상태를 나타내는 조건을 기다리고, page.$$eval 같은 도우미로 DOM 결과를 읽습니다. 이는 HTTP 응답을 파싱하는 것보다 사용자용 브라우저에 훨씬 가깝지만, 환경이 완전히 같다는 뜻은 아닙니다. 헤드리스 신호, 뷰포트, 로케일, 폰트, 프로필 상태, TLS/네트워크 경로, 사이트 방어 기제가 실제로 제공되는 내용을 바꿀 수 있습니다. 이번 리뷰는 안티봇 동작이나 실제 브라우저와의 완전한 동일성은 테스트하지 않았습니다.
page.screenshot()은 렌더링된 페이지를 전체 페이지 또는 일부만 캡처할 수 있고, 이번 실행에서는 첫 호출부터 정상 작동했습니다. 앞서 말한 request API, 즉 context.request.get은 같은 context의 쿠키를 사용하면서 렌더링은 생략하므로, 하나의 스크립트 안에서 "페이지를 열고 DOM을 읽기"와 "JSON 엔드포인트만 호출하기"를 도구를 바꾸지 않고 섞을 수 있습니다.
하지만 내부에 없는 것이 바로 크롤링 기계입니다. 요청 스케줄러, 방문 기록 저장, 정중한 요청 정책, 내보내기 파이프라인이 없습니다. 제한된 범위의 순회는 쉽게 짤 수 있지만, 신뢰할 수 있는 frontier 작업에는 URL 정규화, 리다이렉트 처리, 재시도, 범위 규칙, 스로틀링, 복구 로직까지 필요합니다. 그 계층은 직접 만들거나, 브라우저 엔진을 감싼 프레임워크를 써야 합니다.
설치와 사용 준비 현실
설치는 두 단계이고, 실제 배포 부담은 두 번째 단계가 대부분을 차지합니다. npm install playwright는 라이브러리를 설치하고, 별도의 npx playwright install이 브라우저 빌드(제 경우 Chromium)를 내려받습니다. npm 패키지만 보고 곧바로 실행 가능한 전체 시스템으로 생각하면 안 됩니다. 디스크 공간, 다운로드 시간, CI에서의 브라우저 캐시, 프로세스 정리까지 함께 고려해야 합니다.
Playwright를 스크래퍼로 기대하고 테스트 튜토리얼을 따라가면 테스트 파일과 expect() assertion부터 시작하게 됩니다. 반면 스크래핑 코드는 라이브러리 API를 직접 사용합니다. 둘 다 문서화되어 있지만, 예시를 찾거나 배포 명령을 고를 때 이 차이는 매우 중요합니다.
이번 실행에서 유용했던 점은 꽤 분명했습니다. browser context가 세션 상태를 분리해줬고, async 호출은 자연스럽게 이어졌고, 스크린샷은 한 번의 호출로 끝났으며, HTTP 500도 response 객체를 통해 확인할 수 있었습니다. 불편했던 부분은 문법이 아니라 운영 측면이었습니다. 브라우저 빌드는 따로 설치해야 했고, 생명주기 관리도 라이브러리와 분리되어 있었습니다.
직접 실행한 결과

모든 로컬 수치는 127.0.0.1의 fixture 서버를 대상으로 돌렸고, 크롤링 전에 정답 데이터를 먼저 기록해 두었습니다. 정확한 하니스는 run_playwright_material_tests.mjs에 있으며, 커밋된 원본 아티팩트에는 정답 데이터와 각 테스트 결과가 들어 있습니다. 이 수치는 어디까지나 한 대의 머신에서 한 번 실행한 author-run 관찰값이며, 링크는 재현 가능성을 보여줄 뿐 광범위한 벤치마크로 확장해 해석하라는 뜻은 아닙니다.
| 테스트 | 대상 | 결과 |
|---|---|---|
| 정적 카탈로그 + 페이지네이션 | 로컬 fixture | 제품 12/12개, recall 1.0 |
| 기사 추출 | 로컬 fixture | 제목 + 문단 3/3개, 본문 외 잡텍스트 분리 |
| 동적 JS 페이지(네이티브 렌더) | 로컬 fixture | 8/8개, recall 1.0, 전체 페이지 스크린샷 저장 |
동적 JSON API (page.request) | 로컬 fixture | 8/8개, recall 1.0, DOM 렌더링 없음 |
| HTTP 500 처리 | 로컬 fixture | 상태 코드 500 확인 가능, 이동 자체는 실패하지 않음 |
| 크롤 그래프(수동 BFS) | 로컬 fixture | 12개 페이지, depth {0:1, 1:4, 2:7} |
| Books to Scrape | 공개 데모 | 제품 20개 |
| Quotes JS(JS 렌더링) | 공개 데모 | 인용구 10개, 네이티브 렌더링 |
페이지네이션 루프는 다음 링크를 명시적으로 따라갔습니다. Playwright가 스스로 페이지를 찾아준 것은 아니었습니다. 기사 셀렉터는 본문 결과에서 탐색 텍스트와 푸터 텍스트를 분리하는 역할을 했습니다. 실패 경로에서는 이동 시 500 상태의 response 객체가 반환되었고 예외는 던져지지 않았기 때문에, 호출자가 로그를 남길지, 재시도할지, 계속 진행할지 결정해야 했습니다. 두 공개 실습 대상은 표에 적힌 수치 그대로 나왔습니다.
분명히 해둘 경계가 하나 있습니다. 여기의 모든 테스트는 Chromium에서, 한 대의 머신에서, 한 번만 실행했습니다. 기능 표는 문서상 지원 범위와 실제 검증 범위를 따로 표시했습니다. 다른 Playwright 빌드에서 다시 돌려보지도 않았으므로, 버전 간 결론은 내릴 수 없습니다. 각 테스트의 수행 시간도 벤치마크로는 제외했습니다. 노트북 한 대에서 한 번 잰 시간만으로는 속도 비교를 할 수 없기 때문입니다.
준비 상태는 추출 계약의 일부다
동적 결과는 단순히 브라우저 이동이 아니라, 내가 원하는 데이터를 대표하는 대기 조건에 의존했습니다. 로컬 카탈로그에서는 waitUntil: 'domcontentloaded'로 이동한 뒤 waitForSelector('#dynamic-products article.product-card')를 15초 타임아웃으로 기다렸습니다. 공개 Quotes JS 실행도 같은 이동 상태를 사용했고, .quote가 나타날 때까지 20초 동안 기다렸습니다. 그 셀렉터가 보인 뒤에야 추출을 시작했습니다.
스크립트를 다른 대상에 맞게 바꿀 때 이 차이는 매우 중요합니다. domcontentloaded는 초기 문서가 파싱됐다는 뜻일 뿐입니다. 지연 API 응답이 도착했는지, hydration이 끝났는지, 무한 스크롤이 더 이상 늘어나지 않는지, 가상화된 행이 뷰포트 안에 들어왔는지는 알려주지 않습니다. 매칭되는 요소 하나만 있으면 되는 경우에는 셀렉터가 유용합니다. 하지만 완전성이 알려진 응답, 아이템 수, 애플리케이션 상태, 네트워크가 조용해지는 시점에 달려 있다면 그 조건을 기다려야 합니다. 조건은 출력 계약에 맞춰야 합니다. "카드가 하나 이상 존재한다"와 "기대하는 모든 페이지가 로드됐다"는 전혀 다른 주장입니다.

타임아웃 처리 역시 호출자의 책임입니다. 테스트는 유한한 셀렉터 타임아웃을 사용했지만, 재시도 정책을 따로 조사하지 않았고, 느린 페이지와 영구적으로 바뀐 셀렉터를 구분하지도 않았습니다. 프로덕션용 래퍼는 어떤 준비 조건이 실패했는지 기록하고, 문제를 진단할 수 있을 만큼 페이지 상태를 캡처한 다음, 다시 이동해도 안전한지 판단해야 합니다. Playwright는 이벤트와 DOM은 제공하지만, 당신의 작업에서 “완성된 데이터”가 무엇인지는 추론해주지 못합니다.
이 경계는 모든 extractor 옆에 문서화되어 있어야지, 암묵적 타임아웃으로 남겨두면 안 됩니다.
API 경로도 마찬가지로 별도의 계약이 있습니다. ctx.request.get을 쓴 이유는 이미 browser context가 존재했고, 세션 공유가 유용할 수 있었기 때문입니다. 만약 브라우저 세션 없이도 데이터 엔드포인트가 잘 동작한다는 사실을 알게 된다면, 독립 request context는 브라우저를 띄우지 않는 다른 구조이며 수명주기와 쿠키 동작도 다릅니다. 이번 실행에서는 두 방식을 비교하지 않았습니다. "DOM 렌더링이 없었다"는 점만 측정 사실로 보고, 더 큰 워크플로에서 브라우저 프로세스가 정말 필요한지는 별도로 판단해야 합니다.
크롤링은 누가 책임지는가
크롤 그래프 결과는 Playwright를 어떻게 이해해야 하는지 결정해줍니다. 12개 페이지, 3단계 깊이, 정확한 결과. 하지만 이동 로직은 전부 제 몫이었습니다. Playwright는 "이 URL을 열고 읽기"만 맡았고, 큐, visited set, depth 추적은 제가 제공했습니다.
작고 범위가 제한된 작업에서는 별문제가 아닙니다. 하지만 크롤 규모로 커지면 브라우저 라이브러리 위에 직접 크롤러를 얹거나, 이미 그 역할을 해주는 도구와 Playwright를 함께 써야 한다는 뜻입니다. 대표적인 방식은 Crawlee입니다. Crawlee는 Playwright(그리고 Puppeteer)를 감싸서 실제 request queue, dataset 저장, 자동 스로틀링을 제공합니다. 렌더링은 Playwright의 것을 쓰고, 오케스트레이션은 빌려오는 방식입니다. 반대로 프레임워크 자체에 큐가 들어 있기를 원한다면 Scrapy가 그 철학에 가깝습니다. 다만 Scrapy는 HTTP 우선 도구라 JavaScript를 스스로 렌더링하지는 않습니다. 핵심은 Playwright가 부족하다는 뜻이 아니라, "브라우저 자동화"와 "크롤링"은 서로 다른 일이며 Playwright는 그중 하나만 주장한다는 점입니다.

12페이지 BFS는 책임 경계를 아주 명확하게 보여줍니다. 제어된 그래프에서 큐, visited set, depth tracking을 제공했을 뿐입니다. 실제 production frontier라면 여전히 URL canonicalization, redirect 처리, 허용 host, 중복 키, 재시도, 동시성, host별 지연, 지속 저장, 재시작 의미까지 정해야 합니다. 내보내기 방식도 별도의 선택입니다. fixture가 JSON과 CSV를 쓴 이유는 하니스가 그렇게 했기 때문이지, Playwright가 dataset 추상화를 제공해서가 아닙니다.
세션 설계도 래퍼에 영향을 줍니다. 하나의 브라우저 안에 여러 context를 둘 수 있고 쿠키와 저장소는 분리되지만, 이번 리뷰에서는 병렬 context의 확장성이나 실패 분리를 측정하지 않았습니다. context를 재사용하면 로그인 상태를 유지하고 설정 비용을 줄일 수 있습니다. 반대로 context를 분리하면 작업 간 상태 누출을 막을 수 있습니다. 이런 것들은 Playwright가 primitive를 제공하더라도 결국 크롤러 수준의 정책입니다. 실제 운영할 브라우저 빌드와 배포 환경에서 선택한 수명주기를 꼭 벤치마크해야 합니다.
장단점
장점:
- 실제 Chromium 엔진을 통해 JavaScript를 실행함. 두 동적 대상 모두 준비 조건으로 사용한 셀렉터에 도달함.
- 첫 호출에서 전체 페이지 스크린샷 저장 가능.
- 셀렉터 기반 추출로 통제된 fixture의 정적 카탈로그와 기사 필드를 잘 가져옴.
browserContext.request는 이미 올라와 있는 브라우저 프로세스를 유지한 채 페이지 렌더링 없이 JSON 엔드포인트에 접근 가능.- 나쁜 응답에도 견고함: HTTP 500을 확인할 수 있고 이동 과정에서 예외가 발생하지 않음.
- 하나의 API로 세 엔진(Chromium, Firefox, WebKit)을 지원하고, Python, Java, .NET 클라이언트도 제공함(문서상 지원이며, 여기서는 Chromium만 사용).
- Apache-2.0 라이선스이며 Microsoft가 유지보수.
- library mode에 들어가기만 하면 개발 경험이 깔끔함: 엔진 공통 API, 직관적인 async, 간단한 스크린샷.
단점:
- 내장 크롤 큐, dataset, 자동 스로틀링이 없음 — 크롤 규모 작업은 직접 작성하거나 Crawlee 같은 래퍼가 필요함.
- 브라우저 무게감: 바이너리 다운로드와 페이지별 비용이 HTTP 전용 도구보다 실제 부담임.
- 기본 프레이밍이 테스트 러너라서, 스크래핑은 library mode가 있다는 사실을 알고 마케팅된 경로에서 벗어나야 함.
- Playwright 1.56.0과 Chromium만 사용했고, 버전 간·엔진 간 동일성은 확인하지 않음.
- 스키마 기반 구조화 JSON 출력을 자체적으로 제공하지 않음. 셀렉터와 데이터 형태는 직접 설계해야 함.
누구에게 맞고, 누가 피해야 하나
문제가 JavaScript 실행 후에야 데이터가 나타나는 페이지를 렌더링하는 것이거나, DOM 데이터와 함께 스크린샷도 수집해야 하는 경우라면 Playwright는 충분히 재현해볼 만한 후보입니다. 이미 Playwright 테스트를 쓰는 팀이라면 library mode에서도 같은 개념과 셀렉터 감각을 재사용할 수 있습니다. Python, Java, .NET 클라이언트도 문서상 옵션이지만, 이번 리뷰에서 실제로 사용한 것은 Node와 Chromium뿐입니다.
다음 세 경우에는 다른 계층을 고려하세요. 필요한 데이터가 이미 HTTP 응답에 들어 있다면 HTTP 우선 도구가 브라우저 기동과 렌더링 비용을 피할 수 있습니다. 이 범주에는 크롤러 라이브러리 Colly가 있고, 기사 추출에는 Trafilatura가 더 적합합니다. 큐, 지속 저장, 스로틀링이 필요하다면 크롤러 프레임워크나 Playwright 래퍼를 쓰세요. 셀렉터를 계속 관리하지 않고 스키마 형태의 출력을 원한다면 관리형 추출 서비스를 비교해보는 편이 낫습니다. 이 대안들은 이번 리뷰에서 벤치마크하지 않았습니다.
특히 Playwright와 Puppeteer 중에서 고르는 상황이라면 그것은 또 다른 비교입니다. 우리의 비교 리뷰는 같은 fixture로 두 도구를 돌려보고, 실제 선택이 어디에서 갈리는지 보여줍니다.
대안과 관리형 추출의 위치
Playwright는 무료이고 Apache-2.0 라이선스이며 직접 운영하는 방식입니다. 브라우저 배포, 셀렉터, 준비 조건, 크롤 코드, 업데이트, 실패 처리를 모두 사용자가 책임져야 합니다. 이번 리뷰는 안티봇 성능이나 관리형 서비스와의 총운영비 비교는 하지 않았습니다.
오픈소스 안에서의 비교는 작업 단위로 보는 것이 가장 유용합니다. 브라우저 위에서 대규모 크롤 작업을 한다면 Crawlee가 Playwright에 없는 큐와 dataset을 보완해줍니다. 출력 목표가 사람이 읽는 HTML이 아니라 LLM용 Markdown이라면 Crawl4AI가 브라우저를 돌려 Markdown을 생성하는 방식이 더 맞을 수 있습니다. 여러 도구를 한 번에 비교하고 싶다면 우리의 오픈소스 스크래퍼 총정리를 보면 각 범주를 나란히 볼 수 있습니다.
공개: Thunderbit는 이 글의 발행사 제품이며, 이번 Playwright fixture로는 실행하지 않았습니다. Thunderbit는 관리형 추출 범주에 속합니다. 서비스가 렌더링을 운영하고 페이지 텍스트나 스키마 형태의 레코드를 반환하는 반면, Playwright는 브라우저 운영과 셀렉터 로직을 개발자에게 맡깁니다. 따라서 비교 포인트는 호스팅 방식, 출력 형태, 비용 모델이지, 이번 리뷰에서 얻은 성능 결과가 아닙니다.
결론
대상이 브라우저 엔진을 필요로 하고, 준비 상태 조건·셀렉터·크롤 오케스트레이션을 직접 책임질 준비가 되어 있다면 Playwright를 쓰는 것이 맞습니다. 결과 표가 보여주듯, 이번 author-run 테스트에서 Chromium 기반 library mode는 통제된 정적/동적/API/스크린샷/실패 fixture를 기대한 대로 처리했습니다.
다만 증거의 경계는 분명히 유지해야 합니다. 여기서는 Chromium과 Node만 사용했고, 12페이지 순회는 수동 BFS에 의존했으며, browserContext.request는 페이지 렌더링은 건너뛰었지만 이미 실행 중인 브라우저 프로세스는 그대로 사용했고, 모든 동적 추출은 명시된 준비 셀렉터를 사용했습니다. 따라서 이 리뷰에서의 Playwright는 측정된 엔드투엔드 크롤링 시스템이 아니라 브라우저 primitive입니다.
웹 데이터 추출용 Thunderbit 체험하기 Get Started Free
자주 묻는 질문
Playwright로 스크래핑할 때도 기다림(wait)이 꼭 필요한가요?
네. 브라우저가 실행된다고 해서 스크립트가 언제 애플리케이션 데이터가 준비됐는지 알 수 있는 것은 아닙니다. 이번 테스트는 domcontentloaded까지 이동한 뒤, 추출 전에 대상 전용 셀렉터를 기다렸습니다. 실제 서비스 페이지에서는 response, locator 상태, 애플리케이션 이벤트 같은 다른 신호가 필요할 수 있습니다.
Playwright만으로 웹사이트 전체를 크롤링할 수 있나요? 기본 제공만으로는 어렵습니다. request queue, dataset writer, auto-throttle이 없기 때문입니다. 제 crawl-graph 테스트가 depth {0:1, 1:4, 2:7}의 12개 페이지까지 간 것은 BFS를 직접 작성했기 때문입니다. 크롤 규모 작업에서는 Playwright를 Crawlee와 함께 쓰거나, 아예 크롤러 프레임워크를 사용하는 편이 낫습니다.
browserContext.request와 독립 request context는 언제 써야 하나요?
기존 browser context의 페이지와 쿠키를 공유해야 하는 HTTP 호출이라면 browserContext.request를 쓰세요. 브라우저를 띄우지 않고 API 전용 context만 원하고, 브라우저 페이지와 쿠키를 자동 공유할 필요가 없다면 playwright.request.newContext()가 맞습니다. 이번 리뷰에서는 첫 번째 경로만 테스트했습니다.
여기서 Firefox와 WebKit도 테스트했나요? 아니요. 모든 테스트는 한 대의 머신에서 한 번만 Chromium으로 실행했습니다. Playwright의 세 엔진 지원(Chromium, Firefox, WebKit)과 Python, Java, .NET 클라이언트는 문서상 기능으로만 언급한 것이며 검증한 것은 아닙니다. Firefox와 WebKit의 동일성, 프록시, 병렬 확장성, 네트워크 가로채기는 이 수치의 범위를 벗어납니다.
이번 리뷰는 어떤 환경을 기준으로 하나요? Playwright 1.56.0, Node v22.22.3, macOS arm64, 그리고 Chromium만 사용했습니다. Firefox, WebKit, 프록시, 병렬 확장성, 안티봇 동작, 이후 Playwright 버전은 범위 밖이었습니다. 설치에는 라이브러리 외에 별도의 브라우저 빌드 다운로드가 필요했습니다.


