# main.py import sys from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QTextBrowser, QLineEdit, QLabel, QCheckBox, QComboBox, QProgressBar, QWidget, QMessageBox, QTabWidget) from PyQt5.QtCore import Qt, QThread, pyqtSignal from playwright.async_api import async_playwright import configparser import logging import json from cryptography.fernet import Fernet import asyncio # 설정 로드 및 저장 def load_config(): config = configparser.ConfigParser() config.read('config.ini') return config def save_config(config): with open('config.ini', 'w') as configfile: config.write(configfile) # 암호화 키 생성 및 로드 def generate_key(): return Fernet.generate_key() def load_key(): try: with open("secret.key", "rb") as key_file: return key_file.read() except FileNotFoundError: key = generate_key() with open("secret.key", "wb") as key_file: key_file.write(key) return key # 암호화 및 복호화 함수 def encrypt_data(data, key): fernet = Fernet(key) return fernet.encrypt(data.encode()) def decrypt_data(data, key): fernet = Fernet(key) return fernet.decrypt(data).decode() # 로그 설정 def setup_logging(): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') logging.info("Logging setup complete.") class LicenseAgreement(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('License Agreement') layout = QVBoxLayout() self.licenseText = QTextBrowser() self.licenseText.setPlainText("License Agreement Text Here...") layout.addWidget(self.licenseText) self.acceptCheckbox = QCheckBox("I accept the terms and conditions.") self.acceptCheckbox.stateChanged.connect(self.toggleAcceptButton) layout.addWidget(self.acceptCheckbox) self.acceptButton = QPushButton("Accept") self.acceptButton.setEnabled(False) self.acceptButton.clicked.connect(self.accept) layout.addWidget(self.acceptButton) self.cancelButton = QPushButton("Cancel") self.cancelButton.clicked.connect(self.cancel) layout.addWidget(self.cancelButton) self.setLayout(layout) def toggleAcceptButton(self, state): self.acceptButton.setEnabled(state == Qt.Checked) def accept(self): self.accepted = True self.close() def cancel(self): self.accepted = False self.close() class FetchSettingsThread(QThread): result_ready = pyqtSignal(dict) def run(self): asyncio.run(self.fetch_market_settings()) async def fetch_market_settings(self): async with async_playwright() as p: browser = await p.chromium.launch(headless=False) page = await browser.new_page() await page.goto("https://percenty.co.kr") await page.click(".signList > .ant-btn-default > span") await page.fill(".ant-input:nth-child(4)", "your_username") await page.fill(".ant-input:nth-child(1)", "your_password") await page.click(".ant-btn-primary") # 팝업 다이얼로그 닫기 try: await page.click('xpath=body > div:nth-child(10) > div > div.ant-modal-wrap.ant-modal-centered > div > div.ant-modal-content > div.ant-modal-footer > button.ant-btn.css-1li46mu.ant-btn-primary') except: pass await page.click('xpath=/html/body/div[1]/div/div/div/div/aside/div/ul/li[7]/ul/li[2]') market_data = {} # 각 마켓의 API key를 가져오는 로직 markets = { "쿠팡": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[1]", "스마트스토어": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[2]", "옥션지마켓": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[3]", "11번가-일반": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[4]", "11번가-글로벌": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[5]", "롯데온": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[6]", } for market, xpath in markets.items(): await page.click(f'xpath={xpath}') if market == "쿠팡": market_data[market] = { "쿠팡ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[1]/input', 'value'), "업체코드": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[2]/input', 'value'), "Access Key": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[3]/input', 'value'), "Secret Key": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[4]/input', 'value') } elif market == "스마트스토어": market_data[market] = { "애플리케이션 ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[2]/input', 'value'), "애플리케이션 시크릿": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[3]/input', 'value') } elif market == "옥션지마켓": market_data[market] = { "옥션ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value'), "G마켓ID": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[2]/input', 'value') } elif market == "11번가-일반": market_data[market] = { "API KEY": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[4]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value') } elif market == "11번가-글로벌": market_data[market] = { "API KEY": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[5]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value') } elif market == "롯데온": market_data[market] = { "API KEY": await page.get_attribute('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[6]/div/div[1]/div/div[2]/div/div/div[1]/input', 'value') } await browser.close() self.result_ready.emit(market_data) class ChangeBusinessThread(QThread): progress_update = pyqtSignal(int) def __init__(self, market_data): super().__init__() self.market_data = market_data def run(self): asyncio.run(self.change_business()) async def change_business(self): async with async_playwright() as p: browser = await p.chromium.launch(headless=False) page = await browser.new_page() await page.goto("https://percenty.co.kr") await page.click(".signList > .ant-btn-default > span") await page.fill(".ant-input:nth-child(4)", "your_username") await page.fill(".ant-input:nth-child(1)", "your_password") await page.click(".ant-btn-primary") # 팝업 다이얼로그 닫기 try: await page.click('xpath=body > div:nth-child(10) > div > div.ant-modal-wrap.ant-modal-centered > div > div.ant-modal-content > div.ant-modal-footer > button.ant-btn.css-1li46mu.ant-btn-primary') except: pass await page.click('xpath=/html/body/div[1]/div/div/div/div/aside/div/ul/li[7]/ul/li[2]') markets = self.market_data.keys() progress_step = 100 // len(markets) progress = 0 for market in markets: market_xpath = { "쿠팡": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[1]", "스마트스토어": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[2]", "옥션지마켓": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[3]", "11번가-일반": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[4]", "11번가-글로벌": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[5]", "롯데온": "/html/body/div[1]/div/div/div/div/main/div[2]/div/div[1]/div[1]/div/div[6]" }[market] await page.click(f'xpath={market_xpath}') data = self.market_data[market] if market == "쿠팡": await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[1]/input', data["쿠팡ID"]) await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[2]/input', data["업체코드"]) await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[3]/input', data["Access Key"]) await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div/div/div[1]/div/div[2]/div/div[2]/div[4]/input', data["Secret Key"]) elif market == "스마트스토어": await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[2]/input', data["애플리케이션 ID"]) await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[2]/div/div[1]/div/div[2]/div/div/div[3]/input', data["애플리케이션 시크릿"]) elif market == "옥션지마켓": await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[1]/input', data["옥션ID"]) await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[3]/div/div[1]/div/div[2]/div/div/div[2]/input', data["G마켓ID"]) elif market == "11번가-일반": await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[4]/div/div[1]/div/div[2]/div/div/div[1]/input', data["API KEY"]) elif market == "11번가-글로벌": await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[5]/div/div[1]/div/div[2]/div/div/div[1]/input', data["API KEY"]) elif market == "롯데온": await page.fill('xpath=/html/body/div[1]/div/div/div/div/main/div[2]/div/div[2]/div/div[6]/div/div[1]/div/div[2]/div/div/div[1]/input', data["API KEY"]) progress += progress_step self.progress_update.emit(progress) await browser.close() self.progress_update.emit(100) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() self.config = load_config() self.key = load_key() self.fetch_thread = FetchSettingsThread() self.fetch_thread.result_ready.connect(self.updateStatus) self.load_business_data() def initUI(self): self.setWindowTitle('Percenty API Manager') mainLayout = QVBoxLayout() self.settingButtonLayout = QHBoxLayout() self.currentSettingButton = QPushButton("현재 설정 가져오기") self.saveSettingButton = QPushButton("현재 설정 저장하기") self.currentSettingButton.clicked.connect(self.fetch_current_settings) self.saveSettingButton.clicked.connect(self.save_current_settings) self.settingButtonLayout.addWidget(self.currentSettingButton) self.settingButtonLayout.addWidget(self.saveSettingButton) mainLayout.addLayout(self.settingButtonLayout) self.currentStatusLayout = QHBoxLayout() self.statusBox1 = QLabel("사업자 현황") self.statusBox2 = QLabel("마켓 현황") self.statusBox3 = QLabel("빈 박스") self.currentStatusLayout.addWidget(self.statusBox1) self.currentStatusLayout.addWidget(self.statusBox2) self.currentStatusLayout.addWidget(self.statusBox3) mainLayout.addLayout(self.currentStatusLayout) self.selectSettingLayout = QVBoxLayout() self.businessDropdown = QComboBox() self.businessDropdown.currentIndexChanged.connect(self.update_market_checkboxes) self.marketCheckboxLayout = QVBoxLayout() self.changeBusinessButton = QPushButton("사업자 바꾸기") self.changeBusinessButton.clicked.connect(self.change_business) self.progressBar = QProgressBar() self.selectSettingLayout.addWidget(self.businessDropdown) self.selectSettingLayout.addLayout(self.marketCheckboxLayout) self.selectSettingLayout.addWidget(self.changeBusinessButton) self.selectSettingLayout.addWidget(self.progressBar) mainLayout.addLayout(self.selectSettingLayout) widget = QWidget() widget.setLayout(mainLayout) self.setCentralWidget(widget) def load_business_data(self): try: loaded_data = self.config['BUSINESS_DATA']['data'] decrypted_data = decrypt_data(loaded_data, self.key) self.business_data = json.loads(decrypted_data) self.update_business_dropdown() except KeyError: self.business_data = {} def update_business_dropdown(self): self.businessDropdown.clear() for business_name in self.business_data.keys(): self.businessDropdown.addItem(business_name) self.update_market_checkboxes() def fetch_current_settings(self): self.fetch_thread.start() def save_current_settings(self): encrypted_data = encrypt_data(json.dumps(self.business_data), self.key) self.config['BUSINESS_DATA'] = {'data': encrypted_data} save_config(self.config) QMessageBox.information(self, "Success", "Current settings have been saved.") def updateStatus(self, market_data): business_name = self.businessDropdown.currentText() if business_name: self.business_data[business_name]["markets"] = market_data self.update_market_checkboxes() self.statusBox1.setText(f"사업자 현황: {business_name}") self.statusBox2.setText(json.dumps(market_data, indent=4, ensure_ascii=False)) def update_market_checkboxes(self): business_name = self.businessDropdown.currentText() if not business_name: return self.clear_layout(self.marketCheckboxLayout) markets = self.business_data[business_name]["markets"] for market, details in markets.items(): market_checkbox = QCheckBox(market) market_checkbox.setChecked(details["api_key"] != "") self.marketCheckboxLayout.addWidget(market_checkbox) def clear_layout(self, layout): while layout.count(): child = layout.takeAt(0) if child.widget(): child.widget().deleteLater() def change_business(self): business_name = self.businessDropdown.currentText() selected_markets = [checkbox.text() for checkbox in self.findChildren(QCheckBox) if checkbox.isChecked()] if business_name: market_data = {market: self.business_data[business_name]["markets"][market] for market in selected_markets} self.change_thread = ChangeBusinessThread(market_data) self.change_thread.progress_update.connect(self.update_progress) self.change_thread.start() def update_progress(self, value): self.progressBar.setValue(value) if __name__ == "__main__": setup_logging() app = QApplication(sys.argv) licenseWindow = LicenseAgreement() licenseWindow.show() app.exec_() if licenseWindow.accepted: mainWindow = MainWindow() mainWindow.show() sys.exit(app.exec_())