from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.keys import Keys import time from edit.action_elements import click_element, return_element from ai.deepl import trans from ai.compare import find_most_similar_image_by_one import re import logging # 로거 인스턴스 가져오기 logger = logging.getLogger('default_logger') def modify_option_page(driver, original_img): # 옵션 탭으로 이동 logger.debug("옵션탭으로 이동") option_tab_XPATH = "//div[@id='rc-tabs-0-tab-1']" click_element(driver, 'XPATH', option_tab_XPATH, 10, 'js') logger.debug("옵션탭으로 이동 완료") logger.debug("페이지 로딩 대기") time.sleep(2) # 페이지 로딩 대기. # 옵션타입 갯수 체크 # 옵션타입2가 존재할 경우 옵션타입2의 옵션갯수에 따라 (1개면 작업하지 않고, 2개이상일 경우 작업) # 일단 보류 logger.debug("옵션타입 체크") option_type_1_xpath="//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div[1]/div/div/div/span/div/div/span" # 옵션타입이 1개일 경우 옵션타입2를 가져올 경우 오류발생할 것. 적절한 예외처리필요 option_type_2_xpath="//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div[2]/div/div/div/span/div/div/span" option_type_3_xpath="//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div[3]/div/div/div/span/div/div/span" option_type1 = return_element(driver, 'XPATH', option_type_1_xpath, 10) logger.debug(f"옵션 타입 : {option_type1.text}") # 현재 전체 옵션갯수 가져오기 # 가져온 옵션갯수에 따라, 2개이하면 수정하지 않고, 3개이상일 경우 이미지 유사도에 따라 선택 logger.debug("옵션갯수 가져오기") option_num_xpath="//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div/div/div/div[2]/div/div/div[5]/div/div/label/span[2]" option_num_element = return_element(driver, 'XPATH', option_num_xpath, 10) option_number = int(re.search(r'\d+', option_num_element.text).group()) # 가격 낮은 순으로 정렬 logger.debug("가격 낮은 순으로 정렬") low_price_order_xpath="//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div/div/div/div[2]/div/div/div[5]/div/div[3]/button/span" click_element(driver, 'XPATH', low_price_order_xpath, 10, 'js') # 이미지 비교 logger.debug("이미지 비교로 유사도 판단 후 옵션 선택") # 옵션 이미지 URL을 저장할 리스트 초기화 option_images_urls = [] selected_option_indexes = [] for i in range(1, option_number + 1): # 옵션 이미지의 XPath 경로 동적 생성 opt_img_xpath = f"//li[{i}]/div/div/div/div[2]/div/img" try: # 해당 XPath를 이용하여 웹 요소 찾기 opt_img_element = driver.find_element(By.XPATH, opt_img_xpath) except Exception as e: logger.debug(f"옵션 이미지 xpath를 찾을 수 없음 {e}") opt_img_element = None # 옵션이미지가 없을 경우 처리 if not opt_img_element: logger.debug(f"{i}번째 옵션이미지가 없음") # 아래의 2가지 상황에 맞추어 추가코드 필요 # 1. 전체 옵션의 이미지가 없는 경우 처리 # 2. 일부 옵션만 이미지가 없는 경우 처리 else: # 웹 요소의 src 속성에서 이미지 URL 추출 img_url = opt_img_element.get_attribute('src') # 추출한 이미지 URL을 리스트에 추가 option_images_urls.append(img_url) # 유사도 비교로 적합한 이미지를 가진 옵션번호 저장 similarity = find_most_similar_image_by_one(original_img, img_url) if similarity > 0.6: selected_option_indexes.append(i) logger.debug(f"옵션번호 {i}번이 이미지 유사도 {similarity}로 선택되었습니다.") # # 선택된 옵션인덱스로 실제 옵션 체크 # # 옵션타입1의 옵션전체 선택&해제 버튼 xpath=(//input[@type='checkbox'])[22] # # 옵션타입1의 1번 옵션 선택&해제 버튼 xpath=(//input[@type='checkbox'])[23] # # 옵션타입1의 2번 옵션 선택&해제 버튼 xpath=(//input[@type='checkbox'])[24] # # 주의점은 해당 옵션을 체크해제할 경우 이미지 주소를 가져올 수 없으므로, 체크 해제 전 모든 옵션에 해당하는 이미지 주소를 가져올 것. # # 만약 이미지 주소가 none이거나 없으면 이미지 비교를 하지말고 옵션명으로 비교할 것. logger.debug("옵션갯수 다시 가져오기") selected_option_num_xpath="//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div/div/div/div[2]/div/div/div[5]/div/div/label/span[2]" selected_option_num_element = return_element(driver, 'XPATH', selected_option_num_xpath, 10) selected_options_num = int(re.search(r'\d+', selected_option_num_element.text).group()) logger.debug("선택된 옵션 인덱스로 옵션박스 체크 실행") all_checkbox_xpath=("//input[@type='checkbox'])[22]") # 전체옵션 체크해제를 위한 준비 # all_checkbox_xpath="//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div/div/div/div[2]/div/div/div[5]/div/div/label/span/input" # selected_options_num = len(selected_option_indexes) selected_options_num = selected_option_indexes max_options_num = min(7, selected_options_num) if option_number > 2: # 선택가능한 옵션갯수가 2개이하일 경우 모든옵션을 선택하기 위함. logger.debug("전체옵션 선택해제 실행") click_element(driver, 'XPATH', all_checkbox_xpath, 10, 'js') for i in range(1, max_options_num + 1): # 최대 선택가능한 옵션은 아무리 많아도 (7개 또는 selected_options_num 중 작은 숫자) 까지만 selected_option_number = selected_option_indexes[i] option_checkbox_xpath = f"(//input[@type='checkbox'])[{22 + selected_option_number}]" logger.debug(f"{i}번째 옵션 체크") click_element(driver,'XPATH', option_checkbox_xpath, 10, 'js') logger.debug("선택된 옵션명 DeepL로 번역 후 새로운 옵션명 입력") logger.debug("선택된 옵션갯수 새로 가져오기") selected_option_num_element = return_element(driver, 'XPATH', option_num_xpath, 10) selected_option_number = int(re.search(r'\d+', selected_option_num_element).group()) for i in range(1, selected_option_number + 1): # 원본 옵션이름의 XPath 경로 동적 생성으로 원본옵션명을 번역 생성 ori_optionName_xpath = f"/html/body/div[28]/div/div[3]/div/div[2]/div[1]/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[6]/div[1]/div/div/ul/li[{i}]/div/div[1]/div/div[3]/div[3]/span" ori_optionName_element = driver.find_element(By.XPATH, ori_optionName_xpath) ori_optionName = ori_optionName_element.get_attribute('text') trans_option_name = trans(ori_optionName) # 옵션이름입력칸의 XPath 경로 동적 생성으로 번역된 옵션명을 새로 입력 optionName_input_xpath = f"//li[{i}]/div/div/div/div[3]/div[2]/div/span/input" optionName_input_element = driver.find_element(By.XPATH, optionName_input_xpath) optionName_input_element.setText(trans_option_name) logger.debug("옵션선택과 옵션명 수정 완료 후 옵션명 정리") # A-Z # xpath=//span[contains(.,'A-Z')] # xpath=//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div/div/div/div[2]/div/div/div[4]/div/div/div/div/button/span # 1-99 # xpath=//span[contains(.,'1-99')] # xpath=//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div/div/div/div[2]/div/div/div[4]/div/div/div/div[2]/button/span # 빈칸제거 # xpath=//span[contains(.,'빈칸 제거')] # xpath=//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div/div/div/div[2]/div/div/div[4]/div/div/div/div[3]/button/span