Compare commits
6 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d060e38c32 | |
|
|
5069a0ba05 | |
|
|
306fb77e7c | |
|
|
65a1c85faa | |
|
|
0515ccc524 | |
|
|
53071e4533 |
|
|
@ -6,6 +6,7 @@ dist/
|
|||
Include/
|
||||
__pycache__/
|
||||
*.log
|
||||
*.zip
|
||||
*.log.*
|
||||
pyvenv.cfg
|
||||
Output/
|
||||
24
build.py
24
build.py
|
|
@ -1,6 +1,9 @@
|
|||
import shutil
|
||||
import os
|
||||
from subprocess import call
|
||||
import subprocess
|
||||
|
||||
# 가상 환경 경로 (필요에 따라 변경)
|
||||
venv_path = os.path.join(os.getcwd(), 'venv')
|
||||
|
||||
# 삭제할 디렉토리 목록
|
||||
folders_to_delete = ['build', 'dist']
|
||||
|
|
@ -11,7 +14,18 @@ for folder in folders_to_delete:
|
|||
shutil.rmtree(folder)
|
||||
print(f"{folder} 폴더를 삭제했습니다.")
|
||||
|
||||
# PyInstaller 명령 실행
|
||||
# 여기에서 'your_script.py'를 실제 빌드하고자 하는 스크립트의 이름으로 바꿔주세요.
|
||||
# 추가 PyInstaller 옵션이 필요한 경우 이 부분에 추가합니다.
|
||||
call(['pyinstaller', 'taomanXLS.spec'])
|
||||
# 가상 환경 활성화 및 cx_Freeze 빌드 실행
|
||||
try:
|
||||
if os.name == 'nt': # Windows
|
||||
activate_script = os.path.join(venv_path, 'Scripts', 'activate.bat')
|
||||
# cmd 명령어를 통해 가상 환경 활성화 후 setup.py 빌드 실행
|
||||
command = f'cmd /c "{activate_script} && python setup.py build"'
|
||||
result = subprocess.run(command, shell=True, check=True)
|
||||
print(result)
|
||||
else: # Linux/Mac
|
||||
activate_script = os.path.join(venv_path, 'bin', 'activate')
|
||||
command = f'/bin/bash -c "source {activate_script} && python setup.py build"'
|
||||
subprocess.run(command, shell=True, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
|
|
|||
Binary file not shown.
4
setup.py
4
setup.py
|
|
@ -3,7 +3,7 @@ from cx_Freeze import setup, Executable
|
|||
|
||||
# Add options for build_exe
|
||||
build_exe_options = {
|
||||
"packages": ["os", "pandas", "xlwings", "configparser", "PyQt5"],
|
||||
"packages": ["os", "pandas", "xlwings", "openpyxl", "configparser", "PyQt5"],
|
||||
"include_files": [
|
||||
("퍼센티양식.xlsx", "퍼센티양식.xlsx"),
|
||||
("config.ini", "config.ini"),
|
||||
|
|
@ -17,7 +17,7 @@ if sys.platform == "win32":
|
|||
|
||||
setup(
|
||||
name="taomanXLS",
|
||||
version="1.1",
|
||||
version="1.3",
|
||||
description="Taoman_to_PercentyXLS",
|
||||
options={"build_exe": build_exe_options},
|
||||
executables=[Executable("taomanXLS.py", base=base, icon="taomanXLS.ico")]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[Setup]
|
||||
; 기본 설정
|
||||
; 기본 ?¤ì •
|
||||
AppName=TaomanXLS
|
||||
AppVersion=1.1
|
||||
AppVersion=1.4
|
||||
DefaultDirName={pf}\TaomanXLS
|
||||
DefaultGroupName=TaomanXLS
|
||||
OutputBaseFilename=TaomanXLSInstaller
|
||||
|
|
@ -15,8 +15,8 @@ Name: "english"; MessagesFile: "compiler:Default.isl"
|
|||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
; cx_Freeze로 생성한 파일을 모두 포함
|
||||
Source: "build\exe.win-amd64-3.11\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; cx_Freezeë¡??<3F>성???Œì<C592>¼??모ë‘<C3AB> ?¬í•¨
|
||||
Source: "build\exe.win-amd64-3.7\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\TaomanXLS"; Filename: "{app}\taomanXLS.exe"; WorkingDir: "{app}"
|
||||
|
|
|
|||
100
taomanXLS.py
100
taomanXLS.py
|
|
@ -1,21 +1,30 @@
|
|||
import sys
|
||||
import os
|
||||
import os, sys
|
||||
import pandas as pd
|
||||
import random
|
||||
import configparser
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,
|
||||
QFileDialog, QRadioButton, QTextEdit, QMessageBox, QLineEdit, QCheckBox
|
||||
QFileDialog, QRadioButton, QTextEdit, QMessageBox, QLineEdit, QCheckBox,
|
||||
QSpinBox
|
||||
)
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal
|
||||
import xlwings as xw
|
||||
import traceback
|
||||
import xlwings as xw # xlwings 모듈 임포트
|
||||
import traceback # traceback 모듈 임포트
|
||||
|
||||
|
||||
class CommaSpinBox(QSpinBox):
|
||||
def textFromValue(self, value):
|
||||
return f"{value:,}" # 숫자에 콤마 추가
|
||||
|
||||
def valueFromText(self, text):
|
||||
return int(text.replace(",", "")) # 콤마 제거하고 숫자 변환
|
||||
|
||||
|
||||
class ExportThread(QThread):
|
||||
log_signal = pyqtSignal(str)
|
||||
finished_signal = pyqtSignal()
|
||||
|
||||
def __init__(self, data, export_format, output_folder, original_file_name, exclude_words, ban_words, shuffle_title):
|
||||
def __init__(self, data, export_format, output_folder, original_file_name, exclude_words, ban_words, shuffle_title, price_limit_enabled, price_limit):
|
||||
super().__init__()
|
||||
self.data = data
|
||||
self.export_format = export_format
|
||||
|
|
@ -24,9 +33,18 @@ class ExportThread(QThread):
|
|||
self.exclude_words = exclude_words
|
||||
self.ban_words = ban_words
|
||||
self.shuffle_title = shuffle_title
|
||||
self.price_limit_enabled = price_limit_enabled
|
||||
self.price_limit = price_limit
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
# 타오바오URL이 비어있는 데이터 제외
|
||||
self.data = self.data[self.data['타오바오URL'].notna() & self.data['타오바오URL'].str.strip().astype(bool)]
|
||||
|
||||
# 가격 제한 적용
|
||||
if self.price_limit_enabled:
|
||||
self.data = self.data[self.data['가격'] >= self.price_limit]
|
||||
|
||||
chunk_size = 50
|
||||
for i in range(0, len(self.data), chunk_size):
|
||||
chunk = self.data.iloc[i:i+chunk_size].copy()
|
||||
|
|
@ -45,7 +63,8 @@ class ExportThread(QThread):
|
|||
if self.shuffle_title:
|
||||
chunk['상품명'] = chunk['상품명'].apply(self.shuffle_title_words)
|
||||
|
||||
output_file = os.path.join(self.output_folder, f"percenty-{i//chunk_size + 1:02d}_{self.original_file_name}")
|
||||
# output_file = os.path.join(self.output_folder, f"{self.original_file_name}_percenty-{i//chunk_size + 1:02d}")
|
||||
output_file = os.path.join(self.output_folder, f"{os.path.splitext(self.original_file_name)[0]}_percenty-{i//chunk_size + 1:02d}.xlsx")
|
||||
|
||||
# Create a DataFrame with exactly 50 rows, filling with empty values if necessary
|
||||
if len(chunk) < chunk_size:
|
||||
|
|
@ -77,9 +96,27 @@ class ExportThread(QThread):
|
|||
template_wb.close()
|
||||
|
||||
elif self.export_format == "헤이셀러":
|
||||
# Implement 헤이셀러 export format if provided
|
||||
pass
|
||||
template_file = "헤이셀러양식.xlsx"
|
||||
with xw.App(visible=False) as app:
|
||||
template_wb = app.books.open(template_file)
|
||||
template_ws = template_wb.sheets[0]
|
||||
|
||||
new_wb = xw.Book()
|
||||
new_ws = new_wb.sheets[0]
|
||||
|
||||
# Copy the template sheet to the new workbook
|
||||
template_ws.api.Copy(Before=new_ws.api)
|
||||
new_ws = new_wb.sheets[0]
|
||||
|
||||
# Write data to the new workbook
|
||||
new_ws.range('E3:E53').value = [[v] for v in chunk['타오바오URL']]
|
||||
new_ws.range('B3:B53').value = [[v] for v in chunk['상품명']]
|
||||
new_ws.range('D3:D53').value = [[v] for v in chunk['가격']]
|
||||
new_ws.range('A3:A53').value = [[v] for v in chunk['카테고리']]
|
||||
|
||||
new_wb.save(output_file)
|
||||
new_wb.close()
|
||||
template_wb.close()
|
||||
self.log_signal.emit(f"Exported {output_file}")
|
||||
|
||||
os.startfile(self.output_folder)
|
||||
|
|
@ -99,6 +136,7 @@ class ExportThread(QThread):
|
|||
return ' '.join(prefix + suffix)
|
||||
return title
|
||||
|
||||
|
||||
class ExcelProcessorApp(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
|
@ -112,8 +150,8 @@ class ExcelProcessorApp(QWidget):
|
|||
|
||||
def initUI(self):
|
||||
self.setWindowTitle('WRMC TaomanXLS')
|
||||
self.setGeometry(100, 100, 450, 600)
|
||||
self.setFixedSize(450, 600)
|
||||
self.setGeometry(100, 100, 300, 650)
|
||||
self.setFixedSize(300, 650)
|
||||
|
||||
main_layout = QVBoxLayout()
|
||||
|
||||
|
|
@ -126,8 +164,8 @@ class ExcelProcessorApp(QWidget):
|
|||
|
||||
self.source_button = QPushButton('소싱맨 읽기')
|
||||
self.source_button.setMinimumHeight(70)
|
||||
self.source_button.setEnabled(False)
|
||||
self.source_button.clicked.connect(self.read_source)
|
||||
self.source_button.setEnabled(False) # 소싱맨 푸쉬 버튼 비활성화
|
||||
button_layout.addWidget(self.source_button)
|
||||
|
||||
self.export_button = QPushButton('출력')
|
||||
|
|
@ -162,6 +200,26 @@ class ExcelProcessorApp(QWidget):
|
|||
ban_layout.addWidget(self.ban_input)
|
||||
shuffle_layout.addLayout(ban_layout)
|
||||
|
||||
# 가격제한 체크박스와 CommaSpinBox, QLabel 추가
|
||||
price_limit_layout = QHBoxLayout()
|
||||
self.price_limit_checkbox = QCheckBox('가격제한')
|
||||
self.price_limit_checkbox.stateChanged.connect(self.toggle_price_limit)
|
||||
price_limit_layout.addWidget(self.price_limit_checkbox)
|
||||
|
||||
self.price_limit_spinbox = CommaSpinBox()
|
||||
self.price_limit_spinbox.setRange(1000, 1000000)
|
||||
self.price_limit_spinbox.setValue(10000)
|
||||
self.price_limit_spinbox.setSingleStep(1000)
|
||||
self.price_limit_spinbox.setSuffix(" 원")
|
||||
self.price_limit_spinbox.setEnabled(False) # 기본값은 비활성화
|
||||
price_limit_layout.addWidget(self.price_limit_spinbox)
|
||||
|
||||
self.price_limit_label = QLabel('이상')
|
||||
self.price_limit_label.setEnabled(False) # 기본값은 비활성화
|
||||
price_limit_layout.addWidget(self.price_limit_label)
|
||||
|
||||
shuffle_layout.addLayout(price_limit_layout)
|
||||
|
||||
main_layout.addLayout(shuffle_layout)
|
||||
|
||||
# Second layout with radio buttons
|
||||
|
|
@ -171,7 +229,7 @@ class ExcelProcessorApp(QWidget):
|
|||
radio_layout.addWidget(self.percent_radio)
|
||||
|
||||
self.hayseller_radio = QRadioButton('헤이셀러')
|
||||
self.hayseller_radio.setEnabled(False)
|
||||
self.hayseller_radio.setEnabled(False) # 헤이셀러 라디오 버튼 비활성화
|
||||
radio_layout.addWidget(self.hayseller_radio)
|
||||
|
||||
main_layout.addLayout(radio_layout)
|
||||
|
|
@ -228,7 +286,7 @@ class ExcelProcessorApp(QWidget):
|
|||
self.log(f"Reading file: {file_path}")
|
||||
try:
|
||||
df = pd.read_excel(file_path, sheet_name='추출상점')
|
||||
required_columns = ["퍼센티카테고리", "가격", "상품명", "태그", "타오바오URL"]
|
||||
required_columns = ["퍼센티카테고리", "가격", "상품명", "태그", "타오바오URL", "카테고리"]
|
||||
if all(col in df.columns for col in required_columns):
|
||||
self.log(f"Successfully read data from {file_path}")
|
||||
return df[required_columns], file_path
|
||||
|
|
@ -264,6 +322,8 @@ class ExcelProcessorApp(QWidget):
|
|||
ban_words = [word.strip() for word in ban_words if word.strip()]
|
||||
|
||||
shuffle_title = self.shuffle_checkbox.isChecked()
|
||||
price_limit_enabled = self.price_limit_checkbox.isChecked()
|
||||
price_limit = self.price_limit_spinbox.value()
|
||||
|
||||
export_format = "퍼센티" if self.percent_radio.isChecked() else "헤이셀러"
|
||||
self.log(f"Exporting data in {export_format} format")
|
||||
|
|
@ -284,7 +344,7 @@ class ExcelProcessorApp(QWidget):
|
|||
self.log("출력 폴더를 선택하지 않았습니다.")
|
||||
return
|
||||
|
||||
self.export_thread = ExportThread(data, export_format, output_folder, original_file_name, exclude_words, ban_words, shuffle_title)
|
||||
self.export_thread = ExportThread(data, export_format, output_folder, original_file_name, exclude_words, ban_words, shuffle_title, price_limit_enabled, price_limit)
|
||||
self.export_thread.log_signal.connect(self.log)
|
||||
self.export_thread.finished_signal.connect(self.on_export_finished)
|
||||
self.export_button.setEnabled(False)
|
||||
|
|
@ -293,12 +353,18 @@ class ExcelProcessorApp(QWidget):
|
|||
def on_export_finished(self):
|
||||
self.export_button.setEnabled(True)
|
||||
|
||||
def toggle_price_limit(self):
|
||||
state = self.price_limit_checkbox.isChecked()
|
||||
self.price_limit_spinbox.setEnabled(state)
|
||||
self.price_limit_label.setEnabled(state)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
ex = ExcelProcessorApp()
|
||||
|
||||
|
||||
# Add signal to save config on exit
|
||||
app.aboutToQuit.connect(ex.save_config)
|
||||
|
||||
|
||||
ex.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue