title 추가

This commit is contained in:
R5600U_PC 2024-10-11 16:23:20 +09:00
parent 6f7a6249eb
commit d7ddac9162
5 changed files with 394 additions and 7 deletions

View File

@ -39,9 +39,39 @@ leading_text_6 = "**반드시 옵션사진과 옵션이름을 확인하시고
leading_text_7 = "---"
# 필요한 만큼 추가 가능
[ProductNameLocators]
product_name_input_locator = //*[@id='productMainContentContainerId']/div/div[1]/div/div/div[1]/input
[TitleLocators]
# 상품명 관련 선택자
product_name_input_locator = //*[@id='productMainContentContainerId']/div/div[1]/div[5]/div[1]/span/input
product_name_input_css_path = 'div#productMainContentContainerId div:nth-child(5) > div:nth-child(1) > span > input'
# 상품명 추천단어 입력칸 선택자
product_name_suggestion_input_locator = //*[@id="productMainContentContainerId"]/div/div[1]/div[2]/div[2]/div/span/span/span[1]/input
product_name_suggestion_input_css_path = 'div#productMainContentContainerId div:nth-child(2) > div:nth-child(2) > div > span > span > span.ant-input-affix-wrapper.css-1li46mu.ant-input-outlined > input'
# 상품명 추천단어 입력 검색 버튼 선택자
product_name_search_button_locator = //*[@id="productMainContentContainerId"]/div/div[1]/div[2]/div[2]/div/span/span/span[2]/button
product_name_search_button_css_path = 'div#productMainContentContainerId div:nth-child(2) > div:nth-child(2) > div > span > span > span.ant-input-group-addon > button[type="button"]'
# 원본 상품명 선택자
original_product_name_locator = //*[@id="productMainContentContainerId"]/div/div[1]/div[6]/div[1]/div/span
original_product_name_css_path = 'div#productMainContentContainerId div.sc-aNeao.tNLFa > div.ant-flex.css-1li46mu.ant-flex-align-stretch.ant-flex-vertical > div:nth-child(1) > div > span'
# 상품명의 경고단어 삭제 버튼 선택자
product_name_warning_delete_button_locator = //*[@id="productMainContentContainerId"]/div/div[1]/div[6]/div[3]/div[2]/div/button
product_name_warning_delete_button_css_path = 'div#productMainContentContainerId div:nth-child(2) > div > button[type="button"]'
# 카테고리 관련 선택자
category_suggestion_button_locator = //*[@id='productMainContentContainerId']/div/div[1]/div[5]/div[2]/button
category_suggestion_button_css_path = 'div#productMainContentContainerId div:nth-child(2) > button[type="button"]'
# 카테고리 선택자 - 인증 여부에 따른 분기
category_main_selector_with_cp = '#productMainContentContainerId .ant-select.ant-select-outlined.css-1li46mu.ant-select-single.ant-select-show-arrow:nth-of-type(1)'
category_main_selector_with_ss = '#productMainContentContainerId .ant-select.ant-select-outlined.css-1li46mu.ant-select-single.ant-select-show-arrow:nth-of-type(2)'
category_main_selector_with_esm = '#productMainContentContainerId .ant-select.ant-select-outlined.css-1li46mu.ant-select-single.ant-select-show-arrow:nth-of-type(3)'
category_certified_text_locator = div.ant-col.css-1li46mu:nth-child(1)
category_text_with_certification_locator = div.ant-col.css-1li46mu:nth-child(2)
category_text_without_certification_locator = div.ant-col.css-1li46mu:nth-child(1)
[BrowserControl]
# 크롬 창 이름

10
gui.py
View File

@ -716,11 +716,11 @@ class TranslationApp(QWidget):
self.logger.debug(f'{index}/{len(product_buttons)}: 세부사항 수정 작업 중...')
# 상품명 수집 및 수집 오류 처리
product_name = await self.browser_controller.get_product_name(index, 'css')
if product_name == "수집 오류 발생":
self.logger.debug('상품 수집 오류, 다음 상품으로 넘어갑니다.')
continue
# # 상품명 수집 및 수집 오류 처리
# product_name = await self.browser_controller.get_product_name(index, 'css')
# if product_name == "수집 오류 발생":
# self.logger.debug('상품 수집 오류, 다음 상품으로 넘어갑니다.')
# continue
# 상품 수정 다이얼로그 열기
await self.browser_controller.open_product_edit_dialog(button)

146
test/ele_test.py Normal file
View File

@ -0,0 +1,146 @@
import asyncio
from playwright.async_api import async_playwright
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget, QMessageBox
from qasync import QEventLoop
import sys
class CategoryHandler:
def __init__(self, page):
self.page = page
async def handle_category_action(self):
# #productMainContentContainerId 내부에서 클래스 이름 "ant-select ant-select-outlined css-1li46mu ant-select-single ant-select-show-arrow"를 포함한 요소 중 두 번째 요소 찾기
print("[DEBUG] handle_category_action: Locating category container element...")
category_locator = "div#productMainContentContainerId div.ant-select.ant-select-outlined.css-1li46mu.ant-select-single.ant-select-show-arrow >> nth=1"
try:
await self.page.wait_for_selector(category_locator, timeout=5000)
except Exception as e:
print(f"[ERROR] handle_category_action: Timed out waiting for category container element. Error: {e}")
QMessageBox.information(None, "결과", f"카테고리 컨테이너 요소를 찾는 데 실패했습니다: {e}")
return
category_element = self.page.locator(category_locator)
count = await category_element.count()
print(f"[DEBUG] handle_category_action: Number of elements found with locator '{category_locator}': {count}")
if count == 0:
print(f"[ERROR] handle_category_action: Category container element not found using locator '{category_locator}'!")
QMessageBox.information(None, "결과", "카테고리 컨테이너 요소를 찾을 수 없습니다.")
return
# "인증필요"와 카테고리 텍스트 추출
print("[DEBUG] handle_category_action: Extracting '인증필요' and category text...")
certification_text = ""
category_text = ""
try:
cert_needed_locator = category_element.locator("div.ant-col.css-1li46mu:nth-child(1)")
certification_text = await cert_needed_locator.inner_text()
print(f"[DEBUG] handle_category_action: Certification text found - '{certification_text}'")
if "인증필요" in certification_text:
# 인증필요가 있는 경우 두 번째 요소가 카테고리 텍스트
category_text_locator = category_element.locator("div.ant-col.css-1li46mu:nth-child(2)")
category_text = await category_text_locator.inner_text()
else:
# 인증필요가 없는 경우 첫 번째 요소가 카테고리 텍스트
category_text = certification_text
certification_text = "" # 인증필요가 없으므로 초기화
except Exception:
# 인증필요가 없는 경우 첫 번째 요소가 카테고리 텍스트
print("[DEBUG] handle_category_action: Certification text not found. Assuming first element is category text.")
category_text_locator = category_element.locator("div.ant-col.css-1li46mu:nth-child(1)")
category_text = await category_text_locator.inner_text()
full_text = f"{certification_text} {category_text}".strip()
print(f"[DEBUG] handle_category_action: Full text - '{full_text}'")
QMessageBox.information(None, "검색 결과", f"카테고리 텍스트: {full_text}")
# 카테고리 텍스트에 '인증'이라는 단어가 포함되어 있는지 검사
if "인증" in full_text:
print("[INFO] 인증 필요 카테고리입니다. 인증 절차를 진행합니다.")
# 인증이 필요한 경우 수행할 작업
await self.perform_certification_action()
else:
print("[INFO] 인증이 필요하지 않은 카테고리입니다.")
# 인증이 필요하지 않은 경우 수행할 작업
await self.perform_standard_action()
async def perform_certification_action(self):
# 인증 절차를 진행하는 코드 작성
print("[DEBUG] perform_certification_action: Starting certification process...")
# 예시: 특정 버튼 클릭하기
await self.page.click("button:has-text('인증 시작')")
print("[INFO] perform_certification_action: Certification process completed.")
async def perform_standard_action(self):
# 인증이 필요하지 않은 경우의 일반적인 작업 코드 작성
print("[DEBUG] perform_standard_action: Performing standard action...")
# 예시: 다음 단계로 이동
await self.page.click("button:has-text('다음 단계')")
print("[INFO] perform_standard_action: Standard action completed.")
async def run_playwright():
print("[DEBUG] run_playwright: Launching Playwright...")
playwright = await async_playwright().start()
browser = await playwright.chromium.launch(headless=False)
page = await browser.new_page()
print("[DEBUG] run_playwright: Navigating to https://www.percenty.co.kr...")
await page.goto("https://www.percenty.co.kr") # 실제 페이지 URL로 변경하세요
print("[INFO] run_playwright: Page loaded successfully.")
return page, browser, playwright
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Playwright 테스트")
self.setGeometry(100, 100, 400, 300)
self.page = None
self.browser = None
self.playwright = None
# 버튼 생성
self.init_button = QPushButton("Playwright 실행")
self.init_button.clicked.connect(self.run_playwright_button)
self.check_button = QPushButton("요소 검사 및 메시지 출력")
self.check_button.clicked.connect(self.check_category_button)
self.check_button.setEnabled(False)
# 레이아웃 설정
layout = QVBoxLayout()
layout.addWidget(self.init_button)
layout.addWidget(self.check_button)
self.setLayout(layout)
def run_playwright_button(self):
print("[DEBUG] run_playwright_button: Playwright 실행 버튼 클릭됨.")
asyncio.create_task(self.init_playwright())
async def init_playwright(self):
print("[DEBUG] init_playwright: Initializing Playwright...")
self.page, self.browser, self.playwright = await run_playwright()
self.check_button.setEnabled(True)
print("[INFO] init_playwright: Playwright initialized and check button enabled.")
def check_category_button(self):
if self.page:
print("[DEBUG] check_category_button: 요소 검사 버튼 클릭됨.")
asyncio.create_task(self.handle_category_action())
async def handle_category_action(self):
print("[DEBUG] handle_category_action: Handling category action...")
handler = CategoryHandler(self.page)
await handler.handle_category_action()
print("[INFO] handle_category_action: Category check completed.")
if __name__ == "__main__":
print("[DEBUG] Main: Starting application...")
app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
window = MainWindow()
window.show()
with loop:
sys.exit(loop.run_forever())

164
title.py Normal file
View File

@ -0,0 +1,164 @@
class TitleHandler:
"""
TitleHandler 클래스는 상품명과 카테고리 관련 정보를 처리하는 역할을 합니다.
다양한 선택자를 사용하여 페이지에서 상품명, 추천 단어, 카테고리 등을 수집하고 입력하는 기능을 제공합니다.
Attributes:
page (Page): Playwright의 페이지 객체로, 브라우저와의 상호작용을 담당합니다.
logger (Logger): 로깅을 위한 Logger 객체입니다.
"""
def __init__(self, page, logger, locator_manager):
self.page = page
self.logger = logger
self.locator_manager = locator_manager
# 선택자 로드
self.product_name_input_locator = self.locator_manager.get_locator('TitleLocators', 'product_name_input_locator')
self.suggestion_input_locator = self.locator_manager.get_locator('TitleLocators', 'suggestion_input_locator')
self.search_button_locator = self.locator_manager.get_locator('TitleLocators', 'search_button_locator')
self.original_name_locator = self.locator_manager.get_locator('TitleLocators', 'original_name_locator')
self.delete_warning_button_locator = self.locator_manager.get_locator('TitleLocators', 'delete_warning_button_locator')
self.category_suggestion_button_locator = self.locator_manager.get_locator('TitleLocators', 'category_suggestion_button_locator')
self.main_category_locator_with_cp = self.locator_manager.get_locator('TitleLocators', 'category_main_selector_with_cp')
self.main_category_locator_with_ss = self.locator_manager.get_locator('TitleLocators', 'category_main_selector_with_ss')
self.main_category_locator_with_esm = self.locator_manager.get_locator('TitleLocators', 'category_main_selector_with_esm')
self.certified_text_locator = self.locator_manager.get_locator('TitleLocators', 'certified_text_locator')
self.category_text_locator = self.locator_manager.get_locator('TitleLocators', 'category_text_locator')
self.category_text_locator_certified = self.locator_manager.get_locator('TitleLocators', 'category_text_locator_certified')
async def get_product_name(self) -> str:
"""
노출상품명 입력칸에서 상품명을 가져오는 메서드입니다.
Returns:
str: 상품명 텍스트
"""
try:
self.logger.debug("노출상품명 입력칸에서 상품명을 가져오는 중입니다.")
product_name_element = await self.page.query_selector(self.product_name_input_locator)
product_name = await product_name_element.get_attribute('value') if product_name_element else ""
self.logger.debug(f"상품명: {product_name}")
return product_name
except Exception as e:
self.logger.error(f"상품명 가져오기 중 오류 발생: {e}", exc_info=True)
return ""
async def enter_product_name_suggestion(self, suggestion: str):
"""
상품명 추천단어를 입력칸에 입력하는 메서드입니다.
Args:
suggestion (str): 입력할 추천 단어
"""
try:
self.logger.debug(f"추천 단어를 상품명 추천 입력칸에 입력 중: {suggestion}")
suggestion_input_element = await self.page.query_selector(self.suggestion_input_locator)
if suggestion_input_element:
await suggestion_input_element.fill(suggestion)
self.logger.debug(f"추천 단어 '{suggestion}' 입력 완료.")
else:
self.logger.error("추천 입력칸 요소를 찾을 수 없습니다.")
except Exception as e:
self.logger.error(f"추천 입력 단어 입력 중 오류 발생: {e}", exc_info=True)
async def click_product_name_search_button(self):
"""
상품명 추천단어 입력칸의 검색 버튼을 클릭하는 메서드입니다.
"""
try:
self.logger.debug("상품명 추천단어 검색 버튼 클릭 중.")
search_button_element = await self.page.query_selector(self.search_button_locator)
if search_button_element:
await search_button_element.click()
self.logger.debug("검색 버튼 클릭 완료.")
else:
self.logger.error("검색 버튼 요소를 찾을 수 없습니다.")
except Exception as e:
self.logger.error(f"상품명 추천 검색 버튼 클릭 중 오류 발생: {e}", exc_info=True)
async def get_original_product_name(self) -> str:
"""
원본 상품명을 가져오는 메서드입니다.
Returns:
str: 원본 상품명 텍스트
"""
try:
self.logger.debug("원본 상품명을 가져오는 중입니다.")
original_name_element = await self.page.query_selector(self.original_name_locator)
original_name = await original_name_element.inner_text() if original_name_element else ""
self.logger.debug(f"원본 상품명: {original_name}")
return original_name
except Exception as e:
self.logger.error(f"원본 상품명 가져오기 중 오류 발생: {e}", exc_info=True)
return ""
async def delete_warning_word_in_product_name(self):
"""
상품명에서 경고 단어를 삭제하는 버튼을 클릭하는 메서드입니다.
"""
try:
self.logger.debug("경고 단어 삭제 버튼 클릭 중입니다.")
delete_button_element = await self.page.query_selector(self.delete_warning_button_locator)
if delete_button_element:
await delete_button_element.click()
self.logger.debug("경고 단어 삭제 버튼 클릭 완료.")
else:
self.logger.error("경고 단어 삭제 버튼 요소를 찾을 수 없습니다.")
except Exception as e:
self.logger.error(f"경고 단어 삭제 버튼 클릭 중 오류 발생: {e}", exc_info=True)
async def click_category_suggestion_button(self):
"""
카테고리 추천받기 버튼을 클릭하는 메서드입니다.
"""
try:
self.logger.debug("카테고리 추천받기 버튼 클릭 중입니다.")
category_suggestion_button_element = await self.page.query_selector(self.category_suggestion_button_locator)
if category_suggestion_button_element:
await category_suggestion_button_element.click()
self.logger.debug("카테고리 추천받기 버튼 클릭 완료.")
else:
self.logger.error("카테고리 추천받기 버튼 요소를 찾을 수 없습니다.")
except Exception as e:
self.logger.error(f"카테고리 추천받기 버튼 클릭 중 오류 발생: {e}", exc_info=True)
async def get_category(self, market) -> str:
"""
카테고리를 가져오는 메서드로 인증 필요 여부에 따라 카테고리 선택자를 다르게 처리합니다.
Returns:
str: 카테고리 텍스트
"""
try:
self.logger.debug("카테고리 텍스트를 가져오는 중입니다.")
if market == 'ss':
main_category_element = await self.page.query_selector(self.main_category_locator_with_ss)
self.logger.debug(f"선택 마켓 : 스마트스토어")
elif market == 'cp':
main_category_element = await self.page.query_selector(self.main_category_locator_with_cp)
self.logger.debug(f"선택 마켓 : 쿠팡")
elif market == 'esm':
main_category_element = await self.page.query_selector(self.main_category_locator_with_esm)
self.logger.debug(f"선택 마켓 : ESM")
if not main_category_element:
self.logger.error("카테고리 메인 선택자를 찾을 수 없습니다.")
return ""
certified_text_element = await main_category_element.query_selector(self.certified_text_locator)
if certified_text_element:
certified_text = await certified_text_element.inner_text()
if "인증" in certified_text:
category_text_element = await main_category_element.query_selector(self.category_text_locator_certified)
self.logger.debug(f"카테고리 인증 필요 발생: {category_text}")
else:
category_text_element = certified_text_element
category_text = await category_text_element.inner_text() if category_text_element else ""
self.logger.debug(f"카테고리 텍스트: {category_text}")
return category_text
else:
self.logger.error("카테고리 인증 요소를 찾을 수 없습니다.")
return ""
except Exception as e:
self.logger.error(f"카테고리 텍스트 가져오기 중 오류 발생: {e}", exc_info=True)
return ""

47
title.txt Normal file
View File

@ -0,0 +1,47 @@
상품명 / 카테고리
상품명 추천단어 입력칸의 요소
<input placeholder="직접 검색하기" maxlength="100" class="ant-input css-1li46mu" type="text" value="">
상품명 추천단어 입력칸의 css
#productMainContentContainerId > div > div.sc-aNeao.tNLFa > div:nth-child(2) > div:nth-child(2) > div > span > span > span.ant-input-affix-wrapper.css-1li46mu.ant-input-outlined > input
css path
"div#productMainContentContainerId div:nth-child(2) > div:nth-child(2) > div > span > span > span.ant-input-affix-wrapper.css-1li46mu.ant-input-outlined > input"
xpath
//*[@id="productMainContentContainerId"]/div/div[1]/div[2]/div[2]/div/span/span/span[1]/input
상품명 추천단어 입력 검색버튼 요소
<button type="button" class="ant-btn css-1li46mu ant-btn-default ant-btn-icon-only ant-input-search-button"><span class="ant-btn-icon"><span role="img" aria-label="search" class="anticon anticon-search"><svg viewBox="64 64 896 896" focusable="false" data-icon="search" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"></path></svg></span></span></button>
상품명 추천단어 입력 검색버튼 css
#productMainContentContainerId > div > div.sc-aNeao.tNLFa > div:nth-child(2) > div:nth-child(2) > div > span > span > span.ant-input-group-addon > button
상품명 추천단어 입력 검색버튼 css path
"div#productMainContentContainerId div:nth-child(2) > div:nth-child(2) > div > span > span > span.ant-input-group-addon > button[type=\"button\"]"
상품명 추천단어 입력 검색버튼 xpath
//*[@id="productMainContentContainerId"]/div/div[1]/div[2]/div[2]/div/span/span/span[2]/button
카테고리 추천받기 버튼 요소
<button type="button" class="ant-btn css-1li46mu ant-btn-primary ant-btn-background-ghost"><span>카테고리 추천 받기</span></button>
카테고리 추천받기 버튼 css
#productMainContentContainerId > div > div.sc-aNeao.tNLFa > div:nth-child(5) > div:nth-child(2) > button
카테고리 추천받기 버튼 css path
"div#productMainContentContainerId div:nth-child(2) > button[type=\"button\"]"
카테고리 추천받기 버튼 xpath
//*[@id="productMainContentContainerId"]/div/div[1]/div[5]/div[2]/button
노출상품명 입력칸
//*[@id="productMainContentContainerId"]/div/div[1]/div[5]/div[1]/span/input
"div#productMainContentContainerId div:nth-child(5) > div:nth-child(1) > span > input"
<input class="ant-input css-1li46mu" type="text" value="Huali 공동 브랜드 Jade Gui Dog 여자 신발 2024 봄 가을 한정판 만화 스타일 아동 스포츠 편안한 운동화">
원본상품명
//*[@id="productMainContentContainerId"]/div/div[1]/div[6]/div[1]/div/span
"div#productMainContentContainerId div.sc-aNeao.tNLFa > div.ant-flex.css-1li46mu.ant-flex-align-stretch.ant-flex-vertical > div:nth-child(1) > div > span"
<span class="sc-fremEr TIBrr Body3Regular14 CharacterSecondary45">回力联名玉桂狗女童鞋2024春秋季限量卡通款小孩儿童运动舒适板鞋</span>
상품명의 경고단어 삭제 버튼
//*[@id="productMainContentContainerId"]/div/div[1]/div[6]/div[3]/div[2]/div/button
"div#productMainContentContainerId div:nth-child(2) > div > button[type=\"button\"]"
<button type="button" class="ant-btn css-1li46mu ant-btn-text ant-btn-sm"><span>삭제하기</span></button>