forked from ckh08045/AutoPercenty
번역 수정
This commit is contained in:
parent
c8e1f742a5
commit
546de5fb5f
|
|
@ -39,7 +39,7 @@ def trans(original_text):
|
|||
options.add_argument('--ignore-certificate-errors')
|
||||
options.add_argument('--ssl-protocol=any')
|
||||
options.add_argument('--disable-cache')
|
||||
options.add_argument('--headless')
|
||||
#options.add_argument('--headless')
|
||||
driver = webdriver.Chrome(options=options)
|
||||
|
||||
# selenium-stealth 설정 적용
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
from playwright.sync_api import sync_playwright
|
||||
|
||||
import random
|
||||
|
||||
class DeepLTranslator:
|
||||
def __init__(self):
|
||||
self.playwright = sync_playwright().start()
|
||||
self.browser = self.playwright.chromium.launch(headless=True) # 시연을 위해 headless 모드 비활성화
|
||||
# 동영상 녹화 설정을 포함하여 브라우저 컨텍스트 생성
|
||||
self.context = self.browser.new_context(
|
||||
user_agent=random.choice([
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.0.0",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 OPR/85.0.0.0"
|
||||
]),
|
||||
# # 동영상 녹화 설정 추가
|
||||
# record_video_dir="videos/", # 동영상이 저장될 디렉토리 지정
|
||||
# record_video_size={"width": 1280, "height": 720} # 동영상 크기 지정
|
||||
)
|
||||
self.page = self.context.new_page()
|
||||
self.page.goto("https://www.deepl.com/translator#zh/ko/")
|
||||
|
||||
def translate(self, texts):
|
||||
# 단일 텍스트를 리스트로 변환하여 일관된 처리를 가능하게 함
|
||||
if isinstance(texts, str):
|
||||
texts = [texts]
|
||||
|
||||
translated_texts = []
|
||||
for text in texts:
|
||||
# 텍스트 입력 전 입력 필드 클리어
|
||||
self.page.evaluate("""() => {
|
||||
const editor = document.querySelector('[data-testid="translator-source-input"] div[contenteditable="true"]');
|
||||
editor.textContent = ''; // 입력 필드 클리어
|
||||
editor.dispatchEvent(new Event('input', {bubbles: true}));
|
||||
}""")
|
||||
|
||||
# 텍스트 입력
|
||||
# self.page.fill('[data-testid="translator-source-input"] div[contenteditable="true"]', text)
|
||||
self.page.evaluate("""(text) => {
|
||||
const editor = document.querySelector('[data-testid="translator-source-input"] div[contenteditable="true"]');
|
||||
editor.textContent = text;
|
||||
editor.dispatchEvent(new Event('input', {bubbles: true}));
|
||||
editor.dispatchEvent(new Event('keydown', {bubbles: true}));
|
||||
editor.dispatchEvent(new Event('keyup', {bubbles: true}));
|
||||
editor.dispatchEvent(new Event('keypress', {bubbles: true}));
|
||||
}""", text)
|
||||
|
||||
# 번역이 완료될 때까지 기다림
|
||||
self.page.wait_for_function("document.querySelector(\"[data-testid='translator-target-input']\").textContent.length > 0", timeout=20000)
|
||||
self.page.wait_for_selector('[data-testid="translator-target-input"]', state="visible", timeout=10000)
|
||||
|
||||
# 번역된 텍스트 추출
|
||||
translated_text = self.page.text_content('[data-testid="translator-target-input"]')
|
||||
translated_texts.append(translated_text.strip())
|
||||
|
||||
# translated_texts.append(translated_text)
|
||||
|
||||
return translated_texts
|
||||
|
||||
def close(self):
|
||||
self.browser.close()
|
||||
self.playwright.stop()
|
||||
|
||||
# # 사용 예시
|
||||
# translator = DeepLTranslator()
|
||||
# texts_to_translate = ["Hello, world!", "This is a test."]
|
||||
# translated_texts = translator.translate(texts_to_translate)
|
||||
# for original, translated in zip(texts_to_translate, translated_texts):
|
||||
# print(f"Original: {original} | Translated: {translated}")
|
||||
|
||||
# translator.close()
|
||||
|
|
@ -110,12 +110,14 @@ def trans_list_text(original_texts):
|
|||
page.evaluate("""(text) => {
|
||||
const editor = document.querySelector('[data-testid="translator-source-input"] div[contenteditable="true"]');
|
||||
editor.textContent = text;
|
||||
const inputEvent = new Event('input', { bubbles: true });
|
||||
editor.dispatchEvent(inputEvent);
|
||||
editor.dispatchEvent(new Event('input', {bubbles: true}));
|
||||
editor.dispatchEvent(new Event('keydown', {bubbles: true}));
|
||||
editor.dispatchEvent(new Event('keyup', {bubbles: true}));
|
||||
editor.dispatchEvent(new Event('keypress', {bubbles: true}));
|
||||
}""", text)
|
||||
# 번역이 완료될 때까지 기다림
|
||||
|
||||
page.wait_for_function("document.querySelector(\"[data-testid='translator-target-input']\").textContent.length > 0")
|
||||
page.wait_for_function("document.querySelector(\"[data-testid='translator-target-input']\").textContent.length > 0", timeout=20000)
|
||||
|
||||
page.wait_for_selector('[data-testid="translator-target-input"]', state="visible", timeout=10000)
|
||||
|
||||
|
|
|
|||
15
ai/gemini.py
15
ai/gemini.py
|
|
@ -62,17 +62,18 @@ class ImageDescriptionGenerator:
|
|||
[정보]
|
||||
A. 해당상품의 타오바오 상품명은 '{product_info.tao_title}'
|
||||
B. 해당상품의 키워드는 '{product_info.keyword_title}'
|
||||
B. 해당상품의 옵션이름은 '{product_info.trans_option_1_names[0]}, {product_info.trans_option_1_names[1]}, {product_info.trans_option_1_names[2]}, {product_info.trans_option_1_names[3]}, {product_info.trans_option_1_names[4]}'
|
||||
C. 해당상품과 비슷한 상품을 파는 경쟁사의 제품정보는 아래와 같아.
|
||||
C-1. 상품명1 : {product_info.naver_products[0]["productTitle"]}
|
||||
C. 해당상품을 나타나는 상품의 옵션이름은 '{product_info.trans_option_1_names}'
|
||||
D. 해당상품의 특징이라 할 수 옵션의 공통적인 키워드는 '{product_info.trans_option_1_name_common_parts}'
|
||||
E. 해당상품과 비슷한 상품을 파는 경쟁사의 제품정보는 아래와 같아.
|
||||
E-1. 상품명1 : {product_info.naver_products[0]["productTitle"]}
|
||||
상품가격1 : {product_info.naver_products[0]["price"]}
|
||||
C-2. 상품명2 : {product_info.naver_products[1]["productTitle"]}
|
||||
E-2. 상품명2 : {product_info.naver_products[1]["productTitle"]}
|
||||
상품가격2 : {product_info.naver_products[1]["price"]}
|
||||
C-3. 상품명3 : {product_info.naver_products[2]["productTitle"]}
|
||||
E-3. 상품명3 : {product_info.naver_products[2]["productTitle"]}
|
||||
상품가격3 : {product_info.naver_products[2]["price"]}
|
||||
C-4. 상품명4 : {product_info.naver_products[3]["productTitle"]}
|
||||
E-4. 상품명4 : {product_info.naver_products[3]["productTitle"]}
|
||||
상품가격4 : {product_info.naver_products[3]["price"]}
|
||||
C-5. 상품명5 : {product_info.naver_products[4]["productTitle"]}
|
||||
E-5. 상품명5 : {product_info.naver_products[4]["productTitle"]}
|
||||
상품가격5 : {product_info.naver_products[4]["price"]}
|
||||
|
||||
[질문]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
import re
|
||||
from collections import Counter
|
||||
|
||||
def parse_and_extract(option_names):
|
||||
def split_brackets(text):
|
||||
# 괄호 내부와 외부 내용 분리
|
||||
outside, inside = re.sub(r'\(.*?\)', '', text).strip(), re.findall(r'\((.*?)\)', text)
|
||||
return outside.strip(), ' '.join(inside).strip() if inside else ''
|
||||
|
||||
parsed_options = [split_brackets(option) for option in option_names]
|
||||
outside_words = [part.split() for part, _ in parsed_options]
|
||||
inside_words = [part.split() for _, part in parsed_options if part] # 괄호 내용이 있는 경우만 처리
|
||||
|
||||
def find_common_words(words_list):
|
||||
# 모든 단어를 카운트하여 공통 단어 추출
|
||||
word_count = Counter(word for words in words_list for word in words)
|
||||
num_options = len(words_list)
|
||||
common_words = [word for word in set(word for words in words_list for word in words) if word_count[word] == num_options]
|
||||
common_ordered = sorted(common_words, key=lambda x: next((i for i, lst in enumerate(words_list) for j in lst if x == j), None))
|
||||
return common_ordered
|
||||
|
||||
common_outside_words = find_common_words(outside_words)
|
||||
common_inside_words = find_common_words(inside_words)
|
||||
|
||||
def filter_words(words, common_words):
|
||||
return ' '.join(word for word in words if word not in common_words)
|
||||
|
||||
unique_outsides = [filter_words(words, common_outside_words) for words in outside_words]
|
||||
unique_insides = [filter_words(words, common_inside_words) for words in inside_words]
|
||||
|
||||
# 괄호 내용이 있을 때만 괄호 추가
|
||||
unique_options = [outside + (' (' + inside + ')' if inside else '') for outside, inside in zip(unique_outsides, unique_insides)]
|
||||
|
||||
common_words = common_inside_words + common_outside_words
|
||||
return unique_options, common_words
|
||||
|
|
@ -353,7 +353,7 @@ def create_product_card(product_name, image_url, price, rank, purchase, review):
|
|||
|
||||
# return product_info_md
|
||||
|
||||
def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver_codes, login_info):
|
||||
def modify_detail_page(driver, product_info, gemini, translator, delv_collection, json_naver_codes, login_info):
|
||||
|
||||
detail_css = ".ant-tabs-tab:nth-child(6)"
|
||||
|
||||
|
|
@ -550,6 +550,10 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
|
|||
# # data-value 속성 값을 가져옵니다.
|
||||
current_value = textarea.get_attribute("data-value")
|
||||
original_html_tags = original_html(current_value)
|
||||
|
||||
detail_images = fetch_image_urls(original_html_tags)
|
||||
product_info.detail_image_urls = detail_images
|
||||
|
||||
# logger.debug(f"현재 속성값 :{current_value}")
|
||||
product_info.current_value = original_html_tags
|
||||
|
||||
|
|
@ -573,23 +577,23 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
|
|||
# # JavaScript를 사용하여 textarea 값 설정
|
||||
# script = "arguments[0].value = arguments[1];"
|
||||
# driver.execute_script(script, textarea, new_value)
|
||||
time.sleep(0.5)
|
||||
logger.debug("새로운 값이 성공적으로 설정됨.")
|
||||
#time.sleep(0.5)
|
||||
#logger.debug("새로운 값이 성공적으로 설정됨.")
|
||||
|
||||
time.sleep(0.2)
|
||||
#time.sleep(0.2)
|
||||
|
||||
# textarea.send_keys(Keys.ENTER)
|
||||
# textarea.send_keys(Keys.ENTER)
|
||||
# logger.debug("엔터키 전송.")
|
||||
|
||||
click_element(driver, 'XPATH', save_button_xpath, 5, 'js')
|
||||
time.sleep(0.2)
|
||||
logger.debug("저장버튼 전송.")
|
||||
#click_element(driver, 'XPATH', save_button_xpath, 5, 'js')
|
||||
#time.sleep(0.2)
|
||||
#logger.debug("저장버튼 전송.")
|
||||
|
||||
# html_btn.click()
|
||||
logger.debug("HTML 수정 버튼 다시 클릭하여 기본편집페이지로 돌아감.")
|
||||
click_element(driver, 'XPATH', html_btn_xpath, 5, 'js')
|
||||
|
||||
logger.debug("HTML 수정 버튼 다시 클릭하여 기본편집페이지로 돌아감.")
|
||||
time.sleep(0.2)
|
||||
except Exception as e:
|
||||
logger.debug(f"HTML 전환 수정 중 에러발생 : {e}", exc_info=True)
|
||||
|
|
@ -598,22 +602,20 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
|
|||
trans_img_tag = login_info["whether_modifyImageTanslation"]
|
||||
logger.debug(f"whether_modifyImageTanslation : {trans_img_tag}")
|
||||
|
||||
if login_info["whether_modifyImageTanslation"]:
|
||||
if trans_img_tag:
|
||||
logger.debug("상세페이지 이미지 번역 시작")
|
||||
|
||||
logger.debug("HTML 수정 버튼을 클릭하여 원본이밎URL 수집 및 삭제")
|
||||
logger.debug("HTML 수정 버튼을 클릭하여 원본 URL 수집 및 삭제")
|
||||
click_element(driver, 'XPATH', html_btn_xpath, 5, 'js')
|
||||
|
||||
# # ============번역을 위한 사전작업============
|
||||
# 이미지 Url 수집
|
||||
# translated_image_urls = [] # 번역된 이미지 URL들을 저장할 리스트
|
||||
detail_images = fetch_image_urls(original_html_tags)
|
||||
|
||||
current_value = textarea.get_attribute("data-value")
|
||||
original_html_tags = original_html(current_value)
|
||||
#current_value = textarea.get_attribute("data-value")
|
||||
#original_html_tags = original_html(current_value)
|
||||
|
||||
# logger.debug(f"detail_images URLs \n {detail_images}")
|
||||
product_info.detail_image_urls = detail_images
|
||||
|
||||
# 원본 URL을 빈문자열로 대체
|
||||
logger.debug("원본 URL을 빈 문자열로 대체")
|
||||
|
|
@ -632,7 +634,7 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
|
|||
for i, detail_image in enumerate(detail_images):
|
||||
logger.debug(f"상세페이지 {i+1}번째 이미지 번역 시작")
|
||||
logger.debug(f"이미지 타입 : {type(detail_image)}")
|
||||
returned_img = image_trans(detail_image, 'translate')
|
||||
returned_img = image_trans(detail_image, translator, 'translate')
|
||||
image_to_clipboard(returned_img)
|
||||
logger.debug("번역 완료 및 부텨넣기")
|
||||
detail_content.send_keys(Keys.CONTROL, 'v')
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ 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, click_and_confirm_tab
|
||||
from ai.split import parse_and_extract
|
||||
from ai.deepl import trans, trans_list
|
||||
from ai.deepl_with_playwright import trans_text, trans_list_text
|
||||
# from ai.compare import find_most_similar_image_by_one
|
||||
|
|
@ -14,7 +15,7 @@ import logging
|
|||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
|
||||
def modify_option_page(driver, product_info):
|
||||
def modify_option_page(driver, product_info, translator):
|
||||
|
||||
option_css = ".ant-tabs-tab:nth-child(2)"
|
||||
|
||||
|
|
@ -148,13 +149,13 @@ def modify_option_page(driver, product_info):
|
|||
try:
|
||||
logger.debug(f"옵션타입 {option_idx}에 대한 처리 시작")
|
||||
logger.debug("가격 낮은 순으로 정렬")
|
||||
low_price_order_xpath = f"//div[{option_idx}]/div/div/div[2]/div/div/div[4]/div[2]/div[2]/div/div[3]/button"
|
||||
low_price_order_xpath = f"//div[{option_idx}]/div/div/div[2]/div/div/div[4]/div[2]/div[2]/div/div[4]/button"
|
||||
click_element(driver, 'XPATH', low_price_order_xpath, 10, 'js')
|
||||
edit_option(driver, option_idx, options_info[f'option_type_{option_idx}']['options_count']) # 각 옵션의 전체 체크박스 해제
|
||||
# 가격 낮은 순으로 재정렬
|
||||
logger.debug("가격 낮은 순으로 재정렬")
|
||||
click_element(driver, 'XPATH', low_price_order_xpath, 10, 'js')
|
||||
option_name_trans(driver, product_info, option_idx, options_info[f'option_type_{option_idx}']['options_count'], allowed_special_chars, special_char_replacements)
|
||||
option_name_trans(driver, translator, product_info, option_idx, options_info[f'option_type_{option_idx}']['options_count'], allowed_special_chars, special_char_replacements)
|
||||
except KeyError:
|
||||
logger.error(f"옵션타입 {option_idx}에 대한 정보가 없습니다.")
|
||||
except Exception as e:
|
||||
|
|
@ -198,13 +199,13 @@ def edit_option(driver, option_type, option_count):
|
|||
# select_all_checkbox_xpath = f"//div[@id='productMainContentContainerId']/div/div[2]/div/div/div[2]/div/div[{option_type}]/div/div/div[2]/div/div/div[5]/div/div/label/span"
|
||||
select_all_checkbox_xpath = f"//div[{option_type}]/div/div/div[2]/div/div/div[4]/div[2]/div[1]/label/span[1]"
|
||||
|
||||
logger.debug("전체체크박스의 상태확인")
|
||||
select_all_checkbox_state_xpath = f"//div[{option_type}]/div/div/div[2]/div/div/div[4]/div[2]/div[1]/label/span[1]/input"
|
||||
select_all_checkbox_state_element = return_element(driver, 'XPATH', select_all_checkbox_state_xpath, 10)
|
||||
# select_all_checkbox_state_element = driver.find_element_by_xpath(select_all_checkbox_state_xpath)
|
||||
if select_all_checkbox_state_element.get_attribute("aria-checked") == "mixed":
|
||||
logger.debug("전체체크박스의 일부 선택상태 확인")
|
||||
click_element(driver, 'XPATH', select_all_checkbox_xpath, 10, 'js')
|
||||
# logger.debug("전체체크박스의 상태확인")
|
||||
# select_all_checkbox_state_xpath = f"//div[{option_type}]/div/div/div[2]/div/div/div[4]/div[2]/div[1]/label/span[1]/input"
|
||||
# select_all_checkbox_state_element = return_element(driver, 'XPATH', select_all_checkbox_state_xpath, 10)
|
||||
# # select_all_checkbox_state_element = driver.find_element_by_xpath(select_all_checkbox_state_xpath)
|
||||
# if select_all_checkbox_state_element.get_attribute("aria-checked") == "mixed":
|
||||
# logger.debug("전체체크박스의 일부 선택상태 확인")
|
||||
# click_element(driver, 'XPATH', select_all_checkbox_xpath, 10, 'js')
|
||||
|
||||
click_element(driver, 'XPATH', select_all_checkbox_xpath, 10, 'js')
|
||||
logger.debug(f"옵션타입 {option_type} 전체 선택 체크박스 해제")
|
||||
|
|
@ -230,7 +231,7 @@ def edit_option(driver, option_type, option_count):
|
|||
except Exception as e:
|
||||
logger.error(f"옵션 타입 {option_type} 편집 중 예외 발생: {e}", exc_info=True)
|
||||
|
||||
def option_name_trans(driver, product_info, option_type_number, option_count, allowed_special_chars, special_char_replacements):
|
||||
def option_name_trans(driver, translator, product_info, option_type_number, option_count, allowed_special_chars, special_char_replacements):
|
||||
|
||||
"""
|
||||
원본 옵션명을 수집하여 번역 후 새로 입력
|
||||
|
|
@ -246,7 +247,7 @@ def option_name_trans(driver, product_info, option_type_number, option_count, al
|
|||
|
||||
logger.debug("선택된 옵션명 DeepL로 번역 후 새로운 옵션명 입력")
|
||||
ori_optionNames = []
|
||||
|
||||
deepl_trans_optionNames = []
|
||||
# 원본 옵션명 추출
|
||||
try:
|
||||
for i in range(1, option_count + 1):
|
||||
|
|
@ -260,6 +261,7 @@ def option_name_trans(driver, product_info, option_type_number, option_count, al
|
|||
ori_optionName_element = driver.find_element(By.XPATH, ori_optionName_xpath)
|
||||
ori_optionName = ori_optionName_element.text.strip()
|
||||
cleaned_ori_optionName = replace_or_remove_special_chars(ori_optionName, allowed_special_chars, special_char_replacements)
|
||||
logger.debug(f"정제된 {i}번째 원본 옵션명 : {cleaned_ori_optionName}")
|
||||
ori_optionNames.append(cleaned_ori_optionName)
|
||||
except Exception as e:
|
||||
logger.debug(f"원본옵션명 처리중 에러발생 : {e}", exc_info=True)
|
||||
|
|
@ -272,33 +274,37 @@ def option_name_trans(driver, product_info, option_type_number, option_count, al
|
|||
# cleaned_ori_text = replace_or_remove_special_chars(combined_ori_optionNames, allowed_special_chars, special_char_replacements)
|
||||
# logger.debug(f"원본옵션명 집합 \n {cleaned_ori_text}")
|
||||
|
||||
logger.debug("번역 시행")
|
||||
logger.debug(f"원본옵션 총 {len(ori_optionNames)}개 번역 시행")
|
||||
deepl_trans_optionNames = translator.translate(ori_optionNames) # DeepL 번역 함수
|
||||
|
||||
# deepl_trans_optionNames = trans_list_text(ori_optionNames) # DeepL 번역 함수
|
||||
deepl_trans_optionNames = trans_list(ori_optionNames) # DeepL 번역 함수
|
||||
#deepl_trans_optionNames = trans_list(ori_optionNames) # DeepL 번역 함수
|
||||
# trans_optionNames_text = trans_text(cleaned_ori_text) # DeepL_with_playwright 번역 함수
|
||||
|
||||
# trans_optionNames_text = trans(cleaned_ori_text) # DeepL 번역 함수
|
||||
|
||||
logger.debug(f"번역된 텍스트 \n {deepl_trans_optionNames} ")
|
||||
|
||||
logger.debug("번역 텍스트의 특수문자 제거 및 대체")
|
||||
logger.debug("번역 텍스트의 특수문자 제거 및 대체")
|
||||
trans_optionNames = []
|
||||
for deepl_trans_optionName in deepl_trans_optionNames:
|
||||
cleand_trans_optionName = replace_or_remove_special_chars(deepl_trans_optionName, allowed_special_chars, special_char_replacements)
|
||||
trans_optionNames.append(cleand_trans_optionName)
|
||||
|
||||
parsed_trans_optionNames, common_names = parse_and_extract(trans_optionNames)
|
||||
# trans_optionNames = trans_optionNames_text.split('\n\n')
|
||||
# logger.debug("번역 텍스트 나누기")
|
||||
|
||||
logger.debug("product_info 옵션명 업데이트")
|
||||
try:
|
||||
product_info.update_option_names(option_type_number, ori_optionNames, trans_optionNames)
|
||||
product_info.update_option_names(option_type_number, ori_optionNames, parsed_trans_optionNames, common_names)
|
||||
except Exception as e:
|
||||
logger.debug(f"product_info 옵션명 업데이트 중 에러 발생 {e}", exc_info=True)
|
||||
|
||||
# 번역된 옵션명을 각 input 요소에 입력
|
||||
try:
|
||||
for i, trans_optionName in enumerate(trans_optionNames, 1):
|
||||
logger.debug(f"parsed_trans_optionNames 갯수 : {len(parsed_trans_optionNames)}")
|
||||
for i, trans_optionName in enumerate(parsed_trans_optionNames, 1):
|
||||
optionName_input_xpath = f"//div[{option_type_number}]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{i}]/div/div[1]/div/div[3]/div[2]/div[1]/span/input" if option_type_number != 2 else f"//div[{option_type_number}]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{i}]/div/div[1]/div/div[2]/div[2]/div[1]/span/input"
|
||||
optionName_input_element = WebDriverWait(driver, 10).until(
|
||||
EC.element_to_be_clickable((By.XPATH, optionName_input_xpath)))
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ class ProductInfo:
|
|||
|
||||
self.option_1_names = [] # 상품 옵션 이름 리스트
|
||||
self.trans_option_1_names = [] # 번역된 상품 옵션 이름 리스트
|
||||
self.trans_option_1_name_parts = [] # 번역된 상품 옵션 이름 리스트의 단어별 리스트 저장
|
||||
self.trans_option_1_name_common_parts = [] # 번역된 상품 옵션 이름 리스트의 단어별 리스트 저장
|
||||
self.option_1_image_urls = [] # 상품 옵션 이미지 URL 리스트
|
||||
self.trans_option_1_image_urls = [] # 상품 옵션 이미지 URL 리스트
|
||||
self.option_2_names = [] # 상품 옵션 이름 리스트
|
||||
self.trans_option_2_names = [] # 번역된 상품 옵션 이름 리스트
|
||||
self.trans_option_2_name_parts = [] # 번역된 상품 옵션 이름 리스트의 단어별 리스트 저장
|
||||
self.trans_option_2_name_common_parts = [] # 번역된 상품 옵션 이름 리스트의 단어별 리스트 저장
|
||||
self.option_2_image_urls = [] # 상품 옵션 이미지 URL 리스트
|
||||
self.trans_option_2_image_urls = [] # 상품 옵션 이미지 URL 리스트
|
||||
self.detail_image_urls = [] # 상품 상세페이지 이미지 URL 리스트
|
||||
|
|
@ -81,12 +81,12 @@ class ProductInfo:
|
|||
'naver_products': self.naver_products,
|
||||
'option_1_names': self.option_1_names,
|
||||
'trans_option_1_names': self.trans_option_1_names,
|
||||
'trans_option_1_name_parts': self.trans_option_1_name_parts,
|
||||
'trans_option_1_name_parts': self.trans_option_1_name_common_parts,
|
||||
'option_1_image_urls': self.option_1_image_urls,
|
||||
'trans_option_1_image_urls': self.trans_option_1_image_urls,
|
||||
'option_2_names': self.option_2_names,
|
||||
'trans_option_2_names': self.trans_option_2_names,
|
||||
'trans_option_2_name_parts': self.trans_option_2_name_parts,
|
||||
'trans_option_2_name_parts': self.trans_option_2_name_common_parts,
|
||||
'option_2_image_urls': self.option_2_image_urls,
|
||||
'trans_option_2_image_urls': self.trans_option_2_image_urls,
|
||||
'detail_image_urls': self.detail_image_urls,
|
||||
|
|
@ -95,16 +95,18 @@ class ProductInfo:
|
|||
'trans_thumb_image_urls': self.trans_thumb_image_urls,
|
||||
}
|
||||
|
||||
def update_option_names(self, option_type_number, ori_optionNames, trans_optionNames):
|
||||
def update_option_names(self, option_type_number, ori_optionNames, trans_optionNames, common_names):
|
||||
if option_type_number == 1:
|
||||
self.option_1_names = ori_optionNames
|
||||
self.trans_option_1_names = trans_optionNames
|
||||
self.trans_option_1_name_common_parts = common_names
|
||||
while len(self.option_1_names) < 5:
|
||||
self.option_1_names.append(".")
|
||||
self.trans_option_1_names.append(".")
|
||||
elif option_type_number == 2:
|
||||
self.option_2_names = ori_optionNames
|
||||
self.trans_option_2_names = trans_optionNames
|
||||
self.trans_option_2_name_common_parts = common_names
|
||||
while len(self.option_2_names) < 5:
|
||||
self.option_2_names.append(".")
|
||||
self.trans_option_2_names.append(".")
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import logging
|
|||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
|
||||
def image_trans(image_url, convert_type):
|
||||
def image_trans(image_url, translator, convert_type):
|
||||
# 이미지를 URL로부터 읽어옵니다.
|
||||
image = read_image_from_url(image_url)
|
||||
|
||||
|
|
@ -69,7 +69,8 @@ def image_trans(image_url, convert_type):
|
|||
texts_to_translate = [text for _, text, _, _, _ in detected_texts]
|
||||
logger.debug(f"원본 텍스트: {texts_to_translate}")
|
||||
logger.debug(f"DEEPL 번역시작")
|
||||
translated_texts = translate_texts_deepl(texts_to_translate)
|
||||
# translated_texts = translate_texts_deepl(texts_to_translate)
|
||||
translated_texts = translator.translate(texts_to_translate)
|
||||
if not translated_texts: # 빈 리스트 체크
|
||||
logger.debug(f"DEEPL 번역실패로 translatepy 시작")
|
||||
translated_texts = translate_texts_translatepy(texts_to_translate)
|
||||
|
|
|
|||
6
main.py
6
main.py
|
|
@ -19,6 +19,7 @@ from utils import log
|
|||
from config import WEBSITE_URL
|
||||
from credentials import load_credentials, save_credentials
|
||||
from ai.gemini import ImageDescriptionGenerator
|
||||
from ai.deepl_class import DeepLTranslator
|
||||
from login_widget import LoginWidget
|
||||
from mongo_config import MongoConfig
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
|
@ -155,7 +156,7 @@ def main():
|
|||
|
||||
# 사용자로부터 로그인 정보를 받거나 저장된 정보 사용
|
||||
gemini = ImageDescriptionGenerator('AIzaSyCER9mD617P5OGaoHCK7drsTkmXUIzFn4U')
|
||||
|
||||
translator = DeepLTranslator()
|
||||
# # username, password, employeeID = load_credentials()
|
||||
# if not username or not password or not employeeID:
|
||||
# username = input("Username: ")
|
||||
|
|
@ -190,10 +191,11 @@ def main():
|
|||
login(driver, login_info) # login 함수에 로그인 정보를 전달하여 호출
|
||||
|
||||
#상품 수정 작업 수행
|
||||
modify_products(driver, gemini, mongo_config, login_info, set_num_modify)
|
||||
modify_products(driver, gemini, translator, mongo_config, login_info, set_num_modify)
|
||||
|
||||
#웹 드라이버 종료
|
||||
driver.quit()
|
||||
translator.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
CURRENT_VERSION = "1.0.0"
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ def wait_for_javascript(driver, timeout=20):
|
|||
except TimeoutException:
|
||||
logger.debug("페이지 로딩 실패: 시간 초과")
|
||||
|
||||
def modify_products(driver, gemini, mongo_config, login_info, set_num_modify):
|
||||
def modify_products(driver, gemini, translator, mongo_config, login_info, set_num_modify):
|
||||
# product_info = set_product_info() # 상품정보리스트 생성
|
||||
autoPercentyProductsDB = AutoPercentyProductsDB(mongo_config)
|
||||
|
||||
|
|
@ -197,8 +197,8 @@ def modify_products(driver, gemini, mongo_config, login_info, set_num_modify):
|
|||
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, login_info)),
|
||||
('option_modification', modify_option_page, (driver, product_infos[i-1], translator)),
|
||||
('detail_page_modification', modify_detail_page, (driver, product_infos[i-1], gemini, translator, delv_collection, json_naver_codes, login_info)),
|
||||
('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])),
|
||||
|
|
|
|||
Loading…
Reference in New Issue