- 기본적인 Playwright 사용법을 익히기 위한 튜토리얼입니다.
- 최대한 적은 기능을 사용하려 했습니다.
- Playwright는 브라우저를 제어하기 위한 Node.js 라이브러리입니다.
- playwright는 Python, Java, C# 등 다양한 언어를 지원합니다.
- Chromium, Webkit, Firefox를 지원합니다.
- 비동기를 지원하기 때문에 await, async를 사용할 수 있습니다.
- codegen을 지원하여, 브라우저에서 작업한 내용을 코드로 변환할 수 있습니다.
pip install playwright로 설치가 가능합니다.- 기본적으로 playwright에서 사용하는 브라우저를 설치해야 합니다.
playwright install [chromium|webkit|firefox]로 설치가 가능합니다.- 실제 사용할 때 channel을 지정하면 PC에 설치된 브라우저를 그대로 사용할 수 있습니다.(사용자 정보는 별도)
- playwright는 크게
PlaywrightContextManager,Browser,Context,Page,Locator의 5가지로 구성되어 있습니다.
- PlaywrightContextManager는
from playwright.sync_api import sync_playwright를 import하여 사용할 수 있습니다. - 안전한 실행과 종료를 위해
with sync_playwright() as p형태의 with문을 사용합니다.
- Browser는
PlaywrightContextManager를 통해 생성됩니다. - 실제 브라우저를 실행 및 관리합니다.
p.chromium.launch()형태로 브라우저를 실행할 수 있습니다.- 브라우저를 실행할 때 헤드리스 여부, 채널, 사용자 데이터 디렉토리 등을 지정할 수 있습니다.
- Context는 브라우저 내에서 다수의 컨텍스트를 위한 선택사항이며,
Browser를 통해 생성됩니다. browser.new_context()형태로 생성할 수 있습니다.
- Page는 브라우저에서 실제로 작업을 수행하는 탭이라 불리는 하나의 객체입니다.
browser.new_page(),context.new_page()형태로 생성할 수 있습니다.page.goto(URL)형태로 페이지를 이동할 수 있습니다.- 대부분의 페이지 관련 인터랙션은
page를 통해 이루어집니다.
- Locator는
Page,Locator를 통해 생성되며, DOM을 탐색하는데 사용됩니다. - 기존의 css selector, xpath 등을 사용할 수 있습니다.
- 추가로 다양항 형태의 선택자를 지원합니다.
page.queryselector등도 지원하지만, locator를 통해 엘리먼트에 접근하는 것을 권장합니다.
-
아래 예제는
playwright를 사용하여https://www.naver.com에 접속하여 로그인 하고 메일 리스트를 가져오는 예제입니다.from os import environ # 환경변수를 가져오기 위한 모듈 from playwright.sync_api import sync_playwright # 환경변수에서 아이디와 비밀번호를 가져옴 USER_ID = environ.get('NAVER_USER_ID', None) USER_PW = environ.get('NAVER_USER_PW', None) if USER_ID is None or USER_PW is None: raise ValueError('NAVER_USER_ID, NAVER_USER_PW 환경변수를 설정해주세요.') # with문을 이용하여 playwright를 사용할 수 있도록 함 with sync_playwright() as p: # 브라우저 실행 시 채널을 chrome로 설정하여 별도의 실행환경을 설치하지 않아도 됨 # headless=False로 설정하여 브라우저를 실행하고, slow_mo=100으로 설정 browser = p.chromium.launch(headless=False, channel="chrome", slow_mo=100) context = browser.new_context() page = context.new_page() page.goto('https://www.naver.com') # 로그인 과정 page.click('#account > a') page.fill('input[name=id]', USER_ID) page.fill('input[name=pw]', USER_PW) page.click('button.btn_login') # 메일 페이지로 이동 page.goto('https://mail.naver.com') # 메일 목록을 가져오기 위해 페이지 로딩이 완료될 때까지 대기 page.wait_for_load_state('networkidle') # css selector를 이용하여 메일 목록을 가져옴 mail_list = page.locator('li.mail_item') # 메일 목록의 개수를 가져옴 mail_cnt = mail_list.count() # 메일 목록을 순회하며 메일 제목과 보낸 사람을 출력 for i in range(mail_cnt): mail = mail_list.nth(i) # 메일 목록 중 i번째 메일을 가져옴 mail.highlight() # 데이터가 아래와 같이 구성되어있어 TEXT NODE에 접근해야 값을 가져올 수 있음 # <button type="button" class="button_sender" ><span class="blind">보낸 사람</span>네이버</button> # 이를 위해 XPath를 이용하여 TEXT NODE에 접근 # 데이터를 감싸는 태그를 찾아서 해당 태그를 기준으로 TEXT NODE에 접근 sender = mail.locator('//*[@class="mail_sender"]/button') # evaluate 함수를 이용하여 js 코드를 실행할 수 있으며, 호출 시 데이터를 전달할 수 있음 sender_text = sender.evaluate('(sender, x) => document.evaluate(x, sender, null, XPathResult.STRING_TYPE).stringValue', 'text()') title = mail.locator('a.mail_title_link') # 메일 제목과 보낸 사람을 출력 #sender_text는 자체가 문자열, title은 locator이기 때문에 text_content()를 이용하여 문자열을 가져옴 print(f'{sender_text}: {title.text_content()}') # 브라우저 종료 browser.close()
5. Playwright codegen 기능 이용해 보기(관련 링크)
codegen은 playwright의 확장 기능이기 때문에playwright install을 해야 사용할 수 있음- playwright codegen 기능을 이용하면 브라우저에서 수행한 작업을 레코딩하여 파이썬 코드로 변환해줌
playwright codegen URL형태로 사용하며, 실행시 브라우저가 실행되고, 브라우저에서 수행한 작업을 레코딩됨- 본 기능은 대략적인 참고용으로만 사용하고, 실제 코드를 작성할 때는 코드를 직접 작성하는 것이 좋음(codegen은 해당 행위에 대한 specipic한 코드만 생성하기 때문에 범용적인 프로그램에는 어울리지 않을 수 있음)
page.goto(url): 해당 url로 이동page.locator(selector): 해당 selector를 찾아 locator 객체를 반환page.click(selector): 해당 selector를 클릭page.fill(selector, text): 해당 selector에 text를 입력page.screenshot(path="example.png"): 현재 페이지의 스크린샷을 path에 저장locator.highlight(): 해당 locator를 화면에 강도하여 표시locator.click(): 해당 locator를 클릭locator.fill(text): 해당 locator에 text를 입력locator.text_content(): 해당 locator의 text를 반환locator.evaluate(func, *args): 해당 locator에 자바스크립트 함수를 실행하고, args를 전달함locator.check(): 해당 locator를 체크함locator.uncheck(): 해당 locator를 체크 해제함locator.is_checked(): 해당 locator가 체크되어 있는지 확인locator.is_disabled(): 해당 locator가 비활성화 되어 있는지 확인locator.press("Enter"): 해당 locator에 key를 입력함locator.set_input_files('myfile.pdf'): 해당 locator에 파일을 업로드함locator.select_option('blue'): 해당 locator의 value를 기준으로 option을 선택함locator.select_option(label='blue'): 해당 locator의 label을 기준으로 option을 선택함page.locator("#item-to-be-dragged").drag_to(page.locator("#item-to-drop-at")): 해당 locator를 드래그하여 다른 locator에 드랍함
-
playwright는 파일 다운로드를 기다리는 컨택스트를 제공함
-
내부적으로는
expect_event를 이용하여 다운로드가 시작되는 것을 기다리고, 다운로드가 시작되면Download객체를 반환함# 다운로드가 시작되는 것을 기다리는 컨택스트 with page.expect_download() as download_info: 다운로드 창을 띄우기 위한 작업 page.get_by_text("Download file").click() # 실제 다운로드 정보를 가져옴 download = download_info.value # 원하는 이름으로 파일 저장 download.save_as("/path/to/save/download/at.txt") # 추천하는 이름으로 파일 저장 download.save_as(download.suggested_filename)
-
playwright는 기본적으로 다이얼로그가 나타나면
dismiss를 수행함 -
다이얼로그 발생시 적절한 처리를 할 수 있는 핸들러를 등록할 수 있음
-
playwright의 모든 핸들러는
page.on('event_name', handler)형태로 등록할 수 있음 -
1회성 핸들러는
page.once('event_name', handler)형태로 등록할 수 있음# 다이얼로그가 발생하면 accept를 수행하는 핸들러 등록 page.on("dialog", lambda dialog: dialog.accept()) # 다이얼로그 발생 page.evaluate("() => confirm('동의하시겠습니까?')") page.evaluate("() => alert('경고창입니다.')")
-
playwright는
Trace Viewer라고 하는 로그를 기록하는 기능을 제공함 -
playwright를 시작할 때 간단한 설정을 추가하여 로그를 기록할 수 있음
-
로그 내역은 zip 파일로 저장되며,
playwright show-trace trace.zip명령어를 통해 확인할 수 있음browser = chromium.launch() context = browser.new_context() # 로그를 기록하기 위한 설정 # 로그를 기록할 때 스크린샷, 소스코드, 스냅샷을 함께 기록하도록 설정할 수 있음 context.tracing.start(screenshots=True, snapshots=True, sources=True) page = context.new_page() page.goto("https://playwright.dev") page.screenshot(path="example.png") # 원하는 순간에 로그 기록을 중단하고 zip 파일로 저장할 수 있음 context.tracing.stop(path = "trace.zip") browser.close()
playwright show-trace trace.zip
- playwright는
page.wait_for_state()를 통해 특정 상태가 될 때까지 대기할 수 있음 - 크게 3가지 상태를 지원함
load- load 이벤트가 발생할 때까지 기다림domcontentloaded- DOMContentLoaded 이벤트가 발생할 때까지 기다림networkidle- 최소 0.5초를 기다리며, 더이상 네트워크 연결이 없을 때까지 기다림(가장 유용한 기능)
- 이러한 기능들은 대부분의 기능(click, goto 등)에서도
wait_until형태로 지원
- 기본적으로 playwright는 auto-waiting을 지원함
- 그럼에도 불구하고 특정 상황에는 의도적으로 기다려야 하는 경우가 생김
- playwright는 비동기 방식으로 동작하기 때문에,
time.sleep()을 사용하면 의도한 대로 동작하지 않을 수 있음 page.wait_for_timeout(ms)을 사용하여 동일한 기능을 구현할 수 있음
- playwright는 pyinstaller로 배포하는 것을 고려하여 만들어져 있음
- bash
PLAYWRIGHT_BROWSERS_PATH=0 playwright install chromium pyinstaller -F main.py
- cmd
set PLAYWRIGHT_BROWSERS_PATH=0 playwright install chromium pyinstaller -F main.py
- powershell
$env:PLAYWRIGHT_BROWSERS_PATH="0" playwright install chromium pyinstaller -F main.py

