[official skill] μΉ μ ν리μΌμ΄μ ν μ€ν
μ΄ μ€ν¬μ Python Playwrightλ₯Ό μ¬μ©νμ¬ λ‘컬 μΉ μ ν리μΌμ΄μ μ μλμΌλ‘ ν μ€νΈνκ³ κ²μ¦νλ λꡬμ λλ€.
π μ°Έκ³ : μ΄ λ¬Έμλ 곡μ Claude Code λ¬Έμμ μλ¬Έ + λ νΌλ°μ€μ λλ€.
- μλ¬Έ λ§ν¬λ₯Ό μ§μ μ¬μ©νμ λ λ©λλ€
- μ΄ νμΌμ
.claude/skills/νμμ 볡μ¬νμ¬ μ€ν¬λ‘ λ±λ‘ν μλ μμ΅λλ€(2026.03.15 κΈ°μ€)
μΉ μ ν리μΌμ΄μ ν μ€ν
λ‘컬 μΉ μ ν리μΌμ΄μ μ ν μ€νΈνλ €λ©΄ λ€μ΄ν°λΈ Python Playwright μ€ν¬λ¦½νΈλ₯Ό μμ±νμΈμ.
μ¬μ© κ°λ₯ν ν¬νΌ μ€ν¬λ¦½νΈ:
scripts/with_server.py- μλ² μλͺ μ£ΌκΈ° κ΄λ¦¬ (λ€μ€ μλ² μ§μ)
νμ μ€ν¬λ¦½νΈλ₯Ό --helpμ ν¨κ» λ¨Όμ μ€ννμΈμ μ¬μ©λ²μ νμΈνκΈ° μν΄. μ€ν¬λ¦½νΈλ₯Ό λ¨Όμ μ€νν΄λ³΄κ³ λ§μΆ€ μ루μ
μ΄ μ λμ μΌλ‘ νμνλ€κ³ νλ¨λκΈ° μ κΉμ§λ μμ€λ₯Ό μ½μ§ λ§μΈμ. μ΄ μ€ν¬λ¦½νΈλ€μ λ§€μ° ν΄ μ μμ΄ μ»¨ν
μ€νΈ μλμ°λ₯Ό μ€μΌμν΅λλ€. μ΄ μ€ν¬λ¦½νΈλ€μ 컨ν
μ€νΈ μλμ°μ λ΄μ©μ μ£Όμ
νκΈ°λ³΄λ€ λΈλλ°μ€ μ€ν¬λ¦½νΈλ‘μ μ§μ νΈμΆλλλ‘ λ§λ€μ΄μ‘μ΅λλ€.
μμ¬κ²°μ νΈλ¦¬: μ κ·Ό λ°©μ μ ν
μ¬μ©μ μμ
--> μ μ HTMLμΈκ°?
|-- μ --> HTML νμΌμ μ§μ μ½μ΄ μ
λ ν° μλ³
| |-- μ±κ³΅ --> μ
λ ν°λ₯Ό μ¬μ©νμ¬ Playwright μ€ν¬λ¦½νΈ μμ±
| +-- μ€ν¨/λΆμμ --> λμ μΌλ‘ μ·¨κΈ (μλ μ°Έμ‘°)
|
+-- μλμ€ (λμ μΉμ±) --> μλ²κ° μ΄λ―Έ μ€ν μ€μΈκ°?
|-- μλμ€ --> μ€ν: python scripts/with_server.py --help
| κ·Έλ° λ€μ ν¬νΌλ₯Ό μ¬μ©νκ³ + κ°μνλ Playwright μ€ν¬λ¦½νΈ μμ±
|
+-- μ --> μ μ°° ν νλ:
1. λ€λΉκ²μ΄μ
ν networkidle λκΈ°
2. μ€ν¬λ¦°μ· 촬μ λλ DOM κ²μ¬
3. λ λλ§λ μνμμ μ
λ ν° μλ³
4. λ°κ²¬λ μ
λ ν°λ‘ μ‘μ
μ€ν
μμ : with_server.py μ¬μ©
μλ²λ₯Ό μμνλ €λ©΄ λ¨Όμ --helpλ₯Ό μ€νν λ€μ ν¬νΌλ₯Ό μ¬μ©νμΈμ:
λ¨μΌ μλ²:
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.py
λ€μ€ μλ² (μ: λ°±μλ + νλ‘ νΈμλ):
python scripts/with_server.py \
--server "cd backend && python server.py" --port 3000 \
--server "cd frontend && npm run dev" --port 5173 \
-- python your_automation.py
μλν μ€ν¬λ¦½νΈλ₯Ό λ§λ€ λλ Playwright λ‘μ§λ§ ν¬ν¨νμΈμ (μλ²λ μλμΌλ‘ κ΄λ¦¬λ©λλ€):
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True) # νμ chromiumμ headless λͺ¨λλ‘ μ€ν
page = browser.new_page()
page.goto('http://localhost:5173') # μλ²κ° μ΄λ―Έ μ€ν μ€μ΄λ©° μ€λΉ μλ£
page.wait_for_load_state('networkidle') # μ€μ: JS μ€ν μλ£ λκΈ°
# ... μλν λ‘μ§
browser.close()
μ μ°° ν νλ ν¨ν΄
-
λ λλ§λ DOM κ²μ¬:
page.screenshot(path='/tmp/inspect.png', full_page=True) content = page.content() page.locator('button').all() -
κ²μ¬ κ²°κ³Όμμ μ λ ν° μλ³
-
λ°κ²¬λ μ λ ν°λ₯Ό μ¬μ©νμ¬ μ‘μ μ€ν
νν μ€μ
- νμ§ λ§μΈμ: λμ μ±μμ
networkidleμ κΈ°λ€λ¦¬κΈ° μ μ DOMμ κ²μ¬νλ κ² - νμΈμ: κ²μ¬ μ μ
page.wait_for_load_state('networkidle')μ κΈ°λ€λ¦¬κΈ°
λͺ¨λ² μ¬λ‘
- λ²λ€λ μ€ν¬λ¦½νΈλ₯Ό λΈλλ°μ€λ‘ μ¬μ©νμΈμ - μμ
μ μνν λ
scripts/μ μλ μ€ν¬λ¦½νΈ μ€ λμμ΄ λ μ μλ κ²μ΄ μλμ§ κ³ λ €νμΈμ. μ΄ μ€ν¬λ¦½νΈλ€μ 컨ν μ€νΈ μλμ°λ₯Ό μ΄μ§λ½νμ§ μμΌλ©΄μ μΌλ°μ μ΄κ³ 볡μ‘ν μν¬νλ‘μ°λ₯Ό μμ μ μΌλ‘ μ²λ¦¬ν©λλ€.--helpλ‘ μ¬μ©λ²μ νμΈν λ€μ μ§μ νΈμΆνμΈμ. - λκΈ°μ μ€ν¬λ¦½νΈμ
sync_playwright()μ¬μ© - μλ£ μ νμ λΈλΌμ°μ λ«κΈ°
- μμ μ μ
λ ν° μ¬μ©:
text=,role=, CSS μ λ ν°, λλ ID - μ μ ν λκΈ° μΆκ°:
page.wait_for_selector()λλpage.wait_for_timeout()
μ°Έμ‘° νμΌ
- examples/ - μΌλ°μ μΈ ν¨ν΄μ 보μ¬μ£Όλ μμ :
element_discovery.py- νμ΄μ§μμ λ²νΌ, λ§ν¬, μ λ ₯ μμ λ°κ²¬static_html_automation.py- λ‘컬 HTMLμ file:// URL μ¬μ©console_logging.py- μλν μ€ μ½μ λ‘κ·Έ μΊ‘μ²