브라우저 컨트롤러에서 메모 입력 재시도 로직을 주석 처리하고, ESC 키 전송 후 팝업 제거 시도 로직을 개선. 로거 모듈에서 커스텀 롤오버 핸들러를 수정하여 로그 파일 이름 형식을 변경하고, 백업 파일 관리 로직을 개선. 이미지 프로세서에서 이미지 처리 로직을 수정하여 누끼 실패 시 번역으로 백업하도록 변경.
This commit is contained in:
parent
f1f019901e
commit
50da369e14
|
|
@ -2901,96 +2901,96 @@ class BrowserController(QThread):
|
|||
self.logger.log(f"메모 입력 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
|
||||
# ESC 키 2번 전송하여 팝업 제거 시도
|
||||
self.logger.log("ESC 키를 2번 전송하여 팝업 제거 후 메모 입력 재시도합니다.", level=logging.WARNING)
|
||||
# self.logger.log("ESC 키를 2번 전송하여 팝업 제거 후 메모 입력 재시도합니다.", level=logging.WARNING)
|
||||
await self.page.keyboard.press("Escape")
|
||||
await self.page.keyboard.press("Escape")
|
||||
await asyncio.sleep(0.5) # 잠시 대기
|
||||
|
||||
# 메모 입력 재시도
|
||||
try:
|
||||
await memo_button.click()
|
||||
self.logger.log("재시도: 메모 버튼을 클릭했습니다.", level=logging.DEBUG)
|
||||
memo_input = self.page.locator(self.memo_input_locator)
|
||||
await memo_input.wait_for(state="visible")
|
||||
self.logger.log("재시도: 메모 입력란 대기 완료", level=logging.DEBUG)
|
||||
# # 메모 입력 재시도
|
||||
# try:
|
||||
# await memo_button.click()
|
||||
# self.logger.log("재시도: 메모 버튼을 클릭했습니다.", level=logging.DEBUG)
|
||||
# memo_input = self.page.locator(self.memo_input_locator)
|
||||
# await memo_input.wait_for(state="visible")
|
||||
# self.logger.log("재시도: 메모 입력란 대기 완료", level=logging.DEBUG)
|
||||
|
||||
# 5. 기존 메모 읽어오기
|
||||
existing = await memo_input.input_value()
|
||||
combined = existing.strip()
|
||||
# # 5. 기존 메모 읽어오기
|
||||
# existing = await memo_input.input_value()
|
||||
# combined = existing.strip()
|
||||
|
||||
# 6. 새 메모 조합
|
||||
suffix = "\n" + "-"*10 + "\n" + f"수집방법:[{collect_method}]\n"
|
||||
if combined:
|
||||
if is_new_memo_first:
|
||||
combined = new_memo + suffix + combined
|
||||
else:
|
||||
combined = combined + suffix + new_memo
|
||||
else:
|
||||
combined = f"수집방법:[{collect_method}]\n" + new_memo
|
||||
# # 6. 새 메모 조합
|
||||
# suffix = "\n" + "-"*10 + "\n" + f"수집방법:[{collect_method}]\n"
|
||||
# if combined:
|
||||
# if is_new_memo_first:
|
||||
# combined = new_memo + suffix + combined
|
||||
# else:
|
||||
# combined = combined + suffix + new_memo
|
||||
# else:
|
||||
# combined = f"수집방법:[{collect_method}]\n" + new_memo
|
||||
|
||||
# 7. 길이 제한 (2000자)
|
||||
if len(combined) > 2000:
|
||||
combined = combined[:2000]
|
||||
# # 7. 길이 제한 (2000자)
|
||||
# if len(combined) > 2000:
|
||||
# combined = combined[:2000]
|
||||
|
||||
# 8. 채우기
|
||||
await memo_input.fill(combined)
|
||||
self.logger.log(f"재시도: 메모 입력: {combined!r}", level=logging.DEBUG)
|
||||
# # 8. 채우기
|
||||
# await memo_input.fill(combined)
|
||||
# self.logger.log(f"재시도: 메모 입력: {combined!r}", level=logging.DEBUG)
|
||||
|
||||
# 9. 노출 체크박스 처리
|
||||
# chk = self.page.locator(
|
||||
# 'label:has-text("상품 목록에 메모 내용 노출하기") '
|
||||
# 'input[type="checkbox"]'
|
||||
# )
|
||||
# await chk.wait_for(state="attached")
|
||||
# checked = await chk.is_checked()
|
||||
# if is_memo_exposure and not checked:
|
||||
# await chk.click()
|
||||
# self.logger.log("재시도: 메모 노출 체크 ON", level=logging.DEBUG)
|
||||
# elif not is_memo_exposure and checked:
|
||||
# await chk.click()
|
||||
# self.logger.log("재시도: 메모 노출 체크 OFF", level=logging.DEBUG)
|
||||
# # 9. 노출 체크박스 처리
|
||||
# # chk = self.page.locator(
|
||||
# # 'label:has-text("상품 목록에 메모 내용 노출하기") '
|
||||
# # 'input[type="checkbox"]'
|
||||
# # )
|
||||
# # await chk.wait_for(state="attached")
|
||||
# # checked = await chk.is_checked()
|
||||
# # if is_memo_exposure and not checked:
|
||||
# # await chk.click()
|
||||
# # self.logger.log("재시도: 메모 노출 체크 ON", level=logging.DEBUG)
|
||||
# # elif not is_memo_exposure and checked:
|
||||
# # await chk.click()
|
||||
# # self.logger.log("재시도: 메모 노출 체크 OFF", level=logging.DEBUG)
|
||||
|
||||
is_memo_exposure = self.toggle_states.get("memo_exposure", False)
|
||||
exposer = self.page.locator(self.memo_exposer_locator)
|
||||
# is_memo_exposure = self.toggle_states.get("memo_exposure", False)
|
||||
# exposer = self.page.locator(self.memo_exposer_locator)
|
||||
|
||||
# 노출 체크박스 존재 대기
|
||||
await exposer.wait_for(state="attached")
|
||||
# # 노출 체크박스 존재 대기
|
||||
# await exposer.wait_for(state="attached")
|
||||
|
||||
# 노출 체크박스가 보이고 활성화될 때까지 대기
|
||||
await exposer.wait_for(state="visible", timeout=5000)
|
||||
# # 노출 체크박스가 보이고 활성화될 때까지 대기
|
||||
# await exposer.wait_for(state="visible", timeout=5000)
|
||||
|
||||
# 활성화 상태 확인 (disabled 속성이 없으면 활성화된 것)
|
||||
max_attempts = 10
|
||||
for attempt in range(max_attempts):
|
||||
is_disabled = await exposer.get_attribute('disabled')
|
||||
if is_disabled is None: # disabled 속성이 없으면 활성화됨
|
||||
break
|
||||
if attempt < max_attempts - 1:
|
||||
await asyncio.sleep(0.5)
|
||||
else:
|
||||
self.logger.log("노출 체크박스가 활성화되지 않았습니다.", level=logging.WARNING)
|
||||
# # 활성화 상태 확인 (disabled 속성이 없으면 활성화된 것)
|
||||
# max_attempts = 10
|
||||
# for attempt in range(max_attempts):
|
||||
# is_disabled = await exposer.get_attribute('disabled')
|
||||
# if is_disabled is None: # disabled 속성이 없으면 활성화됨
|
||||
# break
|
||||
# if attempt < max_attempts - 1:
|
||||
# await asyncio.sleep(0.5)
|
||||
# else:
|
||||
# self.logger.log("노출 체크박스가 활성화되지 않았습니다.", level=logging.WARNING)
|
||||
|
||||
if is_memo_exposure:
|
||||
await exposer.check()
|
||||
else:
|
||||
await exposer.uncheck()
|
||||
# if is_memo_exposure:
|
||||
# await exposer.check()
|
||||
# else:
|
||||
# await exposer.uncheck()
|
||||
|
||||
# 10. 저장
|
||||
save_btn = self.page.locator(self.memo_save_btn_locator)
|
||||
await save_btn.wait_for(state="visible")
|
||||
await save_btn.click()
|
||||
self.logger.log("재시도: 메모 저장 클릭", level=logging.DEBUG)
|
||||
await asyncio.sleep(0.3)
|
||||
except Exception as e2:
|
||||
screenshot_path = await self.save_error_screenshot()
|
||||
self.logger.log(f"재시도 후에도 메모 입력 중 오류 발생: {e2}", level=logging.ERROR, exc_info=True)
|
||||
# ESC 키 2번 전송하여 팝업 제거 후 재시도 로직을 제거하고, 이번 상품의 메모 입력을 건너뛰고 반환합니다.
|
||||
self.logger.log("ESC 키를 2번 전송하여 메모 창을 닫고 해당 상품의 메모 입력을 건너뜁니다.", level=logging.WARNING)
|
||||
await self.page.keyboard.press("Escape")
|
||||
await self.page.keyboard.press("Escape")
|
||||
await asyncio.sleep(0.5) # 잠시 대기
|
||||
await asyncio.sleep(0.5)
|
||||
return
|
||||
# # 10. 저장
|
||||
# save_btn = self.page.locator(self.memo_save_btn_locator)
|
||||
# await save_btn.wait_for(state="visible")
|
||||
# await save_btn.click()
|
||||
# self.logger.log("재시도: 메모 저장 클릭", level=logging.DEBUG)
|
||||
# await asyncio.sleep(0.3)
|
||||
# except Exception as e2:
|
||||
# screenshot_path = await self.save_error_screenshot()
|
||||
# self.logger.log(f"재시도 후에도 메모 입력 중 오류 발생: {e2}", level=logging.ERROR, exc_info=True)
|
||||
# # ESC 키 2번 전송하여 팝업 제거 후 재시도 로직을 제거하고, 이번 상품의 메모 입력을 건너뛰고 반환합니다.
|
||||
# self.logger.log("ESC 키를 2번 전송하여 메모 창을 닫고 해당 상품의 메모 입력을 건너뜁니다.", level=logging.WARNING)
|
||||
# await self.page.keyboard.press("Escape")
|
||||
# await self.page.keyboard.press("Escape")
|
||||
# await asyncio.sleep(0.5) # 잠시 대기
|
||||
# await asyncio.sleep(0.5)
|
||||
# return
|
||||
|
||||
def generate_titles_with_prices(self, title_infos):
|
||||
"""top_5_titles와 top_5_prices를 매칭하여 텍스트 생성"""
|
||||
|
|
|
|||
113
loggerModule.py
113
loggerModule.py
|
|
@ -121,79 +121,58 @@ class Logger(QObject):
|
|||
self.gui_log_level = gui_log_level
|
||||
|
||||
|
||||
class CustomRotatingFileHandler(BaseRotatingHandler):
|
||||
"""로그 파일을 모두 .log 확장자로 생성하는 커스텀 핸들러"""
|
||||
|
||||
def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None):
|
||||
super().__init__(filename, mode, encoding)
|
||||
self.maxBytes = maxBytes
|
||||
self.backupCount = backupCount
|
||||
# 기존 로그 파일 확인 및 인덱스 설정
|
||||
self._base_filename = filename
|
||||
self._extension = '.log'
|
||||
|
||||
class CustomRotatingFileHandler(RotatingFileHandler):
|
||||
"""`.log` 확장자를 강제하고 파일명을 `base_번호.log` 형식으로 롤오버하는 핸들러"""
|
||||
|
||||
def __init__(self, filename, mode="a", maxBytes=0, backupCount=0, encoding=None):
|
||||
# 확장자를 무조건 .log 로 통일
|
||||
if not filename.endswith(".log"):
|
||||
base, _ = os.path.splitext(filename)
|
||||
filename = base + ".log"
|
||||
|
||||
# 부모(RotatingFileHandler) 초기화
|
||||
super().__init__(filename, mode, maxBytes, backupCount, encoding)
|
||||
|
||||
# 편의를 위해 확장자 없는 베이스 이름 저장
|
||||
self._base_name, _ = os.path.splitext(self.baseFilename)
|
||||
|
||||
def doRollover(self):
|
||||
"""롤오버 수행 - 파일이 최대 크기에 도달하면 새 파일 생성"""
|
||||
"""`RotatingFileHandler`의 롤오버 방식(emit → shouldRollover) 그대로 사용하되
|
||||
파일명을 `base_번호.log` 패턴으로 변경한다."""
|
||||
|
||||
# 현재 스트림 닫기
|
||||
if self.stream:
|
||||
self.stream.close()
|
||||
self.stream = None
|
||||
|
||||
# 기존 로그 파일 이름을 기반으로 백업 파일 생성
|
||||
base_name, ext = os.path.splitext(self._base_filename)
|
||||
|
||||
# 현재 디렉토리의 모든 로그 파일 확인
|
||||
log_dir = os.path.dirname(self._base_filename) or '.'
|
||||
existing_logs = glob.glob(f"{base_name}*.log")
|
||||
|
||||
# existing backup logs
|
||||
existing_logs = glob.glob(f"{self._base_name}_*.log")
|
||||
existing_logs.sort()
|
||||
|
||||
# 최대 백업 수 초과하는 파일 제거
|
||||
while len(existing_logs) >= self.backupCount:
|
||||
try:
|
||||
oldest_file = existing_logs.pop(0)
|
||||
os.remove(oldest_file)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 새 로그 파일 이름 생성 (주 로그 파일 이름은 그대로 유지)
|
||||
# 예: log.log, log_1.log, log_2.log, ...
|
||||
if os.path.exists(self._base_filename):
|
||||
# 인덱스가 있는 로그 파일들 찾기
|
||||
indexed_logs = [f for f in existing_logs if f != self._base_filename]
|
||||
max_index = 0
|
||||
|
||||
for log_file in indexed_logs:
|
||||
|
||||
# backupCount 초과 시 오래된 파일 삭제
|
||||
if self.backupCount > 0 and len(existing_logs) >= self.backupCount:
|
||||
for old_log in existing_logs[: len(existing_logs) - self.backupCount + 1]:
|
||||
try:
|
||||
# 파일 이름에서 인덱스 부분 추출
|
||||
name_part = os.path.basename(log_file)
|
||||
name_without_ext = os.path.splitext(name_part)[0]
|
||||
if '_' in name_without_ext:
|
||||
idx_str = name_without_ext.split('_')[-1]
|
||||
if idx_str.isdigit():
|
||||
max_index = max(max_index, int(idx_str))
|
||||
os.remove(old_log)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 새 인덱스로 파일 이름 설정
|
||||
new_index = max_index + 1
|
||||
new_log_file = f"{base_name}_{new_index}.log"
|
||||
|
||||
# 기존 파일 이름 변경
|
||||
try:
|
||||
os.rename(self._base_filename, new_log_file)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 스트림 다시 열기
|
||||
self.mode = 'w'
|
||||
|
||||
# 새 인덱스 계산
|
||||
max_idx = 0
|
||||
for path in existing_logs:
|
||||
idx_str = os.path.splitext(os.path.basename(path))[0].split("_")[-1]
|
||||
if idx_str.isdigit():
|
||||
max_idx = max(max_idx, int(idx_str))
|
||||
|
||||
new_idx = max_idx + 1
|
||||
rollover_target = f"{self._base_name}_{new_idx}.log"
|
||||
|
||||
# 현재 파일명을 rollover_target 으로 변경
|
||||
try:
|
||||
os.rename(self.baseFilename, rollover_target)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 새로운 스트림 오픈 (write 모드)
|
||||
self.mode = "w"
|
||||
self.stream = self._open()
|
||||
|
||||
def shouldRollover(self, record):
|
||||
"""롤오버가 필요한지 확인"""
|
||||
if self.stream is None: # 첫 번째 로그 쓰기 시도
|
||||
self.stream = self._open()
|
||||
|
||||
if self.maxBytes > 0: # 최대 크기가 지정된 경우만 검사
|
||||
self.stream.seek(0, 2) # 파일 끝으로 이동
|
||||
if self.stream.tell() >= self.maxBytes:
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -136,7 +136,8 @@ class ThumbnailHandler:
|
|||
original_image_url=image_url,
|
||||
file_prefix="thumb_rmb"
|
||||
)
|
||||
# result = await self.imageProcessor.process_single_image(page=self.page, original_image_url=image_url, index=idx, delay=1.0, file_prefix="thumb_rmb") # 누끼기능 충돌로 번역대체
|
||||
if not result:
|
||||
result = await self.imageProcessor.process_single_image(page=self.page, original_image_url=image_url, index=idx, delay=1.0, file_prefix="thumb_rmb") # 누끼기능 충돌로 번역대체
|
||||
|
||||
elif thumb:
|
||||
result = await self.imageProcessor.process_single_image(page=self.page, original_image_url=image_url, index=idx, delay=1.0, file_prefix="thumb")
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class ImageProcessor3:
|
|||
self.request_rembg_server_url = self.toggle_states.get("request_rembg_server_url", None)
|
||||
# self.request_rembg_server_url = self.toggle_states.get("request_rembg_server_url_local", None)
|
||||
|
||||
if self.is_frozen():
|
||||
if not self.is_frozen():
|
||||
self.request_rembg_server_url = self.toggle_states.get("request_rembg_server_url_local", None)
|
||||
|
||||
self.request_ai_server = Request_AI_Server(logger=self.logger, inpaint_server_url=self.request_inpainting_server_url, rembg_server_url=self.request_rembg_server_url)
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -9,6 +9,8 @@
|
|||
- 옵션명 번역 중 특수문자 처리 누락 추가
|
||||
- 이미지프로세서 URL 수정
|
||||
- 상세페이지 소개글 입력방법 개선
|
||||
- 누끼 실패시 번역으로 백업
|
||||
- 로거모듈 오류 수정
|
||||
|
||||
### 기능 추가
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue