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.common.exceptions import TimeoutException import time, re, math import json # from utils import log from database import is_product_processed, mark_product_processed from edit.detail1 import modify_detail_page from edit.tag import edit_tag from edit.options import modify_option_page from edit.price import modify_price_page from edit.title import modify_product_title from edit.action_elements import click_element, return_element import logging from edit.product_info import ProductInfo # 로거 인스턴스 가져오기 logger = logging.getLogger('default_logger') def set_product_info(): ''' 상품 정보 product_info 딕셔너리 초기화 ''' product_info = { 'id': None, #상품 아이디 'keyword_title': None, # 키워드 상품명 'product_title': None, # 수정 상품명 'trans_title': None, # 번역 상품명 'tao_high_price': None, # 타오바오의 최고 가격 'tao_low_price': None, # 타오바오의 최저 가격 'option_high_price': None, # 선택된 옵션 최고 가격 'option_low_price': None, # 선택된 옵션 최저 가격 'main_image_url': None, # 상품 메인썸네일 이미지 URL 리스트 'image_urls': [], # 상품 옵션 이미지 URL 리스트 'detail_image_urls': [], # 상품 상세페이지 이미지 URL 리스트 'thumb_image_urls': [], # 상품 썸네일 이미지 URL 리스트 'naver_code': None, # 네이버 카테고리 코드 'naver_avg_price': None, # 네이버 평균가격 'weight': None, # 상품 무게 'w_delv_fee': None, # 상품 무게배송비 'plus_fee': None, # 더하기마진 'return_fee': None, # 반품비 'init_delv_fee': None, # 초기반품비 'exchange_fee': None, # 교환배송비 } return product_info def load_json_naver_codes(filename): codes = [] with open(filename, "r", encoding='utf-8') as file: for line in file: try: item = json.loads(line) codes.append(item) except json.JSONDecodeError as e: logger.error(f"Error decoding JSON: {e}") return codes def wait_for_javascript(driver, timeout=20): try: WebDriverWait(driver, timeout).until(lambda d: d.execute_script('return document.readyState') == 'complete') except TimeoutException: logger.debug("페이지 로딩 실패: 시간 초과") def modify_products(driver, gemini, mongo_config, set_num_modify): # product_info = set_product_info() # 상품정보리스트 생성 # MongoDB에 연결 client = mongo_config.client # self.login_db = self.mongoConfig.get_db() # mongo_config 인스턴스를 통해 데이터베이스 객체를 가져옴 db = client['taobao_project'] delv_collection = db['delv_fee'] set_num_modify = int(set_num_modify) # 한 번만 호출하여 메모리에 로드 json_naver_codes = load_json_naver_codes("Percenty_SS_code.json") # 총 상품 수 확인을 위해 모든 자바스크립트가 로드 될때까지 기다리기 logger.debug("모든 JS 로드 대기") wait_for_javascript(driver) logger.debug("총 상품 수 확인을 위한 JS 로드 완료") # 총 상품 수 확인 try: total_products_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//span[contains(.,'총')]")) ) total_products_text = total_products_element.text total_products = int(''.join(filter(str.isdigit, total_products_text))) logger.debug(f"총 상품수 : {total_products}") total_pages = (total_products + 19) // 20 except Exception as e: logger.debug(f"총 상품 수 확인 중 오류 발생: 요소를 찾을 수 없습니다.{e}") if set_num_modify == 0: pass else: total_products = set_num_modify logger.debug(f"수정 대상 상품수 재설정 : {total_products}") current_page = 1 completed_products = 0 product_infos = [] while current_page <= total_pages: # 현재 페이지의 상품 수 계산 products_on_page = min(20, total_products - completed_products) for i in range(1, products_on_page + 1): # try: logger.debug(f"{current_page}페이지-{i}번 상품 수정시작") product_infos.append(ProductInfo()) # 1번 상품과 나머지 상품들에 대한 XPATH 처리 # 상품ID 복사 try: product_id_element = return_element(driver,"XPATH",f"//div[{i}]/li/div/div/div[2]/div/div/div/div[3]/div[3]/span[2]/span",10) product_id = product_id_element.get_attribute('innerText') product_id_set = f"ID:{product_id}" product_infos[i-1].id = product_id_set logger.debug(f"상품ID : {product_id}") except Exception as e: logger.debug(f"상품ID 복사 중 오류 발생: 요소를 찾을 수 없습니다. : {e}") # 상품ID 처리 여부 판단 if is_product_processed(product_id): logger.debug(f"상품 {product_id}는 이미 처리됨.") # close_button = driver.find_element(By.CSS_SELECTOR, ".anticon-close path") # close_button.click() continue try: p_main_title_xpath = f"//div[{i}]/li/div/div/div[2]/div/div/div[1]/div[1]/span[2]" # p_main_title_xpath = f"//div[{i}]/li/div/div/div[2]/div/div/div/div/span" p_main_title_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, p_main_title_xpath)) ) p_main_title_text = p_main_title_element.text product_infos[i-1].init_title = p_main_title_text logger.debug(f"상품명 확인 : {p_main_title_text}") if p_main_title_text == "수집 오류 발생": logger.debug("수집 오류 발생한 상품은 건너뜁니다.") continue # 다음 상품으로 넘어감 # 여기서부터는 "상품명"이 확인되었거나, 다른 조건에 해당하는 경우 상품 수정 로직을 계속 진행합니다. except Exception as e: logger.debug(f"상품명 확인 중 오류 발생: {e}") continue # 해당 상품을 건너뛰고 다음 상품으로 넘어감 # if i == 1: # xpath_pattern = f"//div[3]/div/span[2]" # # 1번상품 xpath=//div[3]/div/span[2] # # 2번상품 xpath=//div[2]/li/div/div/div[2]/div/div/div/div[3]/div/span[2] # # 3번상품 xpath=//div[3]/li/div/div/div[2]/div/div/div/div[3]/div/span[2] # # 20번상품 xpath=//div[20]/li/div/div/div[2]/div/div/div/div[3]/div/span[2] # else: # # xpath_pattern = f"//div[2]/li[{i}]/div/div/div[2]/div/div/div/div[3]/div/span[2]" # xpath_pattern = f"//div[{i}]/li/div/div/div[2]/div/div/div/div[3]/div/span[2]" try: xpath_pattern = f"//div[{i}]/li/div/div/div[2]/div/div/div[1]/div[3]/div[1]/span[2]" product_tao_price_element = driver.find_element(By.XPATH, xpath_pattern) product_tao_price = product_tao_price_element.text logger.debug(f"product_tao_price : {product_tao_price}") # pattern = r'¥(\d+)~(\d+)' # pattern = r'¥(\d{1,3}(?:,\d{3})*)~(\d{1,3}(?:,\d{3})*)' # pattern = r'¥(\d{1,3}(?:,\d{3})*|\d+\.\d+)~(\d{1,3}(?:,\d{3})*|\d+\.\d+)' # 범위 또는 단일 값을 추출하기 위한 패턴 수정 pattern = r'¥(\d{1,3}(?:,\d{3})*|\d+\.\d+)(?:~(\d{1,3}(?:,\d{3})*|\d+\.\d+))?' match = re.search(pattern, product_tao_price) if match: if match.group(2): # 범위의 두 번째 값이 존재하는 경우 # 쉼표를 제거하고, 첫 번째 값 올림 처리 product_low_cost = math.ceil(float(match.group(1).replace(',', ''))) # 쉼표를 제거하고, 두 번째 값 올림 처리 product_high_cost = math.ceil(float(match.group(2).replace(',', ''))) else: # 단일 값만 존재하는 경우 product_low_cost = math.ceil(float(match.group(1).replace(',', ''))) product_high_cost = product_low_cost # 저가와 고가 모두 같은 값 할당 logger.debug(f"낮은 원가 : {product_low_cost}") logger.debug(f"높은 원가 : {product_high_cost}") else: logger.debug("상품 원가 수집 오류 발생: 요소를 찾을 수 없습니다.") logger.debug("원가를 기본값으로 할당합니다.") product_low_cost = 100 product_high_cost = 100 product_infos[i-1].tao_low_price = product_low_cost product_infos[i-1].tao_high_price = product_high_cost except Exception as e: logger.debug(f"상품 상세 정보 수집 중 오류 발생: {e}") # 상품 이미지 복사 try: product_image_element = return_element(driver,"XPATH",f"//div[{i}]/li/div/div/div[1]/div/div[2]/div/div/img",10) except Exception as e: logger.debug(f"상품 이미지 URL 복사 중 오류 발생: 요소를 찾을 수 없습니다. : {e}") product_image_url = product_image_element.get_attribute('src') product_infos[i-1].main_image_url = product_image_url logger.debug(f"product_image_url : {product_image_url}") # 상품 수정 시작 # try: # product_title_element = WebDriverWait(driver, 10).until( # EC.presence_of_element_located((By.XPATH, (f"//div[{i}]/li/div/div/div[2]/div/div/div/div"))) # # EC.presence_of_element_located((By.CSS_SELECTOR, ".signList > .ant-btn-default > span")) # ) # except Exception as e: # logger.debug(f"상품 수정시작 중 오류 발생: 요소를 찾을 수 없습니다.{e}") # # product_title_element = driver.find_element(By.XPATH, (f"//div[{i}]/li/div/div/div[2]/div/div/div/div")) # driver.execute_script("arguments[0].click();", product_title_element)# 상품 수정 페이지 자바스크립트로 열기 click_to_product_title_for_modify_xpath = f"//div[{i}]/li/div/div/div[2]/div/div/div/div" click_element(driver, 'XPATH', click_to_product_title_for_modify_xpath, 10, 'js') logger.debug("상품 수정 페이지 클릭") time.sleep(2) # # 이미지 주소 복사 # # image_element = driver.find_element(By.XPATH, "//div[@id='productMainContentContainerId']/div/div/div/div/div[2]/div/img") # try: # image_element = WebDriverWait(driver, 10).until( # # EC.presence_of_element_located((By.CSS_SELECTOR, ".sc-gFnajm")) # EC.presence_of_element_located((By.CSS_SELECTOR, ".sc-iaJaUu")) # ) # except Exception as e: # logger.debug(f"상품 이미지 주소 중 오류 발생: 요소를 찾을 수 없습니다. : {e}") # # image_element = driver.find_element(By.CSS_SELECTOR, ".sc-gFnajm") # image_src = image_element.get_attribute("src") # logger.debug(f"상품 이미지 주소 : {image_src}") # #상품명 복사 # product_title_element = driver.find_element(By.XPATH, "//div[@id='productMainContentContainerId']/div/div/div/div/div[5]/div/span/input") # # product_title_element = driver.find_element(By.CSS_SELECTOR, ".ant-input-affix-wrapper-focused > .ant-input") # try: # product_title_element = WebDriverWait(driver, 10).until( # EC.presence_of_element_located((By.XPATH, "//div[5]/div/span/input")) # ) # except Exception as e: # logger.debug(f"상품명 복사 중 오류 발생: 요소를 찾을 수 없습니다. : {e}") # # product_title_element = driver.find_element(By.XPATH, "//div[5]/div/span/input") # product_title = product_title_element.get_attribute("value") product_infos[i-1].main_image_url = product_image_url # 상품 수정 작업 수행 logger.debug("상세페이지 수정작업 시작") modify_detail_page(driver, gemini, product_infos[i-1], delv_collection, json_naver_codes) logger.debug("상세페이지 수정작업 완료") # 키워드 버튼 클릭 # click_element(driver, 'CSS_SELECTOR', '#rc-tabs-0-tab-3', wait_time=10, click_type='normal') click_element(driver, 'CSS_SELECTOR', '.ant-tabs-tab:nth-child(4)', wait_time=10, click_type='normal') logger.debug("키워드 수정작업 시작") # edit_tag(driver, product_infos[i-1]) logger.debug("키워드 수정작업 완료") # 여기에 상품 수정 관련 코드 추가 logger.debug("옵션 수정작업 시작") # modify_option_page(driver, product_infos[i-1]) logger.debug("옵션 수정작업 완료") logger.debug("가격 수정작업 시작") modify_price_page(driver, product_infos[i-1]) logger.debug("가격 수정작업 완료") logger.debug("상품명 수정작업 시작") modify_product_title(driver, product_infos[i-1]) logger.debug("상품명 수정작업 완료") # 상품수정페이지 저장 버튼 클릭 click_element(driver, 'CSS_SELECTOR', '.ant-col:nth-child(9) > .ant-btn', wait_time=10, click_type='normal') # 상품수정페이지 닫기 버튼 클릭 click_element(driver, 'CSS_SELECTOR', '.anticon-close > svg', wait_time=10, click_type='normal') # try: # # 'close' 버튼이 나타날 때까지 최대 10초간 대기 # close_button = WebDriverWait(driver, 10).until( # EC.visibility_of_element_located((By.CSS_SELECTOR, ".anticon-close > svg")) # ) # # 'close' 버튼이 나타나면 클릭 # close_button.click() # logger.debug("Close button was clicked.") # except TimeoutException: # # 지정된 시간 내에 'close' 버튼이 나타나지 않으면 # logger.debug("Close button was not found within the given time.") mark_product_processed(product_id) logger.debug(f"상품 {product_id} 처리 완료.") completed_products += 1 logger.debug(f"진행 상황: {completed_products}/{total_products} ({(completed_products/total_products)*100:.2f}%)") # except Exception as e: # logger.debug(f"상품 {i} 확인 중 오류 발생: {e}") # 다음 페이지로 이동 if current_page < total_pages: try: next_page_button = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".ant-pagination-next > .ant-pagination-item-link")) ) # next_page_button = driver.find_element(By.CSS_SELECTOR, ".ant-pagination-next > .ant-pagination-item-link") # next_page_button.click() driver.execute_script("arguments[0].click();", next_page_button) time.sleep(2) current_page += 1 except Exception as e: logger.debug(f"다음 페이지로 이동하는 중 오류 발생: {e}") break else: logger.debug("모든 페이지 처리 완료. 작업 종료.") break logger.debug("상품 수정 작업이 완료되었습니다.")