옵션 번역 수정

This commit is contained in:
9700X_PC 2024-11-06 22:47:42 +09:00
parent fa39c762a2
commit bf240af991
4 changed files with 57 additions and 49 deletions

View File

@ -34,20 +34,25 @@ price_selector_template = '//*[@id="productMainContentContainerId"]/div[1]/div[2
# 옵션 상자
; option_box_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc'
option_box_selector = '//*[@id="productMainContentContainerId"]/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{index}]/div/div[1]/div/div[2]/div'
; option_box_selector = '//*[@id="productMainContentContainerId"]/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{index}]/div/div[1]/div/div[2]/div'
option_box_selector = 'div#productMainContentContainerId li > div > div:nth-child(1) > div > div:nth-child(2) > div'
; excluded_option_marker = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) > .sc-dfauwV.bXsMpn'
excluded_option_marker = '.bXsMpn.sc-dfauwV'
; delete_button_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) span:has-text("삭제")'
; delete_button_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) div.sc-igZIGL.kQDmyq'
; delete_button_selector = '.kQDmyq.sc-igZIGL'
; delete_button_selector_template = '//*[@id="productMainContentContainerId"]/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{index}]/div/div[1]/div/div[2]/div/div[2]/div[1]/div/span'
delete_button_selector_template = 'div#productMainContentContainerId li:nth-child({index}) > div > div:nth-child(1) > div > div:nth-child(2) > div > div.ant-row.ant-row-no-wrap.ant-row-space-between.ant-row-middle.css-1li46mu > div:nth-child(1) > div > span'
delete_button_selector_template = '//*[@id="productMainContentContainerId"]/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{index}]/div/div[1]/div/div[2]/div/div[2]/div[1]/div/span'
fallback1_delete_button_selector_template = 'div#productMainContentContainerId li:nth-child({index}) > div > div:nth-child(1) > div > div:nth-child(2) > div > div.ant-row.ant-row-no-wrap.ant-row-space-between.ant-row-middle.css-1li46mu > div:nth-child(1) > div > span'
confirm_delete_button_selector = '.ant-modal.css-1li46mu.ant-modal-confirm.ant-modal-confirm-confirm button:has-text("삭제")'
delete_dialog_selector = 'div.sc-ddjGPC.jbwEYW'
confirm_delete_button_selector = 'button.ant-btn-primary.ant-btn-dangerous:has-text('삭제')'
; confirm_delete_button_selector = '.ant-modal.css-1li46mu.ant-modal-confirm.ant-modal-confirm-confirm button:has-text("삭제")'
; confirm_delete_button_selector = 'xpath=/html/body/div[8]/div/div[2]/div/div[2]/div/div/div/div[2]/button[2]'
add_button_selector2 = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) > .sc-dRGYJT.hmQUGb'
add_button_selector = '//*[@id="productMainContentContainerId"]/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{index}]/div/div[1]/div/div[2]/div/div/img'
add_button_selector = 'div#productMainContentContainerId li:nth-child({index}) > div > div:nth-child(1) > div > div:nth-child(2) > div > div > img'
; add_button_selector = 'div.hmQUGb.sc-dRGYJT'
; add_button_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) > .sc-krITIZ.ckztYT'
; file_upload_button_selector = '.ant-modal-content button:has-text("클릭 or 드레그로 파일 업로드")'

View File

@ -92,6 +92,7 @@ class LocatorManager:
'excluded_option_marker': self.config.get('OptionLocators', 'excluded_option_marker').strip("'"),
'delete_button_selector_template': self.config.get('OptionLocators', 'delete_button_selector_template').strip("'"),
'fallback1_delete_button_selector_template': self.config.get('OptionLocators', 'fallback1_delete_button_selector_template').strip("'"),
'delete_dialog_selector': self.config.get('OptionLocators', 'delete_dialog_selector').strip("'"),
'confirm_delete_button_selector': self.config.get('OptionLocators', 'confirm_delete_button_selector').strip("'"),
'add_button_selector': self.config.get('OptionLocators', 'add_button_selector').strip("'"),
'file_upload_button_selector': self.config.get('OptionLocators', 'file_upload_button_selector').strip("'"),

View File

@ -36,6 +36,7 @@ class OptionHandler:
self.excluded_option_marker = self.locator_manager.get_locator('OptionLocators', 'excluded_option_marker')
self.delete_button_selector_template = self.locator_manager.get_locator('OptionLocators', 'delete_button_selector_template')
self.fallback1_delete_button_selector_template = self.locator_manager.get_locator('OptionLocators', 'fallback1_delete_button_selector_template')
self.delete_dialog_selector = self.locator_manager.get_locator('OptionLocators', 'delete_dialog_selector')
self.confirm_delete_button_selector = self.locator_manager.get_locator('OptionLocators', 'confirm_delete_button_selector')
self.add_button_selector = self.locator_manager.get_locator('OptionLocators', 'add_button_selector')
self.file_upload_button_selector = self.locator_manager.get_locator('OptionLocators', 'file_upload_button_selector')
@ -268,6 +269,8 @@ class OptionHandler:
if toggle_states['optionAutoSelect']:
self.logger.debug(f"옵션 필터링 및 조정 : {toggle_states['optionAutoSelect']}")
await self.filter_and_adjust_options(max_option_count)
# 가격 낮은 순 재정렬 클릭
await self.low_order_click()
# 6. 선택된 옵션정보 재수집
if self.is_percenty_success:
@ -629,6 +632,7 @@ class OptionHandler:
try:
selected_count = 0 # 현재까지 선택된 옵션 수
self.logger.info(f"최대 선택 가능 옵션수 설정값 : {max_option_count}")
for i, name in enumerate(self.option_info['original_names'].values()):
# 최대 옵션 수에 도달하면 더 이상 선택하지 않음
if max_option_count > 0 and selected_count >= max_option_count:
@ -716,9 +720,9 @@ class OptionHandler:
try:
# 모든 옵션 상자 요소 가져오기
# option_boxes = await self.page.query_selector_all(self.option_box_selector)
option_boxes = await self.page.query_selector_all(self.option_box_selector)
option_boxes = await self.page.query_selector_all("div#productMainContentContainerId li > div > div:nth-child(1) > div > div:nth-child(2) > div")
# option_boxes = await self.page.query_selector_all("div#productMainContentContainerId li > div > div:nth-child(1) > div > div:nth-child(2) > div")
# option_image_element = await self.page.locator("xpath=//*[@id='productMainContentContainerId']/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[1]/div/div[1]/div/div[2]/div/img").element_handle()
@ -732,11 +736,18 @@ class OptionHandler:
# 선택자에서 인덱스를 반영해 동적 선택자를 생성
add_button_selector = self.add_button_selector.format(index=index)
# 옵션 박스 내부의 텍스트 확인하여 "제외된 옵션" 포함 여부 검사
option_text_content = await option_box.inner_text()
if "제외된 옵션" in option_text_content:
self.logger.debug(f"{index}번째 옵션은 제외된 옵션입니다. 번역을 생략합니다.")
continue # 제외된 옵션이므로 다음 옵션으로 이동
# 옵션 이미지가 존재하는지 확인
option_image = await option_box.query_selector("img")
if option_image is None:
self.logger.debug(f"{index}번째 옵션에 이미지가 없습니다. 다음 옵션으로 이동합니다.")
continue
option_image_url = await option_image.get_attribute("src")
self.logger.debug(f"{index}번째 옵션 이미지 URL: {option_image_url}")
@ -765,34 +776,47 @@ class OptionHandler:
try:
# 기본 선택자로 삭제 버튼 찾기
# delete_button = option_box.query_selector(self.delete_button_selector)
delete_button = self.page.locator(f'{self.delete_button_selector_template.format(index=index)}')
await delete_button.wait_for(state="attached", timeout=5000) # 타임아웃 설정
if not await delete_button.is_visible():
# fallback으로 재시도
delete_button = self.page.locator(f'xpath={self.fallback1_delete_button_selector_template.format(index=index)}')
delete_button.set_timeout(5000)
await delete_button.wait_for(state="attached", timeout=5000)
if await delete_button.is_visible():
await delete_button.click()
self.logger.debug(f"{index}번째 옵션의 삭제 버튼 클릭")
# 다이알로그 확인 후 삭제 버튼 클릭
try:
self.logger.debug(f"{index}번째 옵션의 삭제 다이알로그 확인 중...")
dialog = await self.page.wait_for_selector(self.delete_dialog_selector, timeout=5000) # 다이알로그 클래스 확인
if dialog:
self.logger.debug(f"{index}번째 옵션의 삭제 다이알로그 확인됨")
# 삭제 확인 버튼 찾기
confirm_delete_button = await dialog.query_selector(self.confirm_delete_button_selector)
if confirm_delete_button:
await confirm_delete_button.click()
self.logger.debug(f"{index}번째 옵션의 삭제 확인 버튼 클릭됨")
else:
self.logger.error(f"{index}번째 옵션의 삭제 확인 버튼이 보이지 않습니다.")
else:
self.logger.error(f"{index}번째 옵션의 삭제 다이알로그가 나타나지 않았습니다.")
except Exception as e:
self.logger.error(f"{index}번째 옵션의 삭제 다이알로그를 찾는 중 오류 발생: {e}", exc_info=True)
except Exception as e:
self.logger.error(f"{index}번째 옵션의 삭제 버튼을 찾는 중 오류 발생: {e}", exc_info=True)
if delete_button:
# await delete_button.click()
# self.logger.debug(f"{index}번째 옵션의 이미지 삭제 버튼 클릭")
confirm_delete_button = await self.page.wait_for_selector(self.confirm_delete_button_selector)
self.logger.debug(f"{index}번째 옵션의 이미지 삭제확인 버튼 가져오기")
if confirm_delete_button:
await confirm_delete_button.click()
self.logger.debug(f"{index}번째 옵션의 기존 이미지가 삭제되었습니다.")
try:
# '+ 버튼' 클릭 후 파일 업로드
self.logger.debug(f"{index}번째 옵션의 이미지추가 버튼 가져오기")
add_button = self.page.locator(add_button_selector)
add_button = await self.page.query_selector(add_button_selector)
if add_button:
await add_button.click()
@ -812,6 +836,9 @@ class OptionHandler:
self.logger.debug(f"{index}번째 옵션에 이미지가 업로드되었습니다.")
else:
self.logger.error(f"{index}번째 옵션의 파일 입력 요소를 찾을 수 없습니다.")
except Exception as e:
self.logger.error(f"{index}번째 옵션의 이미지를 추가하는 중 오류 발생: {e}", exc_info=True)
except Exception as e:
self.logger.error(f"{index}번째 옵션 이미지 번역 중 오류 발생: {e}", exc_info=True)

View File

@ -9,7 +9,6 @@ import KO_EN
import pyperclip # 클립보드 데이터를 확인하기 위한 라이브러리
from PIL import ImageGrab
import re
# import psutil
class WhaleTranslator:
def __init__(self, app, logger, secret_mode=True, vd_mode=False, pixel_check_interval=0.1, timeout=10, color_tolerance=20):
@ -299,7 +298,7 @@ class WhaleTranslator:
self.logger.debug(f"페이지 로딩 완료 후 웨일 창의 가운데로 마우스 커서 이동")
# pyautogui.moveTo(960,580) # 마우스 센터로 이동
self.move_mouse_to_center()
time.sleep(1) # 마우스 이동 후 대기
time.sleep(0.4) # 마우스 이동 후 대기
# original_color = self.get_mouse_position_color() # 현재 색상 가져오기
# self.colors['before'] = original_color
@ -491,32 +490,7 @@ class WhaleTranslator:
time.sleep(1) # 페이지 로딩 대기
def close_whale_window_if_exists(self):
"""윈도우 핸들을 사용하여 웨일 창을 닫음"""
try:
if not self.whale_hwnd:
self.logger.debug("웨일 창 핸들이 설정되지 않았습니다.")
return
# 핸들이 유효한지 확인
if win32gui.IsWindow(self.whale_hwnd):
self.logger.debug(f"웨일 창 핸들을 찾았습니다: {self.whale_hwnd}. 종료 중...")
win32gui.PostMessage(self.whale_hwnd, win32con.WM_CLOSE, 0, 0) # 창을 종료하는 메시지 전송
time.sleep(1) # 잠시 대기하여 창 종료 확인
if not win32gui.IsWindow(self.whale_hwnd):
self.logger.debug("웨일 창이 성공적으로 종료되었습니다.")
else:
self.logger.debug("웨일 창 종료에 실패했습니다.")
else:
self.logger.debug("유효하지 않은 웨일 창 핸들입니다.")
except Exception as e:
self.logger.error(f"핸들을 사용한 웨일 창 종료 중 오류 발생: {e}", exc_info=True)
def close_whale_window_if_exists_ori(self):
"""웨일 브라우저 창을 프로세스 ID(pid)로 찾아 종료"""
try:
if not self.whale_pid:
@ -816,7 +790,8 @@ class WhaleTranslator:
max_retries (int): 최대 재시도 횟수.
"""
retry_count = 0
self.move_mouse_to_center()
while retry_count < max_retries:
self.logger.debug(f"마우스 오른쪽 클릭 시도 #{retry_count + 1}")
pyautogui.rightClick()