1
0
Fork 0
AutoPercenty2/modify_products.py

474 lines
25 KiB
Python

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
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_with_mongo import AutoPercentyProductsDB
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.thumbnail import modify_thumb_page
from edit.trans_image import *
from edit.uploadMarket import *
from edit.action_elements import click_element, return_element, wait_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
# 함수 이름과 해당하는 작업 함수 매핑
# function_mapping = {
# 'tag_modification': edit_tag,
# 'option_modification': modify_option_page,
# 'detail_page_modification': modify_detail_page,
# 'thumbnail_modification': modify_thumb_page,
# 'price_modification': modify_price_page,
# 'title_modification': modify_product_title,
# }
def should_execute_step(step_name, login_info):
if step_name == 'tag_modification':
return login_info.whether_modifyProductTag
elif step_name == 'thumbnail_modification':
return login_info.whether_modifyProductThumb
elif step_name == 'option_modification':
return login_info.whether_modifyProductOptions
elif step_name == 'detail_page_modification':
return login_info.whether_modifyProductDetail
elif step_name == 'price_modification':
return login_info.whether_modifyProductPrice
else:
return True
def perform_step(db, step_name, action, current_user, *args):
"""
단계별 작업을 수행하는 함수.
"""
product_info = args[1]
try:
action(*args) # action 함수에 product_info 및 *args를 전달합니다.
db.update_process_step(product_info.id, step_name, current_user)
logger.debug(f"Step {step_name} completed for product {product_info.id}.")
except Exception as e:
logger.error(f"Error performing step {step_name} for product {product_info.id}: {e}", exc_info=True)
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}", exc_info=True)
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, login_info, set_num_modify):
# product_info = set_product_info() # 상품정보리스트 생성
autoPercentyProductsDB = AutoPercentyProductsDB(mongo_config)
autoPercentyProductsDB.reset_product_by_id('660d636271e50111cf71284e')
autoPercentyProductsDB.reset_product_by_id('660d635371e50111cf712842')
try:
if login_info['per_mode']:
current_user = login_info['per_email']
else:
current_user = login_info['per_em_email']
logger.debug(f"현재 작업중인 사용자 지정 : {current_user}")
except Exception as e:
logger.debug(f"현재 작업중인 사용자 지정 중 에러발생 : {e}", exc_info=True)
# MongoDB에 연결
try:
client = mongo_config.client
# self.login_db = self.mongoConfig.get_db() # mongo_config 인스턴스를 통해 데이터베이스 객체를 가져옴
db = client['taobao_project']
# products_collection = db['AutoPercenty_Produtcs']
delv_collection = db['delv_fee']
except Exception as e:
logger.debug(f"DB연결 중 에러발생 : {e}", exc_info=True)
set_num_modify = int(set_num_modify)
logger.debug(f"수정대상 상품 수 설정 : {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}", exc_info=True)
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 처리
steps_and_actions = [
('tag_modification', edit_tag, (driver, product_infos[i-1])),
('thumbnail_modification', modify_thumb_page, (driver, product_infos[i-1])),
('option_modification', modify_option_page, (driver, product_infos[i-1])),
('detail_page_modification', modify_detail_page, (driver, product_infos[i-1], gemini, delv_collection, json_naver_codes)),
('price_modification', modify_price_page, (driver, product_infos[i-1])),
('title_modification', modify_product_title, (driver, product_infos[i-1])),
('trans_detailImage', tran_detail_image, (driver, product_infos[i-1])),
('upload_to_market', upload_to_market, (driver, product_infos[i-1])),
]
# 상품 수정 관련 작업을 조건에 따라 수행하는 로직
step_conditions = {
'tag_modification': login_info.whether_modifyProductTag,
'thumbnail_modification': login_info.whether_modifyProductThumb,
'option_modification': login_info.whether_modifyProductOptions,
'detail_page_modification': login_info.whether_modifyProductDetail,
'price_modification': login_info.whether_modifyProductPrice,
'title_modification': login_info.whether_modifyProductName,
'trans_detailImage': login_info.whether_modifyImageTanslation,
'upload_to_market': login_info.whether_uploadToMarket,
}
# 상품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 = f"ID:{product_id}"
product_infos[i-1].id = product_id
logger.debug(f"상품ID : {product_id}")
except Exception as e:
logger.debug(f"상품ID 복사 중 오류 발생: 요소를 찾을 수 없습니다. : {e}", exc_info=True)
# 상품ID 처리 여부 판단
incomplete_steps = autoPercentyProductsDB.is_step_incomplete(product_id)
if incomplete_steps is True:
pass
elif isinstance(incomplete_steps, list) and len(incomplete_steps) < 6:
# incomplete_steps가 리스트 타입이고, 길이가 6 미만인 경우에만 미완성된 단계들에 대해 처리합니다.
logger.debug(f"총 [{len(incomplete_steps)}]개의 미완성 목록을 발견")
logger.debug(f"미완성 스텝 목록 : {incomplete_steps}")
product_infos[i-1] = autoPercentyProductsDB.get_product_info_by_id(product_id)
logger.debug("기존 product_info를 가져옵니다.")
# 완료되지 않은 단계에 해당하는 작업을 수행합니다.
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)
for step_name, action, args in steps_and_actions:
if step_name in incomplete_steps:
# 각 단계별 실행 여부 판단
if step_conditions.get(step_name, False):
perform_step(autoPercentyProductsDB, step_name, action, current_user, *args)
autoPercentyProductsDB.finalize_product_processing(product_id, current_user, product_infos[i-1])
logger.info(f"상품 ID {product_id}의 미완성 목록을 완성했습니다.")
pass
else:
# 여기에는 incomplete_steps가 False이거나 리스트의 길이가 6인 경우.
# 이는 상품이 수정된 적 없거나 모든 단계가 미완성인 상태를 의미.
autoPercentyProductsDB.initialize_process_steps(product_id, current_user)
logger.info(f"상품 ID {product_id}를 초기화 하고 상품수정을 시작합니다.")
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
if not p_main_title_text:
logger.debug("상품명 다시 가져오기")
p_main_title_text = p_main_title_element.get_attribute('innerHTML').strip()
product_infos[i-1].keyword_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}", exc_info=True)
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}", exc_info=True)
# 상품 이미지 복사
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}", exc_info=True)
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}", exc_info=True)
# # 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(0.3)
tao_title_text_xpath = "//div[@id='productMainContentContainerId']/div/div/div[6]/div/div/span"
tao_title = return_element(driver, 'XPATH', tao_title_text_xpath, 10)
logger.debug(f"tao_title 텍스트 : {tao_title.text}")
product_infos[i-1].tao_title = tao_title.text
# 상품수정 페이지에 표시된 퍼센티카테고리 텍스트 수집
per_cat = return_element(driver, 'XPATH', '//div[8]/div/div/div[2]/div/div/div/span[2]/div/div', 10)
logger.debug(f"퍼센티 등록 화면에 표시된 카테고리 텍스트 : {per_cat.text}")
product_infos[i-1].per_cat_code = per_cat.text
# # 이미지 주소 복사
# # 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}", exc_info=True)
# # 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}", exc_info=True)
# # 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
# 각 단계별로 수정 작업 수행
for step_name, action, args in steps_and_actions:
# 각 단계별 실행 여부 판단
if step_conditions.get(step_name, False):
perform_step(autoPercentyProductsDB, step_name, action, current_user, *args)
# 모든 단계가 완료되었다면, 상품 처리 최종화
autoPercentyProductsDB.finalize_product_processing(product_infos[i-1].id, current_user, product_infos[i-1])
# try:
# # 각 단계별 작업 수행
# perform_step(autoPercentyProductsDB, 'tag_modification', product_infos[i-1], current_user, driver)
# perform_step(autoPercentyProductsDB, 'option_modification', product_infos[i-1], current_user, driver)
# perform_step(autoPercentyProductsDB, 'detail_page_modification', product_infos[i-1], current_user, driver, gemini, delv_collection, json_naver_codes)
# perform_step(autoPercentyProductsDB, 'thumbnail_modification', product_infos[i-1], current_user, driver)
# perform_step(autoPercentyProductsDB, 'price_modification', product_infos[i-1], current_user, driver)
# logger.debug("모든 단계의 수정 작업이 완료되었습니다.")
# except Exception as e:
# logger.error(f"수정 작업 중 예외 발생: {e}", exc_info=True)
# logger.debug("키워드 수정작업 시작")
# edit_tag(driver, product_infos[i-1])
# autoPercentyProductsDB.update_process_step(product_id, step_name="step1")
# logger.debug("키워드 수정작업 완료")
# logger.debug("옵션 수정작업 시작")
# modify_option_page(driver, product_infos[i-1])
# logger.debug("옵션 수정작업 완료")
# # 상품 수정 작업 수행
# logger.debug("상세페이지 수정작업 시작")
# modify_detail_page(driver, gemini, product_infos[i-1], delv_collection, json_naver_codes)
# logger.debug("상세페이지 수정작업 완료")
# logger.debug("썸네일 수정작업 시작")
# modify_thumb_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("......상품명 메서드 작성 중......")
# logger.debug("상품명 수정작업 완료")
# 상품수정페이지 저장 버튼 클릭
logger.debug("상품 수정 저장 중......")
click_element(driver, 'CSS_SELECTOR', '.ant-col:nth-child(9) > .ant-btn', wait_time=10, click_type='js')
# 상품수정페이지 닫기 버튼 클릭
time.sleep(1)
ActionChains(driver).send_keys(Keys.ESCAPE).perform()
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}", exc_info=True)
# 다음 페이지로 이동
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}", exc_info=True)
break
else:
logger.debug("모든 페이지 처리 완료. 작업 종료.")
break
logger.debug("상품 수정 작업이 완료되었습니다.")