1
0
Fork 0
AutoPercenty2/modify_products.py

337 lines
16 KiB
Python

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("상품 수정 작업이 완료되었습니다.")