Python을 배워보자

Playwright: 현대적인 웹 테스트 자동화의 강자

_Blue_Sky_ 2025. 7. 26. 19:56
728x90

소개

Playwright는 Microsoft에서 개발한 오픈소스 웹 테스트 자동화 도구로, Chromium, Firefox, WebKit 등 주요 브라우저 엔진을 지원하며 신뢰성 높은 엔드투엔드(E2E) 테스트를 제공합니다. Puppeteer의 한계를 보완하며, 크로스 브라우저 지원, 자동 대기, 네트워크 모킹, 스크린샷 및 비디오 캡처 등 강력한 기능을 자랑합니다. Node.js뿐만 아니라 Python, Java, C#도 지원해 다양한 개발 환경에 적합합니다. 빠른 실행 속도와 직관적인 API로 초보자부터 전문가까지 모두에게 매력적인 선택지입니다.

Playwright의 주요 특징

  1. 크로스 브라우저 지원: Chrome, Firefox, Safari(WebKit)를 단일 API로 테스트 가능.
  2. 자동 대기: 요소가 로드될 때까지 자동으로 대기해 플레이크 테스트(flaky test) 감소.
  3. 다양한 언어 지원: JavaScript/TypeScript, Python, Java, C# 지원.
  4. 강력한 디버깅: 스크린샷, 비디오, 트레이스 뷰어로 문제 원인 파악 용이.
  5. 네트워크 제어: 요청 가로채기, 모킹, 수정 가능.
  6. 멀티 탭/프레임/컨텍스트: 복잡한 웹 앱 시나리오 처리 가능.

다른 프레임워크와 비교

기능/프레임워크 Playwright Puppeteer Selenium Cypress
크로스 브라우저 Chromium, Firefox, WebKit Chromium만 지원 모든 주요 브라우저 Chromium, Firefox
언어 지원 JS, Python, Java, C# JS만 지원 다중 언어 JS/TS만 지원
자동 대기 네이티브 지원 제한적 수동 설정 필요 네이티브 지원
속도 빠름 빠름 느림 빠름
모바일 에뮬레이션 제한적 지원) 지원 제한적
커뮤니티 성장 중 중간 대규모 성장 중
  • Puppeteer: Google이 개발한 도구로 Chromium에 최적화되어 있지만, 다른 브라우저 지원이 없고 Playwright가 이를 보완하며 상위 호환 격.
  • Selenium: 오래된 도구로 다양한 브라우저와 언어를 지원하지만, 설정이 복잡하고 플레이크 테스트가 발생하기 쉬움.
  • Cypress: 현대적인 UI와 빠른 속도를 제공하나, 크로스 브라우저 지원이 제한적이고 JavaScript 전용.

Playwright 설치 및 기본 예제

설치 (Node.js 기준)

npm init -y
npm install @playwright / test
npx playwright install # 브라우저 설치

예제: Google 검색 테스트 (JavaScript)

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: false }); // 브라우저 실행
  const page = await browser.newPage(); // 새 페이지 열기
  await page.goto('https://www.google.com'); // Google로 이동
  await page.fill('input[name="q"]', 'Playwright'); // 검색어 입력
  await page.press('input[name="q"]', 'Enter'); // Enter 키 입력
  await page.waitForSelector('h3'); // 결과 로드 대기
  const results = await page.$$eval('h3', elements => elements.map(el => el.textContent)); // 결과 텍스트 추출
  console.log('검색 결과:', results);
  await browser.close(); // 브라우저 닫기
})();

Python 예제: 로그인 테스트

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://example.com/login')
    page.fill('input#username', 'testuser')
    page.fill('input#password', 'password123')
    page.click('button[type="submit"]')
    page.wait_for_selector('div.dashboard')
    assert 'Welcome' in page.text_content('div.dashboard')
    browser.close()

Playwright 활용 팁

  1. 코드 생성기: npx playwright codegen으로 인터랙티브하게 테스트 코드 생성.
  2. 트레이스 뷰어: npx playwright show-trace trace.zip으로 테스트 실패 원인 시각화.
  3. CI/CD 통합: GitHub Actions, Jenkins 등에서 쉽게 실행 가능.
  4. 병렬 실행: npx playwright test --workers 4로 테스트 속도 향상.

결론

Playwright는 강력한 기능, 크로스 브라우저 지원, 다양한 언어 호환성으로 현대 웹 테스트의 표준으로 자리 잡았습니다. Puppeteer의 상위 호환으로 시작했지만, 이제는 Selenium이나 Cypress를 대체할 수 있는 강력한 대안입니다. 초보자는 직관적인 API로 빠르게 시작할 수 있고, 전문가는 복잡한 시나리오를 처리할 수 있는 유연성을 누릴 수 있습니다. 웹 테스트 자동화를 고민한다면, Playwright는 반드시 고려해야 할 도구입니다.


이 글이 Playwright의 매력을 전달하는 데 도움이 되길 바랍니다! 추가 요청이 있다면 말씀해주세요.


Playwright로 Python을 활용한 웹 테스트 자동화 예제

Playwright의 Python API는 직관적이고 강력하여 다양한 웹 테스트 시나리오를 쉽게 구현할 수 있습니다. 이전 답변에서 제공한 기본 로그인 테스트 외에, 아래는 Python을 사용한 3가지 다양한 Playwright 예제를 소개합니다. 각 예제는 실용적인 시나리오를 다루며, 스크린샷 저장, 네트워크 요청 모킹, 파일 업로드 등 Playwright의 고급 기능을 활용합니다.

예제 1: 웹 페이지 스크린샷 및 PDF 저장

이 예제는 웹 페이지를 방문해 스크린샷과 PDF를 저장하는 방법을 보여줍니다. 예를 들어, 특정 웹 페이지의 렌더링 상태를 기록하거나 문서화가 필요한 경우 유용합니다.

from playwright.sync_api import sync_playwright

def test_screenshot_and_pdf():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()

        # 웹 페이지로 이동
        page.goto('https://www.example.com')

        # 스크린샷 저장
        page.screenshot(path='example_screenshot.png', full_page=True)

        # PDF 저장 (Chromium에서만 지원)
        page.pdf(path='example_page.pdf', format='A4')

        # 페이지 제목 확인
        title = page.title()
        print(f"페이지 제목: {title}")

        browser.close()

if __name__ == "__main__":
    test_screenshot_and_pdf()

설명:

  • page.screenshot: 전체 페이지 스크린샷을 PNG로 저장.
  • page.pdf: 페이지를 PDF로 저장 (Chromium 전용).
  • headless=False로 설정해 브라우저 동작을 시각적으로 확인 가능.

예제 2: 네트워크 요청 모킹

이 예제는 API 요청을 가로채고 모킹하여 테스트 환경을 제어하는 방법을 보여줍니다. 예를 들어, 외부 API 의존성을 제거하고 테스트 데이터를 주입할 때 유용합니다.

from playwright.sync_api import sync_playwright
import json

def test_network_mocking():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()

        # 네트워크 요청 가로채기
        def handle_route(route, request):
            if 'api.example.com/data' in request.url:
                # 모킹된 응답
                mock_response = {
                    "id": 1,
                    "name": "Mocked User",
                    "email": "mocked@example.com"
                }
                route.fulfill(
                    status=200,
                    content_type='application/json',
                    body=json.dumps(mock_response)
                )
            else:
                route.continue_()

        page.route('**/*', handle_route)

        # 테스트 페이지로 이동
        page.goto('https://example.com/app')

        # API 호출 트리거 (예: 버튼 클릭)
        page.click('button#fetch-data')

        # 모킹된 데이터가 페이지에 반영되었는지 확인
        content = page.text_content('div#user-name')
        assert 'Mocked User' in content
        print("모킹된 데이터 확인 완료:", content)

        browser.close()

if __name__ == "__main__":
    test_network_mocking()

설명:

  • page.route: 특정 URL 패턴의 요청을 가로챔.
  • route.fulfill: 모킹된 JSON 응답을 반환.
  • 실제 API 호출 없이 테스트 데이터를 주입해 테스트 안정성 향상.

예제 3: 파일 업로드 및 다운로드 테스트

이 예제는 파일 업로드와 다운로드를 테스트하는 방법을 보여줍니다. 예를 들어, 파일 업로드 기능을 테스트하거나 다운로드된 파일의 내용을 확인할 때 유용합니다.

from playwright.sync_api import sync_playwright
import os

def test_file_upload_download():
    with sync_playwright() as p:
        browser = p.webkit.launch(headless=False)  # WebKit으로 테스트
        page = browser.new_page()

        # 파일 업로드 페이지로 이동
        page.goto('https://the-internet.herokuapp.com/upload')

        # 파일 업로드
        file_path = 'sample.txt'  # 테스트용 파일 생성
        with open(file_path, 'w') as f:
            f.write('Hello, Playwright!')
        page.set_input_files('input#file-upload', file_path)
        page.click('input[type="submit"]')

        # 업로드 성공 확인
        success_message = page.text_content('#uploaded-files')
        assert 'sample.txt' in success_message
        print("파일 업로드 성공:", success_message)

        # 다운로드 테스트
        page.goto('https://the-internet.herokuapp.com/download')
        with page.expect_download() as download_info:
            page.click('a[href="download/some-file.txt"]')
        download = download_info.value
        download_path = 'downloaded_file.txt'
        download.save_as(download_path)

        # 다운로드된 파일 내용 확인
        with open(download_path, 'r') as f:
            content = f.read()
        print("다운로드된 파일 내용:", content)

        browser.close()
        os.remove(file_path)  # 테스트 파일 정리
        os.remove(download_path)

if __name__ == "__main__":
    test_file_upload_download()

설명:

  • page.set_input_files: 파일 업로드를 시뮬레이션.
  • page.expect_download: 다운로드 이벤트를 캡처하고 파일 저장.
  • 실제 파일 I/O와 함께 테스트하여 현실적인 시나리오 구현.

추가 팁

  • 비동기 API: 위 예제는 sync_playwright를 사용했지만, 비동기 작업을 선호한다면 async_playwrightasync/await를 사용할 수 있습니다.
  • 테스트 프레임워크 통합: pytestpytest-playwright 플러그인을 사용해 테스트를 구조화하세요.
  • 디버깅: page.pause()로 실행 중지 후 브라우저 상태 확인 가능.

이 예제들은 Playwright의 Python API를 활용한 다양한 시나리오를 다룹니다. 추가로 특정 기능이나 시나리오에 대한 예제가 필요하면 말씀해주세요!

 


Playwright를 활용한 Python 웹 크롤링 예제

키워드: Playwright, Python, 웹 크롤링, 데이터 추출, 크로스 브라우저, 동적 웹사이트

Playwright는 단순히 테스트 자동화뿐만 아니라 동적 웹사이트 크롤링에도 강력한 도구입니다. JavaScript로 렌더링된 페이지나 복잡한 상호작용이 필요한 사이트에서도 안정적으로 데이터를 추출할 수 있습니다. 아래는 Python과 Playwright를 사용한 웹 크롤링 예제를 추가로 제공하며, 실제 시나리오를 기반으로 다양한 데이터를 수집하는 방법을 보여줍니다.

예제 4: 동적 웹사이트 크롤링 (상품 정보 수집)

이 예제는 전자상거래 사이트(예: 가상의 쇼핑몰)에서 상품 목록을 크롤링하고, 상품 이름, 가격, 리뷰 수를 추출하는 방법을 보여줍니다. 동적 로딩(예: 무한 스크롤)과 페이지 네비게이션을 처리합니다.

from playwright.sync_api import sync_playwright
import json

def crawl_products():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)  # 브라우저 실행 (디버깅 용으로 headless=False)
        page = browser.new_page()

        # 타겟 웹사이트로 이동 (여기서는 예시로 'the-internet.herokuapp.com' 사용)
        page.goto('https://webscraper.io/test-sites/e-commerce/allinone')

        # 동적 콘텐츠 로드 대기
        page.wait_for_selector('.product-wrapper')

        # 상품 데이터 수집
        products = []
        while True:
            # 상품 목록 추출
            product_elements = page.query_selector_all('.product-wrapper')
            for product in product_elements:
                title = product.query_selector('.title').inner_text()
                price = product.query_selector('.price').inner_text()
                reviews = product.query_selector('.ratings p')  # 리뷰 수
                review_count = reviews.inner_text() if reviews else '0 reviews'

                products.append({
                    'title': title,
                    'price': price,
                    'reviews': review_count
                })

            # 다음 페이지 버튼 확인
            next_button = page.query_selector('a[aria-label="Next"]')
            if next_button and 'disabled' not in next_button.get_attribute('class'):
                next_button.click()
                page.wait_for_timeout(2000)  # 페이지 로드 대기
            else:
                break  # 더 이상 페이지가 없으면 종료

        # 결과 출력 및 저장
        print(f"총 {len(products)}개의 상품 수집 완료")
        for product in products:
            print(product)

        # JSON 파일로 저장
        with open('products.json', 'w', encoding='utf-8') as f:
            json.dump(products, f, ensure_ascii=False, indent=2)

        browser.close()

if __name__ == "__main__":
    crawl_products()

설명:

  • 동적 콘텐츠 처리: page.wait_for_selector로 상품 목록이 로드될 때까지 대기.
  • 데이터 추출: CSS 셀렉터(query_selector)로 상품 정보(제목, 가격, 리뷰 수)를 추출.
  • 페이지 네비게이션: 다음 페이지 버튼을 찾아 클릭하며 무한 스크롤 또는 페이지네이션 처리.
  • 결과 저장: 수집된 데이터를 JSON 파일로 저장해 후속 분석 가능.
  • 사이트 선택: 예제에서는 webscraper.io의 테스트 사이트를 사용했으나, 실제 사이트(예: Amazon, eBay)로 변경하려면 셀렉터와 URL을 조정해야 합니다.

추가 팁

  • 헤드리스 모드: headless=True로 설정해 서버 환경에서 실행 가능.
  • 에러 처리: 실제 크롤링에서는 try-except를 추가해 네트워크 오류나 셀렉터 누락에 대비하세요.
  • 속도 최적화: page.wait_for_timeout 대신 특정 요소 로드를 기다리는 wait_for_selector를 활용해 효율성을 높이세요.
  • 법적 주의: 크롤링 시 대상 사이트의 이용 약관(Terms of Service)과 robots.txt를 확인하세요.

실행 전 준비

  1. Playwright 설치:
    pip install playwright
    playwright install
  2. 테스트 사이트 외의 실제 사이트를 크롤링할 경우, 셀렉터와 페이지 구조를 개발자 도구로 확인하세요.
  3. 대량 크롤링 시 IP 차단을 피하려면 프록시나 요청 간 딜레이를 추가하세요.

이 예제를 통해 Playwright로 동적 웹사이트 크롤링을 쉽게 시작할 수 있습니다. 추가로 특정 사이트나 데이터(예: 이미지 URL, 상세 페이지 크롤링)를 대상으로 한 예제가 필요하면 말씀해주세요!

728x90