그룹선택
This commit is contained in:
parent
2f1d48de66
commit
052b037bd9
|
|
@ -10,6 +10,7 @@ import os, sys, random
|
|||
import requests
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
import psutil
|
||||
|
||||
from whale_new import WhaleTranslator
|
||||
from clipboardImageManager import ClipboardImageManager
|
||||
|
|
@ -114,6 +115,10 @@ class BrowserController(QThread):
|
|||
self.detail_tab_locator = self.locator_manager.get_locator('BrowserControl', 'detail_tab_locator')
|
||||
self.upload_tab_locator = self.locator_manager.get_locator('BrowserControl', 'upload_tab_locator')
|
||||
self.save_button_locator = self.locator_manager.get_locator('BrowserControl', 'save_button_locator')
|
||||
self.group_dropdown_locator = self.locator_manager.get_locator('BrowserControl', 'group_dropdown_locator')
|
||||
self.group_index_template = self.locator_manager.get_locator('BrowserControl', 'group_index_template')
|
||||
self.dropdown_openstatus_locator = self.locator_manager.get_locator('BrowserControl', 'dropdown_openstatus_locator')
|
||||
self.selected_group_name_locator = self.locator_manager.get_locator('BrowserControl', 'selected_group_name_locator')
|
||||
|
||||
self.text_templates = self.locator_manager.selectors.get('DetailPageTextTemplates', {})
|
||||
|
||||
|
|
@ -183,16 +188,6 @@ class BrowserController(QThread):
|
|||
# Playwright 시작 및 브라우저 실행
|
||||
self.playwright = await async_playwright().start()
|
||||
|
||||
# cx_Freeze로 패키징된 경우와 일반 Python 실행 환경 구분하여 경로 설정
|
||||
# if getattr(sys, 'frozen', False):
|
||||
# browser_path = os.path.join(os.path.dirname(sys.executable), 'browsers', 'chromium-1112', 'chrome-win','chrome.exe')
|
||||
# extension_path = os.path.join(os.path.dirname(sys.executable), 'browsers', 'extensions', '1.1.100_0')
|
||||
# user_data_dir = os.path.join(os.path.dirname(sys.executable), 'browsers', 'user_data')
|
||||
# else:
|
||||
# browser_path = os.path.join(os.path.dirname(__file__), 'browsers', 'chromium-1112', 'chrome-win','chrome.exe')
|
||||
# extension_path = os.path.join(os.path.dirname(__file__), 'browsers', 'extensions', '1.1.100_0')
|
||||
# user_data_dir = os.path.join(os.path.dirname(__file__), 'browsers', 'user_data')
|
||||
|
||||
base_path = self.get_base_dir()
|
||||
self.logger.log(f"base_path: {base_path}", level=logging.DEBUG)
|
||||
|
||||
|
|
@ -278,6 +273,11 @@ class BrowserController(QThread):
|
|||
self.logger.log('신규 상품 등록 페이지로 이동 중...', level=logging.INFO)
|
||||
await self.go_to_new_product_page()
|
||||
|
||||
group_index = self.toggle_states['group_index']
|
||||
|
||||
self.logger.log('선택한 그룹 인덱스로 이동', level=logging.INFO)
|
||||
if group_index:
|
||||
await self.select_group_index(group_index=group_index)
|
||||
|
||||
# 각 핸들러에 초기화된 page 객체 전달.
|
||||
self.titleGenerator.update_page(self.page)
|
||||
|
|
@ -546,6 +546,49 @@ class BrowserController(QThread):
|
|||
self.logger.log(f"상품 수정 버튼 상태 확인 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
return False # 오류 발생 시 기본적으로 활성화된 것으로 처리
|
||||
|
||||
async def select_group_index(self, group_index: int):
|
||||
"""그룹 드롭다운 열고 옵션 선택"""
|
||||
try:
|
||||
group_option_locator = self.group_index_template.format(index=group_index)
|
||||
|
||||
# 드롭다운 열기
|
||||
await self.page.wait_for_selector(self.group_dropdown_locator, timeout=3000)
|
||||
await self.page.click(self.group_dropdown_locator)
|
||||
self.logger.log("드롭다운을 성공적으로 클릭했습니다.", level=logging.INFO)
|
||||
|
||||
# 드롭다운 열림 상태 확인
|
||||
await self.page.wait_for_selector(self.dropdown_openstatus_locator, timeout=3000, state='visible')
|
||||
self.logger.log("드롭다운이 열렸습니다.", level=logging.INFO)
|
||||
|
||||
# 옵션 선택
|
||||
await self.page.wait_for_selector(group_option_locator, timeout=3000)
|
||||
await self.page.click(group_option_locator)
|
||||
self.logger.log(f"[{group_index}]번 그룹 선택 완료", level=logging.INFO)
|
||||
|
||||
selected_group_name = await self.page.inner_text(self.selected_group_name_locator)
|
||||
self.logger.log(f"선택된 그룹 이릅 : [{selected_group_name}]", level=logging.INFO)
|
||||
|
||||
except TimeoutError:
|
||||
self.logger.log("드롭다운 또는 옵션 선택 중 타임아웃이 발생했습니다.", level=logging.WARNING)
|
||||
except Exception as e:
|
||||
self.logger.log(f"그룹 선택 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
|
||||
# async def get_selected_group_name(self):
|
||||
# """선택된 그룹 이름 가져오기"""
|
||||
# try:
|
||||
# selected_group_name_locator = self.locator_manager.get_locator('BrowserControl', 'selected_group_name_locator')
|
||||
# await self.page.wait_for_selector(selected_group_name_locator, timeout=3000, state='visible')
|
||||
# selected_group_name = await self.page.inner_text(selected_group_name_locator)
|
||||
# self.logger.log(f"선택된 그룹 이름: {selected_group_name}", level=logging.INFO)
|
||||
# return selected_group_name
|
||||
|
||||
# except TimeoutError:
|
||||
# self.logger.log("선택된 그룹 이름을 가져오는 중 타임아웃이 발생했습니다.", level=logging.WARNING)
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# self.logger.log(f"그룹 이름 가져오기 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
# return None
|
||||
|
||||
async def get_product_edit_buttons_by_templete(self):
|
||||
"""현재 페이지의 세부사항 수정 및 업로드 버튼을 찾기"""
|
||||
# 버튼 선택자 설정
|
||||
|
|
@ -2166,9 +2209,29 @@ class BrowserController(QThread):
|
|||
self.logger.log("Whale 브라우저 창 닫기 시도 중...", level=logging.INFO)
|
||||
self.whale_translator.close_whale_window()
|
||||
|
||||
def force_terminate_browser(self):
|
||||
"""Playwright 브라우저 프로세스를 강제로 종료"""
|
||||
try:
|
||||
if self.browser:
|
||||
browser_pid = self.browser.contexts[0]._channel.owner._impl_obj._browser_pid
|
||||
browser_process = psutil.Process(browser_pid)
|
||||
for child in browser_process.children(recursive=True):
|
||||
child.kill()
|
||||
browser_process.kill()
|
||||
self.logger.log("브라우저 프로세스를 강제로 종료했습니다.", level=logging.WARNING)
|
||||
|
||||
if self.whale_translator:
|
||||
self.whale_translator.close_whale_window()
|
||||
|
||||
except Exception as e:
|
||||
self.logger.log(f"브라우저 프로세스 강제 종료 중 오류 발생: {e}", level=logging.ERROR)
|
||||
|
||||
def terminate(self):
|
||||
self.logger.log("크롬 스레드 종료", level=logging.INFO)
|
||||
self.cleanup() # 종료 시 추가 정리 작업 호출
|
||||
|
||||
if self.whale_translator:
|
||||
self.whale_translator.close_whale_window()
|
||||
super().terminate()
|
||||
|
||||
def cleanup(self):
|
||||
|
|
|
|||
|
|
@ -165,9 +165,11 @@ product_price_for_ed_template = '//*[@id="root"]/div/div/div/div/main/div/div[2]
|
|||
product_image_for_ed_template = '//*[@id="root"]/div/div/div/div/main/div/div[2]/div[3]/div[2]/div/div/div/div/div[2]/table/tbody/tr[{index}]/td[2]/div/div/div/div[1]/span/div/div[1]/img'
|
||||
|
||||
|
||||
|
||||
"div#root div:nth-child(2) > div > li > div > div > div:nth-child(2) > div > div > div.ant-flex.css-1li46mu.ant-flex-align-stretch.ant-flex-justify-space-between.ant-flex-vertical > div.ant-flex.css-1li46mu.ant-flex-wrap-nowrap.ant-flex-justify-flex-end > button[type=\"button\"].ant-btn.css-1li46mu.ant-btn-default.ant-btn-icon-only"
|
||||
|
||||
# 그룹관련 선택자
|
||||
group_dropdown_locator = 'div.ant-select-selector'
|
||||
dropdown_openstatus_locator = 'div.ant-select-dropdown:not(.ant-select-dropdown-hidden)'
|
||||
group_index_template = 'div.ant-select-item.ant-select-item-option:nth-child({index})'
|
||||
selected_group_name_locator = 'div#root div:nth-child(4) > div > div > span.ant-select-selection-item'
|
||||
|
||||
|
||||
# 상품 편집 및 페이지 이동 관련 선택자
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
from playwright.sync_api import sync_playwright
|
||||
import sys, os, random
|
||||
import time
|
||||
|
||||
def change_group(selected_group_index: int):
|
||||
|
||||
# Playwright 시작 및 브라우저 실행
|
||||
playwright = sync_playwright().start()
|
||||
|
||||
base_path = get_base_dir()
|
||||
browser_path = os.path.join(base_path, 'browsers', 'chromium-1140', 'chrome-win','chrome.exe')
|
||||
extension_path = os.path.join(base_path, 'browsers', 'extensions', '1.1.100_0')
|
||||
user_data_dir = os.path.join(base_path, 'browsers', 'user_data')
|
||||
|
||||
# User agent 설정
|
||||
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",
|
||||
])
|
||||
|
||||
# 브라우저 시작 및 설정
|
||||
browser = playwright.chromium.launch_persistent_context(
|
||||
user_data_dir,
|
||||
headless=True,
|
||||
permissions=["geolocation", "notifications"],
|
||||
geolocation={"latitude": 37.5665, "longitude": 126.9780},
|
||||
locale="ko-KR",
|
||||
args=[
|
||||
'--disable-popup-blocking',
|
||||
f'--disable-extensions-except={extension_path}',
|
||||
f'--load-extension={extension_path}',
|
||||
'--start-maximized',
|
||||
'--window-size=1920,1080'
|
||||
],
|
||||
executable_path=browser_path,
|
||||
user_agent=user_agent
|
||||
)
|
||||
|
||||
# 기본 페이지가 없을 수 있으므로 새로운 페이지 생성
|
||||
page = browser.new_page()
|
||||
|
||||
# 로그인 페이지로 이동 (URL을 실제 로그인 페이지로 변경)
|
||||
page.goto('https://percenty.co.kr/signin')
|
||||
|
||||
# 로그인 수행
|
||||
admin_toggle = page.locator('button[role="switch"]')
|
||||
if admin_toggle.get_attribute("aria-checked") == "true":
|
||||
admin_toggle.click() # 관리자 모드에서 직원 모드로 전환
|
||||
|
||||
page.fill('input[placeholder="이메일 주소 입력"]', 'leensoo1nt@gmail.com')
|
||||
page.fill('input[placeholder="직원 아이디 입력"]', 'test')
|
||||
page.fill('input[placeholder="영문/숫자/특수문자의 조합 (6~15자리)"]', 'test')
|
||||
page.click('button:has-text("직원 로그인 하기")')
|
||||
|
||||
page.wait_for_selector('div[role="dialog"]', timeout=3000, state='visible')
|
||||
close_button = page.query_selector("div.ant-modal-footer > div > div > button[type='button'].ant-btn.css-1li46mu.ant-btn-default")
|
||||
if close_button:
|
||||
close_button.click()
|
||||
|
||||
# 상품 수정 페이지로 이동
|
||||
page.wait_for_load_state("networkidle")
|
||||
page.click('span.ant-menu-title-content:has-text("신규 상품 등록")')
|
||||
|
||||
|
||||
page.evaluate("""
|
||||
const dropdown = document.querySelector('input#rc_select_1');
|
||||
if (dropdown) {
|
||||
dropdown.scrollIntoView();
|
||||
}
|
||||
""")
|
||||
|
||||
print("해당요소 스크롤")
|
||||
|
||||
# 그룹 드롭박스 열기
|
||||
group_dropdown_css = "div.ant-select-selector"
|
||||
page.wait_for_selector(group_dropdown_css)
|
||||
print("드롭박스 상위 요소 대기")
|
||||
|
||||
# 드롭박스 열기
|
||||
page.click(group_dropdown_css)
|
||||
print("드롭박스 클릭")
|
||||
|
||||
# 드롭다운 열림 상태 확인
|
||||
dropdown_openstatus_css = "div.ant-select-dropdown:not(.ant-select-dropdown-hidden)"
|
||||
page.wait_for_selector(dropdown_openstatus_css)
|
||||
print("드롭다운 열림 확인")
|
||||
|
||||
# 옵션 선택
|
||||
group_index_css = f"div.ant-select-item.ant-select-item-option:nth-child({selected_group_index + 1})"
|
||||
page.wait_for_selector(group_index_css)
|
||||
page.click(group_index_css)
|
||||
print(f"[{selected_group_index+1}]번 그룹 선택 완료")
|
||||
|
||||
# 변경된 그룹 이름 가져오기
|
||||
selected_group_name_css = "div#root div:nth-child(4) > div > div > span.ant-select-selection-item"
|
||||
selected_group_name = page.inner_text(selected_group_name_css)
|
||||
|
||||
print(f"변경된 그룹 이름: {selected_group_name}")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 브라우저 닫기
|
||||
browser.close()
|
||||
|
||||
def get_base_dir():
|
||||
if getattr(sys, 'frozen', False): # 패키징된 경우
|
||||
base_dir = os.path.dirname(sys.executable)
|
||||
internal_dir = os.path.join(base_dir, '_internal')
|
||||
if os.path.exists(internal_dir):
|
||||
return internal_dir
|
||||
else:
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
return base_dir
|
||||
|
||||
# 실행 예제 (2번째 그룹 선택)
|
||||
change_group(selected_group_index=2)
|
||||
136
gui.py
136
gui.py
|
|
@ -1,4 +1,4 @@
|
|||
from PySide6.QtWidgets import QInputDialog, QWidget, QMessageBox, QSpinBox, QPushButton, QVBoxLayout, QGridLayout, QTextEdit, QLabel, QLineEdit, QHBoxLayout, QProgressBar, QSizePolicy
|
||||
from PySide6.QtWidgets import QApplication, QInputDialog, QWidget, QMessageBox, QSpinBox, QPushButton, QVBoxLayout, QGridLayout, QTextEdit, QLabel, QLineEdit, QHBoxLayout, QProgressBar, QSizePolicy, QComboBox
|
||||
from PySide6.QtCore import Qt, Signal, Slot, QRect, QSettings, QTimer
|
||||
from toggleSwitch import ToggleSwitch
|
||||
from browser_control import BrowserController
|
||||
|
|
@ -11,6 +11,7 @@ from loggerModule import Logger # 추가
|
|||
import logging
|
||||
import sys
|
||||
import os, shutil, time
|
||||
import asyncio
|
||||
|
||||
class AutoPercentyGUI(QWidget):
|
||||
|
||||
|
|
@ -226,6 +227,7 @@ class AutoPercentyGUI(QWidget):
|
|||
'watermark_text': "", # 워터마크 텍스트 저장
|
||||
'opacity_percent': 25, # 워터마크 투명도
|
||||
'max_option_count': 20, # 최대 선택가능한 옵션 수
|
||||
'group_index': 1, # 작업그룹 선택
|
||||
}
|
||||
|
||||
def initUI(self):
|
||||
|
|
@ -396,8 +398,18 @@ class AutoPercentyGUI(QWidget):
|
|||
self.opacity_percent_input.setToolTip("워터마크 투명도 설정: 낮을수록 투명") # 툴팁 설정
|
||||
self.opacity_percent_input.valueChanged.connect(self.update_opacity_percent) # 값 변경 시 update_max_option_count 메서드 호출
|
||||
|
||||
# 워터마크 관련 요소들을 하나의 QHBoxLayout에 추가 (비율 2:3:1)
|
||||
self.watermark_layout = QHBoxLayout()
|
||||
|
||||
# 그룹 선택 드롭박스 및 툴팁 추가
|
||||
self.group_selector_label = QLabel("그룹 선택:", self)
|
||||
self.group_selector = QComboBox(self)
|
||||
self.group_selector.setToolTip(
|
||||
"직원계정은 3개, 관리자계정은 20개 중 선택할 수 있습니다.\n해당 그룹이 없을 경우 기본으로 1번그룹을 작업합니다."
|
||||
)
|
||||
self.group_selector.currentIndexChanged.connect(self.on_group_selected)
|
||||
|
||||
# 기본 상태는 직원 (3개 그룹)
|
||||
self.update_group_items(is_admin=False)
|
||||
|
||||
|
||||
# 초기 위치에서 배치
|
||||
self.update_widget_positions(use_api_row=1)
|
||||
|
|
@ -773,6 +785,39 @@ class AutoPercentyGUI(QWidget):
|
|||
current_row += 1
|
||||
self.toggle_layout.addWidget(self.max_option_count_label, current_row, 0)
|
||||
self.toggle_layout.addWidget(self.max_option_count_input, current_row, 1)
|
||||
self.toggle_layout.addWidget(self.group_selector_label, current_row, 2)
|
||||
self.toggle_layout.addWidget(self.group_selector, current_row, 3)
|
||||
|
||||
def update_group_items(self, is_admin: bool):
|
||||
"""관리자 여부에 따라 그룹 선택 항목 변경"""
|
||||
self.group_selector.clear() # 기존 아이템 제거
|
||||
|
||||
if is_admin:
|
||||
# 관리자 계정: 20개 그룹
|
||||
self.group_selector.addItems([f"{i}번" for i in range(1, 21)])
|
||||
else:
|
||||
# 직원 계정: 3개 그룹
|
||||
self.group_selector.addItems(["1번그룹", "2번그룹", "3번그룹"])
|
||||
|
||||
self.group_selector.setCurrentIndex(0) # 기본값 설정
|
||||
|
||||
def on_group_selected(self):
|
||||
"""그룹 선택 변경 시 호출"""
|
||||
import re
|
||||
try:
|
||||
# 정규식으로 숫자만 추출
|
||||
match = re.search(r'\d+', self.group_selector.currentText())
|
||||
if match:
|
||||
self.toggle_states['group_index'] = int(match.group())
|
||||
print(f"선택된 그룹이 변경되었습니다: {self.toggle_states['group_index']}")
|
||||
else:
|
||||
# 숫자가 없을 경우 처리
|
||||
print(f"선택된 그룹에 숫자가 없습니다: {self.group_selector.currentText()}")
|
||||
self.toggle_states['group_index'] = None
|
||||
except Exception as e:
|
||||
# 기타 예외 처리
|
||||
print(f"그룹 선택 처리 중 오류 발생: {e}")
|
||||
self.toggle_states['group_index'] = None
|
||||
|
||||
def on_toggle_clicked_generic(self, key, is_checked):
|
||||
"""토글 클릭 시 상태 업데이트 및 저장"""
|
||||
|
|
@ -860,6 +905,8 @@ class AutoPercentyGUI(QWidget):
|
|||
self.set_layout_visibility(self.admin_layout, False)
|
||||
self.set_layout_visibility(self.user_layout, True)
|
||||
|
||||
self.update_group_items(is_admin=is_checked)
|
||||
|
||||
# def on_vd_mode_for_detail_imageTrans_clicked(self, is_checked):
|
||||
# """상페이미지 번역여부에 따라 VD 모드 선택 필드를 표시/숨김"""
|
||||
# if is_checked:
|
||||
|
|
@ -1045,22 +1092,83 @@ class AutoPercentyGUI(QWidget):
|
|||
"""브라우저 오류 발생 시 처리할 로직"""
|
||||
self.logger.log(f"브라우저 시작 중 오류 발생: {error_message}", level=logging.ERROR)
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""창 닫기 시 스레드 종료"""
|
||||
self.logger.log('프로그램을 종료합니다...', level=logging.INFO)
|
||||
self.save_settings()
|
||||
|
||||
if self.browser_controller.isRunning():
|
||||
self.browser_controller.stop() # 리소스 정리
|
||||
self.browser_controller.wait() # 스레드가 종료될 때까지 대기
|
||||
event.accept()
|
||||
|
||||
# def close(self):
|
||||
# def closeEvent(self, event):
|
||||
# """창 닫기 시 스레드 종료"""
|
||||
# self.logger.log('프로그램을 종료합니다...', level=logging.INFO)
|
||||
# self.save_settings()
|
||||
# asyncio.run(self.browser_controller.close_browser()) # 브라우저 종료
|
||||
|
||||
# if self.browser_controller.isRunning():
|
||||
# self.browser_controller.stop() # 리소스 정리
|
||||
# # self.browser_controller.wait() # 스레드가 종료될 때까지 대기
|
||||
# event.accept()
|
||||
# super().close()
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""창 닫기 시 스레드 및 리소스 종료"""
|
||||
self.logger.log('프로그램을 종료합니다...', level=logging.INFO)
|
||||
|
||||
# 현재 설정 저장
|
||||
self.save_settings()
|
||||
|
||||
|
||||
# Playwright 및 이벤트 루프 정리
|
||||
try:
|
||||
asyncio.run(self.cleanup_resources())
|
||||
except Exception as e:
|
||||
self.logger.log(f"Playwright 리소스 정리 중 오류 발생: {e}", level=logging.ERROR)
|
||||
|
||||
# 브라우저 컨트롤러 스레드 종료
|
||||
if self.browser_controller.isRunning():
|
||||
self.browser_controller.terminate()
|
||||
self.browser_controller.wait(3000) # 3초 대기
|
||||
if self.browser_controller.isRunning():
|
||||
self.logger.log('스레드가 종료되지 않아 강제 종료를 시도합니다.', level=logging.WARNING)
|
||||
self.browser_controller.terminate() # 강제 종료
|
||||
|
||||
# Qt 메인 이벤트 루프 종료
|
||||
QApplication.quit()
|
||||
event.accept()
|
||||
super().closeEvent(event)
|
||||
|
||||
async def cleanup_resources(self):
|
||||
"""Playwright 및 이벤트 루프 정리"""
|
||||
try:
|
||||
self.logger.log("Playwright 리소스 정리를 시작합니다.", level=logging.INFO)
|
||||
|
||||
# 모든 페이지 닫기
|
||||
if self.browser_controller.browser:
|
||||
self.logger.log("열린 페이지를 닫습니다...", level=logging.INFO)
|
||||
for page in self.browser_controller.browser.pages:
|
||||
try:
|
||||
await asyncio.wait_for(page.close(), timeout=1) # 페이지 닫기에 타임아웃 적용
|
||||
self.logger.log(f"페이지 {page.url} 닫기 완료.", level=logging.INFO)
|
||||
except asyncio.TimeoutError:
|
||||
self.logger.log(f"페이지 {page.url} 닫기 타임아웃 발생. 강제 종료를 시도합니다.", level=logging.WARNING)
|
||||
|
||||
# 브라우저 닫기
|
||||
self.logger.log("브라우저를 닫습니다...", level=logging.INFO)
|
||||
try:
|
||||
await asyncio.wait_for(self.browser_controller.browser.close(), timeout=1)
|
||||
self.logger.log("브라우저 종료 완료.", level=logging.INFO)
|
||||
except asyncio.TimeoutError:
|
||||
self.logger.log("브라우저 종료가 타임아웃되었습니다. 강제 종료를 시도합니다.", level=logging.WARNING)
|
||||
self.browser_controller.force_terminate_browser()
|
||||
|
||||
|
||||
# Playwright 종료
|
||||
if self.browser_controller.playwright:
|
||||
self.logger.log('Playwright 종료 중...', level=logging.INFO)
|
||||
await self.browser_controller.playwright.stop()
|
||||
self.logger.log('Playwright 종료 완료.', level=logging.INFO)
|
||||
|
||||
# 이벤트 루프 종료
|
||||
if self.browser_controller.loop and not self.browser_controller.loop.is_closed():
|
||||
self.browser_controller.loop.call_soon_threadsafe(self.browser_controller.loop.stop)
|
||||
self.logger.log('이벤트 루프 종료 완료.', level=logging.INFO)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.log(f"리소스 정리 중 오류 발생: {e}", level=logging.ERROR)
|
||||
|
||||
@Slot()
|
||||
def on_start_PercentyJob_clicked(self):
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ class LocatorManager:
|
|||
'detail_tab_locator': self.config.get('BrowserControl', 'detail_tab_locator').strip("'"),
|
||||
'upload_tab_locator': self.config.get('BrowserControl', 'upload_tab_locator').strip("'"),
|
||||
'save_button_locator': self.config.get('BrowserControl', 'save_button_locator').strip("'"),
|
||||
'group_dropdown_locator': self.config.get('BrowserControl', 'group_dropdown_locator').strip("'"),
|
||||
'dropdown_openstatus_locator': self.config.get('BrowserControl', 'dropdown_openstatus_locator').strip("'"),
|
||||
'group_index_template': self.config.get('BrowserControl', 'group_index_template').strip("'"),
|
||||
'selected_group_name_locator': self.config.get('BrowserControl', 'selected_group_name_locator').strip("'"),
|
||||
}
|
||||
|
||||
# DetailPageTextTemplates 섹션
|
||||
|
|
|
|||
4
setup.py
4
setup.py
|
|
@ -54,7 +54,7 @@ build_exe_options = {
|
|||
'packages': [
|
||||
'ctypes', 'asyncio', 'os', 're', 'time', 'math', 'json', 'logging', 'shutil', 'random', 'base64',
|
||||
'subprocess', 'configparser', 'pyperclip', 'numpy', 'cv2', 'requests', 'win32clipboard', 'win32gui',
|
||||
'win32con', 'win32process', 'PIL', 'bs4', 'sqlalchemy', 'sqlalchemy.orm', 'PySide6',
|
||||
'win32con', 'win32process', 'PIL', 'bs4', 'sqlalchemy', 'sqlalchemy.orm', 'PySide6', 'psutil',
|
||||
'sqlalchemy.exc', 'collections', 'pandas', 'pymongo', 'translatepy', 'comtypes',
|
||||
|
||||
],
|
||||
|
|
@ -85,7 +85,7 @@ executables = [
|
|||
# Setup 설정
|
||||
setup(
|
||||
name='AutoPercenty3',
|
||||
version='3.1',
|
||||
version='3.2',
|
||||
description='자동화도구',
|
||||
options={'build_exe': build_exe_options},
|
||||
executables=executables
|
||||
|
|
|
|||
Loading…
Reference in New Issue