가격 핸들러에 토글 상태 추가 및 웨일 브라우저 시작 로직 개선. 브라우저 시작 시 최대 3회 재시도 기능 추가, UI에서 여러 토글 상태 초기화 및 추가. 상품명 번역 타입 선택 기능 및 키고정 기능 구현.
This commit is contained in:
parent
9ccaac3e4e
commit
30c785663d
|
|
@ -96,7 +96,7 @@ class BrowserController(QThread):
|
|||
|
||||
self.clipboardImageManager = ClipboardImageManager(logger=self.logger, watermark_font_size=36, debug_flag=self.toggle_states['debug_mode'])
|
||||
self.optionHandler = OptionHandler(self.locator_manager, self, self.whale_translator, self.clipboardImageManager, self.logger, self.gpt_client, self.update_detail_progress_signal, self.set_progress_visible_signal, debug_flag=self.toggle_states['debug_mode'])
|
||||
self.priceHandler = PriceHandler(self.locator_manager, self, self.logger, self.optionHandler, self.price_setting_diag, debug_flag=self.toggle_states['debug_mode'])
|
||||
self.priceHandler = PriceHandler(self.locator_manager, self, self.logger, self.optionHandler, self.price_setting_diag, self.toggle_states, debug_flag=self.toggle_states['debug_mode'])
|
||||
self.thumbnailHandler = ThumbnailHandler(self.locator_manager, self, self.logger, self.whale_translator, self.clipboardImageManager, self.toggle_states, self.update_detail_progress_signal, self.set_progress_visible_signal)
|
||||
self.titleGenerator = TitleGenerator(self.locator_manager, self, self.logger, self.whale_translator, self.toggle_states, self.gpt_client, self.forbidden_word_manager, self.user_id, self.supabase_manager)
|
||||
self.tagsHandler = TagsHandler(self.locator_manager, self, self.logger, self.toggle_states)
|
||||
|
|
@ -1504,7 +1504,28 @@ class BrowserController(QThread):
|
|||
# 금지어 목록 업데이트
|
||||
self.forbidden_word_manager.refresh_forbidden_words()
|
||||
|
||||
self.whale_translator.start_trans_browser()
|
||||
# 웨일 브라우저 시작 - 최대 3번 재시도
|
||||
max_retries = 3
|
||||
retry_count = 0
|
||||
whale_window = None
|
||||
|
||||
while retry_count < max_retries:
|
||||
self.logger.log(f'웨일 브라우저 시작 시도 {retry_count + 1}/{max_retries}...', level=logging.INFO)
|
||||
whale_window = self.whale_translator.start_trans_browser()
|
||||
|
||||
if whale_window:
|
||||
self.logger.log('웨일 브라우저가 성공적으로 시작되었습니다.', level=logging.INFO)
|
||||
break
|
||||
|
||||
retry_count += 1
|
||||
self.logger.log(f'웨일 브라우저 시작 실패. {retry_count}/{max_retries}', level=logging.WARNING)
|
||||
await asyncio.sleep(1) # 잠시 대기 후 재시도
|
||||
|
||||
if not whale_window:
|
||||
error_msg = "웨일 브라우저를 시작할 수 없습니다. 프로그램을 종료합니다."
|
||||
self.logger.log(error_msg, level=logging.ERROR)
|
||||
self.translation_error.emit(error_msg)
|
||||
return
|
||||
|
||||
# 1. 총 상품 수 수집
|
||||
await self.scroll_page_to_bottom() # 동적 로딩을 위해 끝까지 스크롤
|
||||
|
|
|
|||
180
mainUI_SP.py
180
mainUI_SP.py
|
|
@ -437,38 +437,41 @@ class AutoPercentyGUI(QMainWindow):
|
|||
'is_admin' : False,
|
||||
}
|
||||
|
||||
# 토글 상태를 저장할 딕셔너리 초기화
|
||||
# 토글 상태 초기화
|
||||
self.toggle_states = {
|
||||
'title': False,
|
||||
'title': True,
|
||||
'title_trans_type': True,
|
||||
'use_lens': False,
|
||||
'ocr': False,
|
||||
'use_API': False,
|
||||
'clientID': "",
|
||||
'clientSecret': "",
|
||||
'optionTrnas': False,
|
||||
'optionIMGTrans': False,
|
||||
'optionIMGTrans_type': False,
|
||||
'optionAutoSelect': False,
|
||||
'price': False,
|
||||
'thumb': False,
|
||||
'thumb_trans_type': False,
|
||||
'thumb_rmb_count': 0,
|
||||
'thumb_nukki': False, # 썸네일 누끼 독립 기능 추가
|
||||
'tag': False,
|
||||
'detail_Option': False,
|
||||
'detail_IMGTrans': False,
|
||||
'optionTrnas': True,
|
||||
'optionIMGTrans': True,
|
||||
'optionIMGTrans_type': True,
|
||||
'optionAutoSelect': True,
|
||||
'price': True,
|
||||
'tag': True,
|
||||
'thumb': True,
|
||||
'thumb_trans_type': True,
|
||||
'thumb_nukki': False,
|
||||
'detail_Option': True,
|
||||
'detail_IMGTrans': True,
|
||||
'detail_IMGTrans_type': False,
|
||||
'debug_mode': False,
|
||||
'recovery_mode': False,
|
||||
'ed_mode': False, # 등록된 상품을 수정할때
|
||||
'discord': False, # 디스코드 토글
|
||||
'discord_webhook': "", # 디스코드 웹훅 URL
|
||||
'watermark': False, # 워터마크 토글 추가
|
||||
'watermark_text': "", # 워터마크 텍스트 저장
|
||||
'opacity_percent': 25, # 워터마크 투명도
|
||||
'max_option_count': 20, # 최대 선택가능한 옵션 수
|
||||
'group_index': 1, # 작업그룹 선택
|
||||
'ocr': False, # OCR 토글 추가
|
||||
'unwanted_words': self.user_info.get('unwanted_words', []), # 불필요한 단어 리스트 추가
|
||||
# 'ed_mode': False,
|
||||
'discord': False,
|
||||
'watermark': False,
|
||||
'clientID': "",
|
||||
'clientSecret': "",
|
||||
'discord_webhook': "",
|
||||
'watermark_text': "AutoPercenty",
|
||||
'thumb_rmb_count': 3,
|
||||
'max_option_count': 3,
|
||||
'opacity_percent': 50,
|
||||
'group_index': None,
|
||||
'remove_overprice': False, # 가격초과제외 기능
|
||||
'cat_rec': False, # 카테 추천 기능
|
||||
'fixed_keywords': False, # 키고정 기능
|
||||
'fixed_keywords_count': 3, # 키고정 개수 기본값
|
||||
}
|
||||
|
||||
def initUI(self):
|
||||
|
|
@ -597,12 +600,18 @@ class AutoPercentyGUI(QMainWindow):
|
|||
self.toggle_layout.addWidget(self.title_toggle_label, 0, 0)
|
||||
self.toggle_layout.addWidget(self.title_toggle, 0, 1)
|
||||
|
||||
self.title_trans_type_toggle_label = QLabel("상품명 번역 타입", self)
|
||||
self.title_trans_type_toggle = ToggleSwitch(self)
|
||||
self.title_trans_type_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('title_trans_type', checked))
|
||||
self.toggle_layout.addWidget(self.title_trans_type_toggle_label, 0, 2)
|
||||
self.toggle_layout.addWidget(self.title_trans_type_toggle, 0, 3)
|
||||
|
||||
# 쇼핑렌즈 사용 토글
|
||||
self.use_lens_toggle_label = QLabel("쇼핑렌즈 사용", self)
|
||||
self.use_lens_toggle = ToggleSwitch(self)
|
||||
self.use_lens_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('use_lens', checked))
|
||||
self.toggle_layout.addWidget(self.use_lens_toggle_label, 0, 2)
|
||||
self.toggle_layout.addWidget(self.use_lens_toggle, 0, 3)
|
||||
self.toggle_layout.addWidget(self.use_lens_toggle_label, 0, 4)
|
||||
self.toggle_layout.addWidget(self.use_lens_toggle, 0, 5)
|
||||
|
||||
# # API 사용 토글
|
||||
# self.use_API_toggle_label = QLabel("API 사용", self)
|
||||
|
|
@ -711,6 +720,31 @@ class AutoPercentyGUI(QMainWindow):
|
|||
self.debug_toggle = ToggleSwitch(self)
|
||||
self.debug_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('debug_mode', checked))
|
||||
|
||||
# 카테 추천 토글
|
||||
self.cat_rec_toggle_label = QLabel("카테 추천", self)
|
||||
self.cat_rec_toggle = ToggleSwitch(self)
|
||||
self.cat_rec_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('cat_rec', checked))
|
||||
|
||||
# 키고정 토글 및 SpinBox
|
||||
self.keyword_fix_toggle_label = QLabel("키고정", self)
|
||||
self.keyword_fix_toggle = ToggleSwitch(self)
|
||||
self.keyword_fix_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('keyword_fix', checked))
|
||||
|
||||
self.keyword_fix_count_label = QLabel("키고정 수", self)
|
||||
self.keyword_fix_count_input = QSpinBox(self)
|
||||
self.keyword_fix_count_input.setMinimum(1)
|
||||
self.keyword_fix_count_input.setMaximum(8)
|
||||
self.keyword_fix_count_input.setValue(3)
|
||||
self.keyword_fix_count_input.setToolTip("고정할 키워드 개수 (1~8)")
|
||||
self.keyword_fix_count_input.setFixedWidth(60)
|
||||
self.keyword_fix_count_input.valueChanged.connect(self.update_keyword_fix_count)
|
||||
self.keyword_fix_count_input.setEnabled(False)
|
||||
|
||||
# 가격초과제외 토글
|
||||
self.remove_overprice_toggle_label = QLabel("가격초과제외", self)
|
||||
self.remove_overprice_toggle = ToggleSwitch(self)
|
||||
self.remove_overprice_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('remove_overprice', checked))
|
||||
|
||||
# # 수정등록 모드 토글
|
||||
# self.ed_mode_toggle_label = QLabel("수정등록 모드", self)
|
||||
# self.ed_mode_toggle = ToggleSwitch(self)
|
||||
|
|
@ -1070,8 +1104,8 @@ class AutoPercentyGUI(QMainWindow):
|
|||
"""QSettings에 토글 상태 저장"""
|
||||
for key, value in self.toggle_states.items():
|
||||
self.settings.setValue(f"toggle/{key}", value)
|
||||
# 상태가 변경되었을 때 UI를 업데이트
|
||||
self.update_toggle_ui(key)
|
||||
# 각 토글 상태가 변경되었을 때 UI 업데이트
|
||||
self.update_toggle_ui(key)
|
||||
|
||||
def update_toggle_ui(self, key):
|
||||
"""토글 상태에 따라 UI 업데이트"""
|
||||
|
|
@ -1157,6 +1191,10 @@ class AutoPercentyGUI(QMainWindow):
|
|||
self.toggle_states['opacity_percent'] = value # 변경된 정수 값을 바로 저장
|
||||
self.logger.log(f"워터마크 투명도 업데이트: {self.toggle_states['opacity_percent']}", level=logging.DEBUG)
|
||||
|
||||
def update_keyword_fix_count(self, value):
|
||||
self.toggle_states['fixed_keywords_count'] = value
|
||||
self.logger.log(f"키워드 고정 개수 업데이트: {value}", level=logging.DEBUG)
|
||||
|
||||
def update_clientID(self, value):
|
||||
self.toggle_states['clientID'] = value # 변경된 정수 값을 바로 저장
|
||||
self.logger.log(f"clientID 업데이트: {self.toggle_states['clientID']}", level=logging.DEBUG)
|
||||
|
|
@ -1318,9 +1356,16 @@ class AutoPercentyGUI(QMainWindow):
|
|||
current_row += 1
|
||||
self.toggle_layout.addWidget(self.debug_toggle_label, current_row, 0)
|
||||
self.toggle_layout.addWidget(self.debug_toggle, current_row, 1)
|
||||
# self.toggle_layout.addWidget(self.ed_mode_toggle_label, current_row, 2)
|
||||
# self.toggle_layout.addWidget(self.ed_mode_toggle, current_row, 3)
|
||||
self.toggle_layout.addWidget(self.cat_rec_toggle_label, current_row, 2)
|
||||
self.toggle_layout.addWidget(self.cat_rec_toggle, current_row, 3)
|
||||
self.toggle_layout.addWidget(self.remove_overprice_toggle_label, current_row, 4)
|
||||
self.toggle_layout.addWidget(self.remove_overprice_toggle, current_row, 5)
|
||||
|
||||
current_row += 1
|
||||
self.toggle_layout.addWidget(self.keyword_fix_toggle_label, current_row, 0)
|
||||
self.toggle_layout.addWidget(self.keyword_fix_toggle, current_row, 1)
|
||||
self.toggle_layout.addWidget(self.keyword_fix_count_label, current_row, 2)
|
||||
self.toggle_layout.addWidget(self.keyword_fix_count_input, current_row, 3)
|
||||
|
||||
current_row += 1
|
||||
self.toggle_layout.addWidget(self.discord_notify_toggle_label, current_row, 0)
|
||||
|
|
@ -1403,6 +1448,8 @@ class AutoPercentyGUI(QMainWindow):
|
|||
# key에 따라 라벨 텍스트를 설정
|
||||
if key == 'title':
|
||||
label_text = self.title_toggle_label.text()
|
||||
elif key == 'title_trans_type':
|
||||
label_text = self.title_trans_type_toggle_label.text()
|
||||
elif key == 'optionTrnas':
|
||||
label_text = self.optionTrnas_toggle_label.text()
|
||||
elif key == 'optionIMGTrans':
|
||||
|
|
@ -1449,6 +1496,20 @@ class AutoPercentyGUI(QMainWindow):
|
|||
self.unwanted_words_button.setEnabled(False)
|
||||
QMessageBox.warning(self, "권한 부족", "이미지 글자 인식 기능은 VIP 이상 등급에서만 사용 가능합니다.")
|
||||
return
|
||||
elif key == 'cat_rec':
|
||||
# 카테 추천 토글
|
||||
label_text = self.cat_rec_toggle_label.text()
|
||||
elif key == 'fixed_keywords' or key == 'keyword_fix':
|
||||
# 키고정 토글
|
||||
label_text = self.keyword_fix_toggle_label.text()
|
||||
# 키고정 토글 상태에 따라 개수 입력 필드 활성화/비활성화
|
||||
self.keyword_fix_count_input.setEnabled(is_checked)
|
||||
# 키 이름이 'keyword_fix'로 들어온 경우 'fixed_keywords'로 저장
|
||||
if key == 'keyword_fix':
|
||||
self.toggle_states['fixed_keywords'] = is_checked
|
||||
elif key == 'remove_overprice':
|
||||
# 가격초과제외 토글
|
||||
label_text = self.remove_overprice_toggle_label.text()
|
||||
|
||||
# 이미지 번역 관련 토글이 하나라도 켜져 있으면 워터마크 토글 보이기
|
||||
if key in ['optionIMGTrans', 'detail_IMGTrans', 'thumb']:
|
||||
|
|
@ -1583,16 +1644,16 @@ class AutoPercentyGUI(QMainWindow):
|
|||
self.settings.setValue("opacity_percent", self.opacity_percent_input.value())
|
||||
self.settings.setValue("max_option_count", self.max_option_count_input.value())
|
||||
self.settings.setValue("thumb_rmb_count", self.thumb_rmb_count_input.value())
|
||||
|
||||
# self.settings.setValue("api/toggle", self.use_API_toggle.isChecked())
|
||||
# # API 필드 저장
|
||||
# if self.use_API_toggle.isChecked():
|
||||
# self.settings.setValue("api/client_id", self.client_id_input.text())
|
||||
# self.settings.setValue("api/client_secret", self.client_secret_input.text())
|
||||
|
||||
# 새로 추가된 토글 버튼 상태 저장
|
||||
self.settings.setValue("cat_rec", self.cat_rec_toggle.isChecked())
|
||||
self.settings.setValue("fixed_keywords", self.keyword_fix_toggle.isChecked())
|
||||
self.settings.setValue("fixed_keywords_count", self.keyword_fix_count_input.value())
|
||||
self.settings.setValue("remove_overprice", self.remove_overprice_toggle.isChecked())
|
||||
|
||||
self.settings.setValue("discord", self.discord_notify_toggle.isChecked())
|
||||
self.settings.setValue("discord_webhook", self.webhook_input.text())
|
||||
|
||||
self.settings.setValue("title_trans_type", self.title_trans_type_toggle.isChecked())
|
||||
|
||||
|
||||
def load_settings(self):
|
||||
|
|
@ -1615,29 +1676,37 @@ class AutoPercentyGUI(QMainWindow):
|
|||
self.thumb_rmb_count_input.setValue(self.settings.value("thumb_rmb_count", 0, type=int))
|
||||
self.toggle_states['thumb_rmb_count'] = int(self.thumb_rmb_count_input.text())
|
||||
|
||||
# 상품명 번역 타입 설정
|
||||
self.title_trans_type_toggle.setChecked(self.settings.value("title_trans_type", False, type=bool))
|
||||
self.toggle_states['title_trans_type'] = self.settings.value("title_trans_type", False, type=bool)
|
||||
|
||||
# 새로 추가된 토글 버튼 상태 불러오기
|
||||
cat_rec_state = self.settings.value("cat_rec", False, type=bool)
|
||||
self.cat_rec_toggle.setChecked(cat_rec_state)
|
||||
self.toggle_states['cat_rec'] = cat_rec_state
|
||||
|
||||
fixed_keywords_state = self.settings.value("fixed_keywords", False, type=bool)
|
||||
self.keyword_fix_toggle.setChecked(fixed_keywords_state)
|
||||
self.toggle_states['fixed_keywords'] = fixed_keywords_state
|
||||
|
||||
self.keyword_fix_count_input.setValue(self.settings.value("fixed_keywords_count", 2, type=int))
|
||||
self.toggle_states['fixed_keywords_count'] = int(self.keyword_fix_count_input.text())
|
||||
|
||||
remove_overprice_state = self.settings.value("remove_overprice", False, type=bool)
|
||||
self.remove_overprice_toggle.setChecked(remove_overprice_state)
|
||||
self.toggle_states['remove_overprice'] = remove_overprice_state
|
||||
|
||||
# 디스코드 설정 로드
|
||||
self.toggle_states['discord'] = self.settings.value("discord", False, type=bool)
|
||||
self.toggle_states['discord_webhook'] = self.settings.value("discord_webhook", "", type=str)
|
||||
|
||||
# UI 요소에 로드된 값 적용 (추가 필요)
|
||||
# UI 요소에 로드된 값 적용
|
||||
if hasattr(self, 'discord_notify_toggle'):
|
||||
self.discord_notify_toggle.setChecked(self.toggle_states['discord'])
|
||||
if hasattr(self, 'webhook_input'):
|
||||
self.webhook_input.setText(self.toggle_states['discord_webhook'])
|
||||
self.webhook_input.setVisible(self.toggle_states['discord'])
|
||||
|
||||
# # use_API 토글 상태 로드
|
||||
# api_toggle_state = self.settings.value("api/toggle", False, type=bool)
|
||||
# self.use_API_toggle.setChecked(api_toggle_state)
|
||||
|
||||
# self.on_toggle_clicked_generic('use_API', api_toggle_state)
|
||||
|
||||
# # API 필드 로드
|
||||
# self.client_id_input.setText(self.settings.value("api/client_id", "", type=str))
|
||||
# self.toggle_states['clientID'] = self.client_id_input.text()
|
||||
# self.client_secret_input.setText(self.settings.value("api/client_secret", "", type=str))
|
||||
# self.toggle_states['clientSecret'] = self.client_secret_input.text()
|
||||
|
||||
self.load_toggle_settings()
|
||||
|
||||
self.load_unwanted_words()
|
||||
|
|
@ -1648,6 +1717,7 @@ class AutoPercentyGUI(QMainWindow):
|
|||
try:
|
||||
# 토글 상태 읽기
|
||||
self.toggle_states['title'] = self.title_toggle.isChecked()
|
||||
self.toggle_states['title_trans_type'] = self.title_trans_type_toggle.isChecked()
|
||||
self.toggle_states['use_lens'] = self.use_lens_toggle.isChecked()
|
||||
self.toggle_states['ocr'] = self.ocr_toggle.isChecked()
|
||||
self.toggle_states['use_API'] = False # 항상 false로 해도 되는지 확인 필요
|
||||
|
|
@ -1667,6 +1737,9 @@ class AutoPercentyGUI(QMainWindow):
|
|||
# self.toggle_states['ed_mode'] = self.ed_mode_toggle.isChecked()
|
||||
self.toggle_states['discord'] = self.discord_notify_toggle.isChecked()
|
||||
self.toggle_states['watermark'] = self.watermark_toggle.isChecked()
|
||||
self.toggle_states['cat_rec'] = self.cat_rec_toggle.isChecked() # 카테 추천 토글 상태 저장
|
||||
self.toggle_states['fixed_keywords'] = self.keyword_fix_toggle.isChecked() # 키고정 토글 상태 저장
|
||||
self.toggle_states['remove_overprice'] = self.remove_overprice_toggle.isChecked() # 가격초과제외 토글 상태 저장
|
||||
|
||||
# 기타 설정 값들도 저장
|
||||
self.toggle_states['clientID'] = self.client_id_input.text() if hasattr(self, 'client_id_input') else ""
|
||||
|
|
@ -1677,6 +1750,7 @@ class AutoPercentyGUI(QMainWindow):
|
|||
self.toggle_states['max_option_count'] = int(self.max_option_count_input.text())
|
||||
self.toggle_states['opacity_percent'] = int(self.opacity_percent_input.text())
|
||||
self.toggle_states['group_index'] = self.group_selector.currentIndex()
|
||||
self.toggle_states['fixed_keywords_count'] = int(self.keyword_fix_count_input.text()) # 키고정 개수 저장
|
||||
|
||||
return self.toggle_states
|
||||
except Exception as e:
|
||||
|
|
|
|||
9
price.py
9
price.py
|
|
@ -7,7 +7,7 @@ import logging
|
|||
import asyncio
|
||||
|
||||
class PriceHandler:
|
||||
def __init__(self, locator_manager, browser_controller, logger, optionHandler, price_setting_diag, debug_flag=False):
|
||||
def __init__(self, locator_manager, browser_controller, logger, optionHandler, price_setting_diag, toggle_states, debug_flag=False):
|
||||
self.locator_manager = locator_manager
|
||||
self.browser_controller = browser_controller
|
||||
self.optionHandler = optionHandler
|
||||
|
|
@ -15,6 +15,7 @@ class PriceHandler:
|
|||
self.logger = logger
|
||||
self.debug_flag = debug_flag
|
||||
self.price_setting_diag = price_setting_diag
|
||||
self.toggle_states = toggle_states
|
||||
|
||||
self.price_config = self.price_setting_diag.get_price_setting()
|
||||
self.logger.log(f"Price configuration loaded: {self.price_config}", level=logging.DEBUG)
|
||||
|
|
@ -186,8 +187,10 @@ class PriceHandler:
|
|||
self.logger.log(f"반품비: {return_fee}, 초도배송비: {first_delv_fee}, 교환비: {exchange_fee}", level=logging.DEBUG)
|
||||
await self.input_claim_costs(return_fee, first_delv_fee, exchange_fee)
|
||||
|
||||
# 7. 가격범위 초과 제외
|
||||
await self.click_remove_overprice_btn()
|
||||
# 7. 가격범위 초과 제외 - remove_overprice 토글 상태에 따라 실행
|
||||
if self.toggle_states.get('remove_overprice', False):
|
||||
await self.click_remove_overprice_btn()
|
||||
self.logger.log("가격범위 초과 옵션 제외 처리 완료", level=logging.INFO)
|
||||
|
||||
# 8. 저장
|
||||
# save_xpath = "//button[contains(.,'저장하기')]"
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
||||
179
src/whale_new.py
179
src/whale_new.py
|
|
@ -177,47 +177,58 @@ class WhaleTranslator:
|
|||
|
||||
|
||||
def start_trans_browser(self):
|
||||
try:
|
||||
self.modify_preferences_for_incognito()
|
||||
|
||||
self.modify_preferences_for_incognito()
|
||||
base_path = self.get_base_dir()
|
||||
self.whale_exe_path = os.path.join(base_path, "browsers", "whale", "whale.exe")
|
||||
self.user_data_dir = os.path.join(base_path, "browsers", "whale", "user_data")
|
||||
cache_dir = os.path.join(base_path, "browsers", "whale", "cache")
|
||||
extension_path = os.path.join(base_path, "browsers", "whale", "extensions", "gadfmnjdnhkncfcibhfleoojcdimdcbd", "1.1.11_0")
|
||||
|
||||
base_path = self.get_base_dir()
|
||||
self.whale_exe_path = os.path.join(base_path, "browsers", "whale", "whale.exe")
|
||||
self.user_data_dir = os.path.join(base_path, "browsers", "whale", "user_data")
|
||||
cache_dir = os.path.join(base_path, "browsers", "whale", "cache")
|
||||
extension_path = os.path.join(base_path, "browsers", "whale", "extensions", "gadfmnjdnhkncfcibhfleoojcdimdcbd", "1.1.11_0")
|
||||
self.logger.log(f"웨일 경로 설정 : {self.whale_exe_path}", level=logging.DEBUG)
|
||||
self.logger.log(f"웨일 경로 설정 : {self.user_data_dir}", level=logging.DEBUG)
|
||||
self.logger.log(f"웨일 경로 설정 : {cache_dir}", level=logging.DEBUG)
|
||||
self.logger.log(f"웨일 경로 설정 : {extension_path}", level=logging.DEBUG)
|
||||
|
||||
self.logger.log(f"웨일 경로 설정 : {self.whale_exe_path}", level=logging.DEBUG)
|
||||
self.logger.log(f"웨일 경로 설정 : {self.user_data_dir}", level=logging.DEBUG)
|
||||
self.logger.log(f"웨일 경로 설정 : {cache_dir}", level=logging.DEBUG)
|
||||
self.logger.log(f"웨일 경로 설정 : {extension_path}", level=logging.DEBUG)
|
||||
# 경로 존재 확인
|
||||
if not os.path.exists(self.whale_exe_path):
|
||||
self.logger.log(f"웨일 브라우저 실행 파일이 존재하지 않습니다: {self.whale_exe_path}", level=logging.ERROR)
|
||||
return None
|
||||
|
||||
if self.whale_incognito:
|
||||
# 시크릿 모드로 실행
|
||||
self.logger.log("웨일 시크릿 모드로 시작합니다.", level=logging.INFO)
|
||||
self.whale_app = Application(backend="uia").start(
|
||||
f'"{self.whale_exe_path}" '
|
||||
f'--incognito '
|
||||
f'--user-data-dir="{self.user_data_dir}" --disk-cache-dir="{cache_dir}" '
|
||||
f'--load-extension="{extension_path}" '
|
||||
f'--window-size=1280,720 --window-position=1,1'
|
||||
)
|
||||
else:
|
||||
# 일반 모드로 실행
|
||||
self.logger.log("웨일 일반 모드로 시작합니다.", level=logging.INFO)
|
||||
self.whale_app = Application(backend="uia").start(
|
||||
f'"{self.whale_exe_path}" '
|
||||
f'--user-data-dir="{self.user_data_dir}" --disk-cache-dir="{cache_dir}" '
|
||||
f'--load-extension="{extension_path}" '
|
||||
f'--window-size=1280,720 --window-position=1,1'
|
||||
)
|
||||
|
||||
# 창이 완전히 생성될 때까지 대기
|
||||
self.whale_window = self.find_trans_window()
|
||||
if self.whale_incognito:
|
||||
# 시크릿 모드로 실행
|
||||
self.logger.log("웨일 시크릿 모드로 시작합니다.", level=logging.INFO)
|
||||
self.whale_app = Application(backend="uia").start(
|
||||
f'"{self.whale_exe_path}" '
|
||||
f'--incognito '
|
||||
f'--user-data-dir="{self.user_data_dir}" --disk-cache-dir="{cache_dir}" '
|
||||
f'--load-extension="{extension_path}" '
|
||||
f'--window-size=1280,720 --window-position=1,1'
|
||||
)
|
||||
else:
|
||||
# 일반 모드로 실행
|
||||
self.logger.log("웨일 일반 모드로 시작합니다.", level=logging.INFO)
|
||||
self.whale_app = Application(backend="uia").start(
|
||||
f'"{self.whale_exe_path}" '
|
||||
f'--user-data-dir="{self.user_data_dir}" --disk-cache-dir="{cache_dir}" '
|
||||
f'--load-extension="{extension_path}" '
|
||||
f'--window-size=1280,720 --window-position=1,1'
|
||||
)
|
||||
|
||||
# 창이 완전히 생성될 때까지 대기
|
||||
self.whale_window = self.find_trans_window()
|
||||
|
||||
if self.whale_window:
|
||||
self.logger.log("웨일 시작 완료.", level=logging.INFO)
|
||||
else:
|
||||
self.logger.log("웨일 창을 찾을 수 없습니다.", level=logging.WARNING)
|
||||
if self.whale_window:
|
||||
self.logger.log("웨일 시작 완료.", level=logging.INFO)
|
||||
else:
|
||||
self.logger.log("웨일 창을 찾을 수 없습니다.", level=logging.WARNING)
|
||||
|
||||
return self.whale_window
|
||||
|
||||
except Exception as e:
|
||||
self.logger.log(f"웨일 브라우저 시작 중 예외 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
|
@ -225,15 +236,35 @@ class WhaleTranslator:
|
|||
try:
|
||||
if self.whale_incognito:
|
||||
# 시크릿 모드인 경우 창 이름이 '새 시크릿 탭 - Whale'로 시작
|
||||
target_names = '새 시크릿 탭 - Whale'
|
||||
target_names = ['새 시크릿 탭 - Whale']
|
||||
else:
|
||||
# 일반 모드인 경우, 창 이름이 "새 탭 - Whale" 또는 "네이버 웨일에 오신 것을 환영합니다 - Whale"일 수 있음
|
||||
target_names = ['새 탭 - Whale', '네이버 웨일에 오신 것을 환영합니다 - Whale']
|
||||
|
||||
self.logger.log(f"찾을 웨일 창 이름 패턴: {target_names}", level=logging.DEBUG)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 최대 10초 동안 원하는 창 이름이 나타나기를 기다림
|
||||
# ✅ 수정된 조건: `startswith()`로 비교하여 창 이름이 원하는 값 중 하나로 시작하면 OK
|
||||
timings.wait_until(10, 0.5, lambda: any(any(window.name.startswith(name) for name in target_names) for window in findwindows.find_elements()))
|
||||
try:
|
||||
# ✅ 수정된 조건: `startswith()`로 비교하여 창 이름이 원하는 값 중 하나로 시작하면 OK
|
||||
timings.wait_until(10, 0.5, lambda: any(
|
||||
any(window.name.startswith(name) for name in target_names)
|
||||
for window in findwindows.find_elements()
|
||||
))
|
||||
except TimeoutError:
|
||||
self.logger.log(f"10초 내에 웨일 창을 찾지 못했습니다. 대상 창 이름: {target_names}", level=logging.ERROR)
|
||||
|
||||
# 현재 존재하는 모든 창 로깅
|
||||
all_windows = findwindows.find_elements()
|
||||
if all_windows:
|
||||
self.logger.log("현재 존재하는 창 목록:", level=logging.DEBUG)
|
||||
for idx, window in enumerate(all_windows):
|
||||
self.logger.log(f" {idx+1}. {window.name} (PID: {window.process_id})", level=logging.DEBUG)
|
||||
else:
|
||||
self.logger.log("시스템에 표시 가능한 창이 없습니다.", level=logging.DEBUG)
|
||||
|
||||
return None
|
||||
|
||||
windows = findwindows.find_elements()
|
||||
for window in windows:
|
||||
|
|
@ -243,13 +274,17 @@ class WhaleTranslator:
|
|||
self.whale_window = self.whale_app.top_window()
|
||||
|
||||
# 위치 및 크기 조절
|
||||
self.hwnd_wrapper = HwndWrapper(self.whale_window.handle)
|
||||
self.hwnd_wrapper.move_window(x=1, y=1, width=1280, height=720)
|
||||
self.whale_window.set_focus()
|
||||
try:
|
||||
self.hwnd_wrapper = HwndWrapper(self.whale_window.handle)
|
||||
self.hwnd_wrapper.move_window(x=1, y=1, width=1280, height=720)
|
||||
self.whale_window.set_focus()
|
||||
except Exception as e:
|
||||
self.logger.log(f"창 위치 및 크기 조절 중 오류: {e}. 계속 진행합니다.", level=logging.WARNING)
|
||||
|
||||
self.logger.log(f"웨일 창을 성공적으로 찾았습니다. (창 이름: {window.name})", level=logging.INFO)
|
||||
return self.whale_window
|
||||
self.logger.log("대상 창을 찾지 못했습니다.", level=logging.ERROR)
|
||||
|
||||
self.logger.log(f"대상 창 이름({target_names})과 일치하는 창을 찾지 못했습니다.", level=logging.ERROR)
|
||||
except Exception as e:
|
||||
self.logger.log(f"웨일 창 탐색 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
return None
|
||||
|
|
@ -833,24 +868,52 @@ class WhaleTranslator:
|
|||
|
||||
def close_trans_browser(self):
|
||||
try:
|
||||
if self.whale_window:
|
||||
if not self.whale_window or not self.whale_app:
|
||||
self.logger.log("웨일 브라우저가 실행되지 않았거나 이미 종료되었습니다.", level=logging.INFO)
|
||||
return
|
||||
|
||||
# 프로세스 ID 확인
|
||||
try:
|
||||
pid = self.whale_app.process
|
||||
# self.whale_app.send_keys("{VK_MENU}{F4}")
|
||||
self.logger.log(f"종료할 웨일 브라우저 프로세스 ID: {pid}", level=logging.DEBUG)
|
||||
except Exception as e:
|
||||
self.logger.log(f"프로세스 ID 확인 중 오류: {e}. 강제 종료를 시도합니다.", level=logging.WARNING)
|
||||
try:
|
||||
if hasattr(self.whale_app, 'kill'):
|
||||
self.whale_app.kill()
|
||||
return
|
||||
except Exception as e2:
|
||||
self.logger.log(f"강제 종료 시도 중 오류: {e2}", level=logging.ERROR)
|
||||
return
|
||||
|
||||
# Alt+F4 키를 전송하여 창 닫기 시도
|
||||
try:
|
||||
self.whale_window.type_keys("%{F4}") # Alt-F4
|
||||
|
||||
self.logger.log("trans Browser 창 종료 명령 전송됨.", level=logging.INFO)
|
||||
self.logger.log("웨일 브라우저 창 종료 명령(Alt+F4) 전송됨.", level=logging.INFO)
|
||||
except Exception as e:
|
||||
self.logger.log(f"Alt+F4 키 전송 중 오류: {e}. 다른 방법으로 종료를 시도합니다.", level=logging.WARNING)
|
||||
|
||||
# 0.2초 간격으로 최대 2초 동안 프로세스 종료 확인
|
||||
for _ in range(10): # 10 * 0.2 = 2초
|
||||
if not psutil.pid_exists(pid):
|
||||
self.logger.log(f"trans Browser 프로세스 {pid} 정상 종료됨.", level=logging.INFO)
|
||||
return
|
||||
time.sleep(0.2)
|
||||
|
||||
# 여전히 프로세스가 존재하면 강제 종료
|
||||
if psutil.pid_exists(pid):
|
||||
# 0.2초 간격으로 최대 2초 동안 프로세스 종료 확인
|
||||
for i in range(10): # 10 * 0.2 = 2초
|
||||
if not psutil.pid_exists(pid):
|
||||
self.logger.log(f"웨일 브라우저 프로세스 {pid}가 정상적으로 종료되었습니다. (시도 {i+1}/10)", level=logging.INFO)
|
||||
# 클래스 변수 초기화
|
||||
self.whale_app = None
|
||||
self.whale_window = None
|
||||
return
|
||||
time.sleep(0.2)
|
||||
|
||||
# 여전히 프로세스가 존재하면 강제 종료
|
||||
if psutil.pid_exists(pid):
|
||||
self.logger.log(f"웨일 브라우저 프로세스 {pid}가 여전히 실행 중입니다. 강제 종료를 시도합니다.", level=logging.WARNING)
|
||||
try:
|
||||
self.whale_app.kill()
|
||||
self.logger.log(f"trans Browser 프로세스 {pid} 강제 종료됨.", level=logging.INFO)
|
||||
self.logger.log(f"웨일 브라우저 프로세스 {pid}를 강제 종료했습니다.", level=logging.INFO)
|
||||
# 클래스 변수 초기화
|
||||
self.whale_app = None
|
||||
self.whale_window = None
|
||||
except Exception as e:
|
||||
self.logger.log(f"강제 종료 시도 중 오류: {e}", level=logging.ERROR, exc_info=True)
|
||||
except Exception as e:
|
||||
self.logger.log(f"trans Browser 종료 오류: {e}", level=logging.ERROR, exc_info=True)
|
||||
self.logger.log(f"웨일 브라우저 종료 중 예기치 않은 오류: {e}", level=logging.ERROR, exc_info=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
from translatepy import Translator
|
||||
import sys
|
||||
from translatepy.translators.google import GoogleTranslate
|
||||
|
||||
print("Python 버전:", sys.version)
|
||||
print("translatepy 모듈 불러오기 성공")
|
||||
|
||||
# 번역기 초기화
|
||||
try:
|
||||
translator = Translator()
|
||||
print("번역기 초기화 성공")
|
||||
except Exception as e:
|
||||
print(f"번역기 초기화 실패: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 테스트할 중국어 텍스트
|
||||
chinese_text = "你好,我是一个翻译测试"
|
||||
print(f"원본 중국어: {chinese_text}")
|
||||
|
||||
try:
|
||||
print("번역 시작...")
|
||||
# 중국어에서 한국어로 번역
|
||||
result = translator.translate(chinese_text, "zh", "ko")
|
||||
|
||||
gtranslate = GoogleTranslate()
|
||||
r = gtranslate.translate(chinese_text, "ko")
|
||||
print(f"번역 결과: {r}")
|
||||
|
||||
|
||||
# 결과 출력
|
||||
print(f"번역 결과: {result}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"번역 중 오류 발생: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
print("테스트 완료")
|
||||
|
|
@ -5,6 +5,8 @@ import random
|
|||
import json
|
||||
from collections import OrderedDict
|
||||
from translatepy import Translator
|
||||
from translatepy.translators.google import GoogleTranslate
|
||||
|
||||
from titleManager.gpt_client import GPTClient
|
||||
# from titleManager.mongoDBManager import MongoDBManager
|
||||
from titleManager.forbiddenWD_Manager import ForbiddenWordManager
|
||||
|
|
@ -39,8 +41,8 @@ class TitleGenerator:
|
|||
self.naverAPI = NaverSearchAPI(client_id=client_id, client_secret=client_secret, logger=self.logger)
|
||||
self.kipris_api = Kipris_API(logger, apikey='X9Tz3JqC/JcCwxnNewA6qdloIN6QFIitVBgS1a2KVDYk1AmddaDTvzr6+t3dyLZV3gh2TPXdNhxsRQwaKP673Q==')
|
||||
self.gpt_client = gpt_client
|
||||
self.translator = Translator() # 번역 라이브러리 초기화
|
||||
|
||||
# self.translator = Translator() # 번역 라이브러리 초기화
|
||||
self.gtranslate = GoogleTranslate()
|
||||
# 선택자 로드
|
||||
self.product_main_image_locator = self.locator_manager.get_locator('TitleLocators', 'product_main_image_locator')
|
||||
self.product_name_input_locator = self.locator_manager.get_locator('TitleLocators', 'product_name_input_locator')
|
||||
|
|
@ -105,12 +107,11 @@ class TitleGenerator:
|
|||
self.parsing_page = parsing_page
|
||||
self.logger.log(f"paparsing_pagege객체 업데이트 : {parsing_page}", level=logging.DEBUG)
|
||||
|
||||
def translate_product_name_ori(self, original_name: str) -> str:
|
||||
def translate_product_name_from_google(self, original_name: str) -> str:
|
||||
"""텍스트를 한국어로 번역하는 메서드"""
|
||||
try:
|
||||
translated_name = self.translator.translate(original_name, 'zh', 'ko')
|
||||
|
||||
return translated_name.result if translated_name else original_name
|
||||
translated_name = self.gtranslate.translate(original_name, 'ko')
|
||||
return translated_name
|
||||
except Exception as e:
|
||||
self.logger.log(f"번역 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
return original_name
|
||||
|
|
@ -256,10 +257,16 @@ class TitleGenerator:
|
|||
prefix += "/"
|
||||
return prefix + title
|
||||
|
||||
def generate_product_title(self, original_name: str, keyword_name: str, search_result: dict, product_category: str) -> str:
|
||||
def generate_product_title(self, trans_type: bool, original_name: str, keyword_name: str, search_result: dict, product_category: str) -> str:
|
||||
"""상품명을 생성하는 메서드"""
|
||||
# 1. 원본 상품명 번역
|
||||
translated_name = self.translate_product_name(original_name)
|
||||
if trans_type:
|
||||
self.logger.log(f'trans_type : {trans_type}, 구글 번역 사용', level=logging.INFO)
|
||||
translated_name = self.translate_product_name_from_google(original_name)
|
||||
else:
|
||||
self.logger.log(f'trans_type : {trans_type}, GPT 번역 사용', level=logging.INFO)
|
||||
translated_name = self.translate_product_name(original_name)
|
||||
|
||||
self.logger.log(f'translated_name : {translated_name}', level=logging.DEBUG)
|
||||
|
||||
# 2. 검색 결과에서 제목과 가격 가져오기
|
||||
|
|
@ -281,9 +288,16 @@ class TitleGenerator:
|
|||
# 3. 검색된 제목 필터링
|
||||
filtered_top_titles = self.process_top_titles(top_titles)
|
||||
|
||||
# 3. 키워드 상품명에서 첫 4개 키워드 추출
|
||||
essential_keywords = keyword_name.split()[:4]
|
||||
self.logger.log(f'essential_keywords (첫 4개 키워드): {essential_keywords}', level=logging.DEBUG)
|
||||
# 3. 키워드 상품명에서 키워드 추출 - 키고정 토글 상태에 따라 추출 개수 조정
|
||||
if self.toggle_states.get('fixed_keywords', False):
|
||||
# 키고정 활성화: fixed_keywords_count 개수만큼 키워드 추출
|
||||
fixed_count = self.toggle_states.get('fixed_keywords_count', 3)
|
||||
essential_keywords = keyword_name.split()[:fixed_count]
|
||||
self.logger.log(f'essential_keywords (키고정 {fixed_count}개): {essential_keywords}', level=logging.DEBUG)
|
||||
else:
|
||||
# 기본값: 첫 4개 키워드 추출
|
||||
essential_keywords = keyword_name.split()[:4]
|
||||
self.logger.log(f'essential_keywords (첫 4개 키워드): {essential_keywords}', level=logging.DEBUG)
|
||||
|
||||
keyword_title = list(set(
|
||||
word for title in [keyword_name] + filtered_top_titles
|
||||
|
|
@ -313,22 +327,40 @@ class TitleGenerator:
|
|||
keyword_title = [word for word in keyword_title if not self.forbidden_word_manager.is_word_forbidden(word)]
|
||||
self.logger.log(f'keyword_title after forbidden filter : {keyword_title}', level=logging.DEBUG)
|
||||
|
||||
self.title_generator_prompt
|
||||
self.logger.log(f'self.title_generator_prompt : {self.title_generator_prompt}', level=logging.DEBUG)
|
||||
|
||||
# 12. 최종 상품명 생성 (GPT Client 이용)
|
||||
product_title = self.gpt_client.generate_product_name_next(
|
||||
words=keyword_title, original_name=original_name, top_titles=top_titles, category=product_category, title_generator_prompt=self.title_generator_prompt
|
||||
# 상품명 생성 결과
|
||||
prompt = self.title_generator_prompt.format(
|
||||
title_keywords=', '.join(keyword_title),
|
||||
category=product_category
|
||||
)
|
||||
self.logger.log(f'final product_title: {product_title}', level=logging.DEBUG)
|
||||
self.logger.log(f'GPT에 전달할 Prompt : {prompt}', level=logging.DEBUG)
|
||||
|
||||
if not product_title:
|
||||
product_title = keyword_title.append(' '.join(keyword_title))
|
||||
self.logger.log(f'because product_title is None, final product_title: {product_title}', level=logging.DEBUG)
|
||||
|
||||
# 13. 만약 "금지" 등급 단어가 있었다면 접두어 추가 (해당 단어도 함께 표기)
|
||||
# gpt client에 상품명 생성 요청
|
||||
product_title = self.gpt_client.generate_product_name(prompt, category=product_category)
|
||||
self.logger.log(f'GPT 생성 상품명 : {product_title}', level=logging.DEBUG)
|
||||
|
||||
# 키고정 활성화 시 essential_keywords를 접두어로 추가하고 중복 제거
|
||||
if self.toggle_states.get('fixed_keywords', False) and essential_keywords:
|
||||
# essential_keywords를 문자열로 변환
|
||||
essential_prefix = ' '.join(essential_keywords)
|
||||
|
||||
# 접두어와 상품명에서 중복 단어 제거
|
||||
product_words = product_title.split()
|
||||
|
||||
# 중복 단어를 제거한 최종 상품명 생성
|
||||
# 접두어에 있는 단어가 상품명에 있으면 상품명에서 해당 단어 제거
|
||||
filtered_product_words = [word for word in product_words
|
||||
if word not in essential_keywords]
|
||||
|
||||
# 중복이 제거된 최종 상품명
|
||||
final_title = f"{essential_prefix} {' '.join(filtered_product_words)}"
|
||||
self.logger.log(f'접두어 추가 및 중복 제거 후 최종 상품명: {final_title}', level=logging.DEBUG)
|
||||
product_title = final_title
|
||||
|
||||
# 금지상품이면 접두어를 붙임
|
||||
if forbidden_grade_words:
|
||||
product_title = self.add_forbidden_prefix(product_title, forbidden_grade_words)
|
||||
self.logger.log(f'금지어 접두어 추가 후 최종 상품명: {product_title}', level=logging.DEBUG)
|
||||
|
||||
return product_title
|
||||
|
||||
|
||||
|
|
@ -617,7 +649,7 @@ class TitleGenerator:
|
|||
# ]
|
||||
|
||||
# 6. 상품명 생성
|
||||
product_title = self.generate_product_title(original_name=self.title_infos["original_name"], keyword_name=self.title_infos["keyword_name"], search_result=self.title_infos["search_result"], product_category=self.title_infos["category"])
|
||||
product_title = self.generate_product_title(trans_type=self.title_infos["title_trans_type"], original_name=self.title_infos["original_name"], keyword_name=self.title_infos["keyword_name"], search_result=self.title_infos["search_result"], product_category=self.title_infos["category"])
|
||||
if product_title == "관련성이 없는 상품 - 체크필요":
|
||||
return
|
||||
|
||||
|
|
@ -633,7 +665,10 @@ class TitleGenerator:
|
|||
# 8. 상품명 설정
|
||||
is_success = await self.set_product_name(product_title)
|
||||
|
||||
await self.click_cat_rec_btn()
|
||||
# cat_rec 토글이 켜져 있을 때만 카테고리 추천 버튼 클릭
|
||||
if self.toggle_states.get('cat_rec', False):
|
||||
await self.click_cat_rec_btn()
|
||||
self.logger.log("카테고리 추천 버튼을 클릭했습니다.", level=logging.INFO)
|
||||
|
||||
if is_success:
|
||||
self.logger.log("상품명 생성 및 설정 성공", level=logging.INFO)
|
||||
|
|
@ -872,105 +907,6 @@ class TitleGenerator:
|
|||
|
||||
|
||||
|
||||
# async def get_category(self) -> dict:
|
||||
# """
|
||||
# 스마트스토어의 카테고리 정보를 가져오고,
|
||||
# '상품정보제공고시' 요소의 위치에 따라 인증 및 그룹상품 여부를 판단합니다.
|
||||
|
||||
# Returns:
|
||||
# dict: {
|
||||
# "category_text_ss": <텍스트>,
|
||||
# "category_text_esm": <텍스트>,
|
||||
# "is_certified_ss": <True/False>,
|
||||
# "is_group_esm": <True/False>
|
||||
# }
|
||||
# """
|
||||
# try:
|
||||
# category_data = {
|
||||
# "category_text_ss": "",
|
||||
# "category_text_esm": "",
|
||||
# "is_certified_ss": False,
|
||||
# "is_group_esm": False,
|
||||
# }
|
||||
|
||||
# # 1. '상품정보제공고시' 요소의 위치를 확인하여 오프셋 계산
|
||||
# found_index = None
|
||||
# for idx in [5, 6, 7]:
|
||||
# locator = f"div#productMainContentContainerId div:nth-child({idx}) > div > div > div.ant-row.ant-row-middle.css-1li46mu > div:nth-child(1) > span"
|
||||
# try:
|
||||
# await self.page.wait_for_selector(locator, timeout=2000, state="attached")
|
||||
# info_element = self.page.locator(locator)
|
||||
# text = await info_element.inner_text()
|
||||
# if "상품정보제공고시" in text:
|
||||
# found_index = idx
|
||||
# self.logger.log(f"'상품정보제공고시' 요소가 nth-child {idx}에서 확인됨.", level=logging.DEBUG)
|
||||
# break
|
||||
# except Exception:
|
||||
# continue
|
||||
# if not found_index:
|
||||
# found_index = 5
|
||||
# self.logger.log("상품정보제공고시 요소를 찾지 못해 기본값(nth-child 5)을 사용합니다.", level=logging.WARNING)
|
||||
# offset = found_index - 5 # offset: 0, 1, 또는 2
|
||||
|
||||
# # 2. 마켓별 카테고리 선택자 동적 조정
|
||||
# # 기본: SS는 nth-child 8, ESM은 nth-child 9, 여기에 offset을 더함.
|
||||
# base_ss = 8 + offset
|
||||
# base_esm = 9 + offset
|
||||
|
||||
# ss_selector = f"div#productMainContentContainerId div:nth-child({base_ss}) > div > div > div.ant-row.ant-row-no-wrap.ant-row-bottom.css-1li46mu > div:nth-child(1) > div > div > span.ant-select-selection-item > div > div"
|
||||
# esm_selector = f"div#productMainContentContainerId div:nth-child({base_esm}) > div > div > div.ant-row.ant-row-no-wrap.ant-row-bottom.css-1li46mu > div:nth-child(1) > div > div > span.ant-select-selection-item > div > div"
|
||||
|
||||
# self.logger.log(f"SS의 동적 카테고리 선택자: {ss_selector}", level=logging.DEBUG)
|
||||
# self.logger.log(f"ESM의 동적 카테고리 선택자: {esm_selector}", level=logging.DEBUG)
|
||||
|
||||
# # 3. SS 카테고리 텍스트 추출
|
||||
# await self.page.wait_for_selector(ss_selector, timeout=5000, state="attached")
|
||||
# ss_element = self.page.locator(ss_selector)
|
||||
# count_ss = await ss_element.count()
|
||||
# if count_ss > 1:
|
||||
# # 인증 요소 등이 포함되어 있으므로 두 번째 요소에서 실제 텍스트 추출
|
||||
# category_text_ss = await ss_element.nth(1).inner_text()
|
||||
# self.logger.log("SS: 인증 요소 포함되어 있어 두 번째 요소에서 카테고리 텍스트 추출.", level=logging.DEBUG)
|
||||
# category_data["is_certified_ss"] = True
|
||||
# elif count_ss == 1:
|
||||
# category_text_ss = await ss_element.inner_text()
|
||||
# else:
|
||||
# self.logger.log("SS의 카테고리 텍스트 요소를 찾을 수 없습니다.", level=logging.ERROR)
|
||||
# category_text_ss = ""
|
||||
# category_data["category_text_ss"] = category_text_ss.strip()
|
||||
|
||||
# # 4. ESM 카테고리 텍스트 추출
|
||||
# await self.page.wait_for_selector(esm_selector, timeout=5000, state="attached")
|
||||
# esm_element = self.page.locator(esm_selector)
|
||||
# count_esm = await esm_element.count()
|
||||
# if count_esm > 1:
|
||||
# # 그룹상품 요소가 포함되어 있는 경우: 두 번째 요소에서 실제 텍스트 추출
|
||||
# category_text_esm = await esm_element.nth(1).inner_text()
|
||||
# self.logger.log("ESM: 그룹상품 요소 포함되어 있어 두 번째 요소에서 카테고리 텍스트 추출.", level=logging.DEBUG)
|
||||
# category_data["is_group_esm"] = True
|
||||
# elif count_esm == 1:
|
||||
# category_text_esm = await esm_element.inner_text()
|
||||
# else:
|
||||
# self.logger.log("ESM의 카테고리 텍스트 요소를 찾을 수 없습니다.", level=logging.ERROR)
|
||||
# category_text_esm = ""
|
||||
# category_data["category_text_esm"] = category_text_esm.strip()
|
||||
|
||||
# return category_data
|
||||
|
||||
# except Exception as e:
|
||||
# self.logger.log(f"카테고리 텍스트 가져오기 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
# return {
|
||||
# "category_text_ss": "",
|
||||
# "category_text_esm": "",
|
||||
# "is_certified_ss": False,
|
||||
# "is_group_esm": False,
|
||||
# }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async def get_category(self) -> dict:
|
||||
"""
|
||||
스마트스토어의 카테고리 정보를 가져오고,
|
||||
|
|
@ -997,7 +933,7 @@ class TitleGenerator:
|
|||
"is_group_esm": False,
|
||||
}
|
||||
|
||||
# 1. '상품정보제공고시' 기준 요소의 선택자를 config.ini에서 가져옴
|
||||
# 1. '상품정보제공고시' 요소의 위치를 확인하여 오프셋 계산
|
||||
|
||||
self.logger.log(f"기준 선택자(상품정보제공고시): {self.consumer_product_informartion_disclosure_locator}", level=logging.DEBUG)
|
||||
|
||||
|
|
@ -1058,7 +994,7 @@ class TitleGenerator:
|
|||
esm_element = self.page.locator(esm_selector)
|
||||
count_esm = await esm_element.count()
|
||||
if count_esm > 1:
|
||||
# 요소 2개 이상이면 첫 번째는 그룹상품 태그, 두 번째가 실제 텍스트
|
||||
# 그룹상품 요소가 포함되어 있는 경우: 두 번째 요소에서 실제 텍스트 추출
|
||||
category_text_esm = await esm_element.nth(1).inner_text()
|
||||
self.logger.log("ESM: 그룹상품 요소 포함되어 있어 두 번째 요소에서 카테고리 텍스트 추출.", level=logging.DEBUG)
|
||||
category_data["is_group_esm"] = True
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue