211 lines
8.5 KiB
Python
211 lines
8.5 KiB
Python
import sys
|
|
import asyncio
|
|
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLabel,
|
|
QLineEdit, QPushButton, QComboBox, QTextEdit, QFileDialog, QHBoxLayout)
|
|
from PyQt5.QtCore import Qt
|
|
from playwright.async_api import async_playwright
|
|
from PyQt5.QtGui import QClipboard
|
|
|
|
class PlaywrightTester(QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
# GUI 레이아웃 설정
|
|
self.initUI()
|
|
self.browser = None
|
|
self.page = None
|
|
self.elements = [] # 여러 요소를 찾을 때 저장하는 리스트
|
|
self.current_element_index = 0 # 현재 확인 중인 요소 인덱스
|
|
self.playwright = None
|
|
self.log_file_path = None
|
|
self.clipboard = QApplication.clipboard()
|
|
|
|
def initUI(self):
|
|
layout = QVBoxLayout()
|
|
|
|
# 테스트할 URL 입력 필드
|
|
self.url_input = QLineEdit(self)
|
|
self.url_input.setPlaceholderText("Enter URL to test")
|
|
self.url_input.setText("https://percenty.co.kr")
|
|
layout.addWidget(self.url_input)
|
|
|
|
# 선택자 타입 설명 라벨
|
|
self.selector_type_label = QLabel("Selector Type (CSS, XPath, Name):")
|
|
layout.addWidget(self.selector_type_label)
|
|
|
|
# 선택자 타입 콤보박스 (CSS, XPath, Name)
|
|
self.selector_type_combobox = QComboBox()
|
|
self.selector_type_combobox.addItems(["CSS", "XPath", "Name"])
|
|
self.selector_type_combobox.currentIndexChanged.connect(self.update_selector_input)
|
|
layout.addWidget(self.selector_type_combobox)
|
|
|
|
# 선택자 입력 필드
|
|
self.selector_input = QLineEdit(self)
|
|
self.selector_input.setPlaceholderText("Enter selector here (CSS, XPath, Name)")
|
|
layout.addWidget(self.selector_input)
|
|
|
|
# Playwright 실행 버튼
|
|
self.playwright_button = QPushButton("Start Playwright", self)
|
|
self.playwright_button.clicked.connect(self.start_playwright)
|
|
layout.addWidget(self.playwright_button)
|
|
|
|
# 요소 찾기 버튼
|
|
self.find_button = QPushButton("Find Element", self)
|
|
self.find_button.clicked.connect(self.find_element)
|
|
layout.addWidget(self.find_button)
|
|
|
|
# 요소 클릭 버튼
|
|
self.click_button = QPushButton("Click Element", self)
|
|
self.click_button.clicked.connect(self.click_element)
|
|
layout.addWidget(self.click_button)
|
|
|
|
# 다음 요소 확인 버튼 (여러 요소가 있을 때)
|
|
self.next_element_button = QPushButton("Next Element", self)
|
|
self.next_element_button.clicked.connect(self.show_next_element)
|
|
layout.addWidget(self.next_element_button)
|
|
|
|
# 선택자 복사 버튼
|
|
self.copy_selector_button = QPushButton("Copy Selector", self)
|
|
self.copy_selector_button.clicked.connect(self.copy_selector)
|
|
layout.addWidget(self.copy_selector_button)
|
|
|
|
# 로그 창 (출력 결과 표시)
|
|
self.log_output = QTextEdit(self)
|
|
self.log_output.setReadOnly(True)
|
|
layout.addWidget(self.log_output)
|
|
|
|
# 메인 레이아웃 설정
|
|
self.setLayout(layout)
|
|
self.setWindowTitle('Playwright Element Tester')
|
|
self.setGeometry(300, 300, 400, 400)
|
|
|
|
def log_message(self, message):
|
|
"""로그 출력 및 저장"""
|
|
self.log_output.append(message)
|
|
|
|
def update_selector_input(self):
|
|
"""선택자 타입에 따라 입력 필드를 업데이트"""
|
|
selector_type = self.selector_type_combobox.currentText()
|
|
if selector_type == "Name":
|
|
self.selector_input.setPlaceholderText("Enter text to find elements by Name")
|
|
else:
|
|
self.selector_input.setPlaceholderText(f"Enter {selector_type} selector here")
|
|
|
|
async def async_playwright_setup(self, url):
|
|
"""Playwright 비동기 실행 및 페이지 설정"""
|
|
self.playwright = await async_playwright().start()
|
|
self.browser = await self.playwright.chromium.launch(headless=False)
|
|
|
|
# 페이지 생성 시 viewport 설정
|
|
self.page = await self.browser.new_page(viewport={"width": 1920, "height": 1080})
|
|
await self.page.goto(url)
|
|
|
|
def start_playwright(self):
|
|
"""Playwright 실행"""
|
|
url = self.url_input.text()
|
|
if not url:
|
|
self.log_message("URL을 입력하세요.")
|
|
return
|
|
|
|
self.log_message(f"Playwright 실행 중... URL: {url}")
|
|
loop = asyncio.get_event_loop()
|
|
loop.run_until_complete(self.async_playwright_setup(url))
|
|
self.log_message("Playwright 실행 완료. 페이지 로드됨.")
|
|
|
|
async def find_element_async(self):
|
|
"""요소 찾기 비동기 작업"""
|
|
selector_type = self.selector_type_combobox.currentText()
|
|
selector = self.selector_input.text()
|
|
|
|
try:
|
|
self.elements = [] # 요소 리스트 초기화
|
|
if selector_type == "CSS":
|
|
self.elements = await self.page.query_selector_all(selector)
|
|
elif selector_type == "XPath":
|
|
self.elements = await self.page.query_selector_all(selector)
|
|
elif selector_type == "Name":
|
|
# 이름을 기준으로 요소 찾기
|
|
self.elements = await self.page.query_selector_all(f'[name="{selector}"]')
|
|
|
|
if self.elements:
|
|
self.current_element_index = 0
|
|
self.log_message(f"요소 찾기 성공. 총 {len(self.elements)}개의 요소 발견.")
|
|
await self.show_current_element_info()
|
|
else:
|
|
self.log_message(f"요소를 찾을 수 없음: {selector}")
|
|
|
|
except Exception as e:
|
|
self.log_message(f"오류 발생: {e}", exc_info=True)
|
|
|
|
def find_element(self):
|
|
"""요소 찾기 동작"""
|
|
self.log_message("요소 찾기 시작...")
|
|
loop = asyncio.get_event_loop()
|
|
loop.run_until_complete(self.find_element_async())
|
|
|
|
async def show_current_element_info(self):
|
|
"""현재 선택된 요소의 정보를 표시"""
|
|
if not self.elements:
|
|
self.log_message("요소가 없습니다.")
|
|
return
|
|
|
|
current_element = self.elements[self.current_element_index]
|
|
selector_type = self.selector_type_combobox.currentText()
|
|
|
|
# 요소 정보 출력
|
|
if selector_type == "CSS":
|
|
element_info = await current_element.evaluate("e => e.outerHTML")
|
|
self.log_message(f"요소 {self.current_element_index + 1}/{len(self.elements)} 정보: {element_info}")
|
|
elif selector_type == "XPath":
|
|
element_info = await current_element.evaluate("e => e.outerHTML")
|
|
self.log_message(f"요소 {self.current_element_index + 1}/{len(self.elements)} 정보: {element_info}")
|
|
elif selector_type == "Name":
|
|
element_info = await current_element.evaluate("e => e.outerHTML")
|
|
self.log_message(f"요소 {self.current_element_index + 1}/{len(self.elements)} 정보: {element_info}")
|
|
|
|
def show_next_element(self):
|
|
"""다음 요소 확인"""
|
|
if not self.elements:
|
|
self.log_message("찾은 요소가 없습니다.")
|
|
return
|
|
|
|
self.current_element_index = (self.current_element_index + 1) % len(self.elements)
|
|
loop = asyncio.get_event_loop()
|
|
loop.run_until_complete(self.show_current_element_info())
|
|
|
|
async def click_element_async(self):
|
|
"""요소 클릭 비동기 작업"""
|
|
if not self.elements:
|
|
self.log_message("요소가 없어서 클릭할 수 없습니다.")
|
|
return
|
|
|
|
try:
|
|
current_element = self.elements[self.current_element_index]
|
|
await current_element.click()
|
|
self.log_message(f"요소 클릭 성공: {self.current_element_index + 1}/{len(self.elements)}")
|
|
|
|
except Exception as e:
|
|
self.log_message(f"클릭 오류 발생: {e}", exc_info=True)
|
|
|
|
def click_element(self):
|
|
"""요소 클릭 동작"""
|
|
self.log_message("요소 클릭 시작...")
|
|
loop = asyncio.get_event_loop()
|
|
loop.run_until_complete(self.click_element_async())
|
|
|
|
def copy_selector(self):
|
|
"""현재 선택한 요소의 선택자를 클립보드로 복사"""
|
|
if not self.elements:
|
|
self.log_message("복사할 요소가 없습니다.")
|
|
return
|
|
|
|
selector = self.selector_input.text()
|
|
self.clipboard.setText(selector)
|
|
self.log_message(f"선택자 복사 완료: {selector}")
|
|
|
|
if __name__ == '__main__':
|
|
app = QApplication(sys.argv)
|
|
ex = PlaywrightTester()
|
|
ex.show()
|
|
sys.exit(app.exec_())
|