로그추가
18
config.ini
|
|
@ -1,18 +0,0 @@
|
||||||
[Settings]
|
|
||||||
maxweightset = 10
|
|
||||||
maxlengthset = 100
|
|
||||||
maxvolumeset = 155
|
|
||||||
addfeeinterval = 6
|
|
||||||
addfeesetting = 3
|
|
||||||
addfee = 2000
|
|
||||||
fontsize = 14
|
|
||||||
weightinterval = 0.5
|
|
||||||
setsavesetting = True
|
|
||||||
favoritedelv =
|
|
||||||
|
|
||||||
[Kipris]
|
|
||||||
use_kipris = True
|
|
||||||
usage_mode = api
|
|
||||||
api_key = X9Tz3JqC/JcCwxnNewA6qdloIN6QFIitVBgS1a2KVDYk1AmddaDTvzr6+t3dyLZV3gh2TPXdNhxsRQwaKP673Q==
|
|
||||||
set_status = ['°ÅÀý', 'µî·Ï']
|
|
||||||
|
|
||||||
10
config.json
|
|
@ -6,19 +6,17 @@
|
||||||
"addFeeInterval": 5,
|
"addFeeInterval": 5,
|
||||||
"addFeeSetting": 20,
|
"addFeeSetting": 20,
|
||||||
"addFee": 1000,
|
"addFee": 1000,
|
||||||
"fontSize": 10,
|
"fontSize": 12,
|
||||||
"weightInterval": 0.5,
|
"weightInterval": 0.5,
|
||||||
"setSaveSetting": true,
|
"setSaveSetting": true,
|
||||||
"favoriteDelv": "\ub178\ube60\uafb8\ud574\uc6b4(\ubc30\uc1a1\ube44)"
|
"favoriteDelv": "\ub178\ube60\uafb8\ud574\uc6b4(\ubc30\uc1a1\ube44)"
|
||||||
},
|
},
|
||||||
"Kipris": {
|
"Kipris": {
|
||||||
"use_kipris": true,
|
"use_kipris": true,
|
||||||
"usage_mode": "web",
|
"usage_mode": "api",
|
||||||
"api_key": "",
|
"api_key": "X9Tz3JqC/JcCwxnNewA6qdloIN6QFIitVBgS1a2KVDYk1AmddaDTvzr6+t3dyLZV3gh2TPXdNhxsRQwaKP673Q==",
|
||||||
"set_status": [
|
"set_status": [
|
||||||
"\ub4f1\ub85d",
|
"\ub4f1\ub85d"
|
||||||
"\ucde8\ud558",
|
|
||||||
"\ud3ec\uae30"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
137
delv.py
|
|
@ -14,9 +14,9 @@ from src.kipris_settingUI import SettingsDialog
|
||||||
from src.kipris_api_from_publicdata import Kipris_API
|
from src.kipris_api_from_publicdata import Kipris_API
|
||||||
# from src.kipris_web_from_playwright import Kipris_WEB
|
# from src.kipris_web_from_playwright import Kipris_WEB
|
||||||
from src.kiprisThread import *
|
from src.kiprisThread import *
|
||||||
from src.search_display import TrademarkSearchDisplay
|
# from src.search_display import TrademarkSearchDisplay
|
||||||
from src.result_widget import ResultWidget
|
from src.result_widget import ResultWidget
|
||||||
|
from src.currencyInfo import ExchangeRateScraper
|
||||||
|
|
||||||
def minimize_console():
|
def minimize_console():
|
||||||
""" 콘솔 창을 최소화하는 함수 """
|
""" 콘솔 창을 최소화하는 함수 """
|
||||||
|
|
@ -40,7 +40,8 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.asyncWorker = None
|
self.asyncWorker = None
|
||||||
self.search_keyword = None
|
self.search_keyword = None
|
||||||
self.set_status =[]
|
self.set_status =[]
|
||||||
|
self.web_scraper = None # 웹방식 Playwright 객체 미리 초기화
|
||||||
|
self.currentURL = ""
|
||||||
self.config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')
|
self.config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')
|
||||||
|
|
||||||
self.maxWeightSet = 25
|
self.maxWeightSet = 25
|
||||||
|
|
@ -58,12 +59,12 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.addFeeSetting = 20
|
self.addFeeSetting = 20
|
||||||
self.addFeeInterval = 5
|
self.addFeeInterval = 5
|
||||||
|
|
||||||
|
|
||||||
self.setUSD = None
|
self.setUSD = None
|
||||||
self.setCNY = None
|
self.setCNY = None
|
||||||
self.searchDisplay = TrademarkSearchDisplay()
|
self.currentCurrency = None
|
||||||
|
# self.searchDisplay = TrademarkSearchDisplay()
|
||||||
self.searchDisplayWidget = ResultWidget()
|
self.searchDisplayWidget = ResultWidget()
|
||||||
|
self.currencyInfoObject = ExchangeRateScraper()
|
||||||
|
|
||||||
self.favoriteDelv = ""
|
self.favoriteDelv = ""
|
||||||
|
|
||||||
|
|
@ -108,6 +109,14 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
}
|
}
|
||||||
self.settingDialog = SettingsDialog(parent=self, initial_settings=self.user_settings)
|
self.settingDialog = SettingsDialog(parent=self, initial_settings=self.user_settings)
|
||||||
|
|
||||||
|
currencis = ['USD','CNY']
|
||||||
|
self.currencyInfoObject.getCurrency(currencis)
|
||||||
|
self.setUSD = self.currencyInfoObject.currencyInfo['USD']['basePrice']
|
||||||
|
logger.debug(f"setUSD : {self.setUSD}")
|
||||||
|
self.setCNY = self.currencyInfoObject.currencyInfo['CNY']['basePrice']
|
||||||
|
logger.debug(f"setCNY : {self.setCNY}")
|
||||||
|
self.currentCurrency = self.setCNY
|
||||||
|
|
||||||
def saveSettings(self):
|
def saveSettings(self):
|
||||||
""" 설정을 JSON 파일에 저장합니다. """
|
""" 설정을 JSON 파일에 저장합니다. """
|
||||||
try:
|
try:
|
||||||
|
|
@ -220,7 +229,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
# self.api_key = self.config.get('Kipris', 'api_key', fallback="")
|
# self.api_key = self.config.get('Kipris', 'api_key', fallback="")
|
||||||
# self.set_status = self.config.get('Kipris', 'set_status', fallback="[등록]")
|
# self.set_status = self.config.get('Kipris', 'set_status', fallback="[등록]")
|
||||||
|
|
||||||
# # print(f"use_kipris : {self.use_kipris}, usage_mode : {self.usage_mode}, api_key : {self.api_key}")
|
# # logger.debug(f"use_kipris : {self.use_kipris}, usage_mode : {self.usage_mode}, api_key : {self.api_key}")
|
||||||
# except Exception as e:
|
# except Exception as e:
|
||||||
# logger.error(f"설정을 불러오는 중 오류가 발생했습니다: {e}", exc_info=True)
|
# logger.error(f"설정을 불러오는 중 오류가 발생했습니다: {e}", exc_info=True)
|
||||||
|
|
||||||
|
|
@ -283,17 +292,17 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
if keyword:
|
if keyword:
|
||||||
if keyword and keyword not in self.history: # 중복된 검색어가 아니면 추가
|
if keyword and keyword not in self.history: # 중복된 검색어가 아니면 추가
|
||||||
self.history.append(keyword)
|
self.history.append(keyword)
|
||||||
print(f"검색어 [{keyword}] 히스토리에 추가")
|
logger.debug(f"검색어 [{keyword}] 히스토리에 추가")
|
||||||
|
|
||||||
def load_history(self):
|
def load_history(self):
|
||||||
try:
|
try:
|
||||||
with open("search_history.json", "r") as file:
|
with open("search_history.json", "r") as file:
|
||||||
self.history = json.load(file)
|
self.history = json.load(file)
|
||||||
print(f"self.history file loaded{self.history}")
|
logger.debug(f"self.history file loaded{self.history}")
|
||||||
|
|
||||||
except (FileNotFoundError, json.JSONDecodeError):
|
except (FileNotFoundError, json.JSONDecodeError):
|
||||||
self.history = []
|
self.history = []
|
||||||
print(f"self.history{self.history}")
|
logger.debug(f"self.history{self.history}")
|
||||||
|
|
||||||
def save_history(self):
|
def save_history(self):
|
||||||
with open("search_history.json", "w") as file:
|
with open("search_history.json", "w") as file:
|
||||||
|
|
@ -599,7 +608,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.kipris_layout = QtWidgets.QHBoxLayout(self.kiprisWidget)
|
self.kipris_layout = QtWidgets.QHBoxLayout(self.kiprisWidget)
|
||||||
self.kiprisWidget.setLayout(self.kipris_layout)
|
self.kiprisWidget.setLayout(self.kipris_layout)
|
||||||
self.kiprisWidget.setVisible(False)
|
self.kiprisWidget.setVisible(False)
|
||||||
self.kipris_label = QtWidgets.QLabel("키프리스 검색")
|
self.kipris_label = QtWidgets.QLabel(f"키프리스 검색")
|
||||||
self.kipris_edit = QtWidgets.QLineEdit()
|
self.kipris_edit = QtWidgets.QLineEdit()
|
||||||
self.kipris_btn = QtWidgets.QPushButton("검색")
|
self.kipris_btn = QtWidgets.QPushButton("검색")
|
||||||
self.kipris_btn.clicked.connect(self.kipris_btn_clicked)
|
self.kipris_btn.clicked.connect(self.kipris_btn_clicked)
|
||||||
|
|
@ -620,8 +629,8 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.addInfo_vlayout = QtWidgets.QVBoxLayout(self.addInfoWidget)
|
self.addInfo_vlayout = QtWidgets.QVBoxLayout(self.addInfoWidget)
|
||||||
self.addInfo_h1layout = QtWidgets.QHBoxLayout()
|
self.addInfo_h1layout = QtWidgets.QHBoxLayout()
|
||||||
self.addInfo_h2layout = QtWidgets.QHBoxLayout()
|
self.addInfo_h2layout = QtWidgets.QHBoxLayout()
|
||||||
self.addInfo_vlayout.addLayout(self.addInfo_h1layout)
|
|
||||||
self.addInfo_vlayout.addLayout(self.addInfo_h2layout)
|
self.addInfo_vlayout.addLayout(self.addInfo_h2layout)
|
||||||
|
self.addInfo_vlayout.addLayout(self.addInfo_h1layout)
|
||||||
self.addInfoWidget.setLayout(self.addInfo_vlayout)
|
self.addInfoWidget.setLayout(self.addInfo_vlayout)
|
||||||
self.addInfoWidget.setVisible(True)
|
self.addInfoWidget.setVisible(True)
|
||||||
self.setUSD_label = QtWidgets.QLabel(f"[{self.setUSD}]USD/KRW")
|
self.setUSD_label = QtWidgets.QLabel(f"[{self.setUSD}]USD/KRW")
|
||||||
|
|
@ -647,9 +656,11 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.addInfo2_btn.clicked.connect(self.addInfo2_btn_clicked)
|
self.addInfo2_btn.clicked.connect(self.addInfo2_btn_clicked)
|
||||||
self.addInfo_h2layout.addWidget(self.addInfo2_btn)
|
self.addInfo_h2layout.addWidget(self.addInfo2_btn)
|
||||||
self.addInfo3_btn = QtWidgets.QPushButton("타냐어록")
|
self.addInfo3_btn = QtWidgets.QPushButton("타냐어록")
|
||||||
|
self.addInfo3_btn.setEnabled(False)
|
||||||
self.addInfo3_btn.clicked.connect(self.addInfo3_btn_clicked)
|
self.addInfo3_btn.clicked.connect(self.addInfo3_btn_clicked)
|
||||||
self.addInfo_h2layout.addWidget(self.addInfo3_btn)
|
self.addInfo_h2layout.addWidget(self.addInfo3_btn)
|
||||||
self.addInfo4_btn = QtWidgets.QPushButton("딥러닝번역")
|
self.addInfo4_btn = QtWidgets.QPushButton("딥러닝번역")
|
||||||
|
self.addInfo4_btn.setEnabled(False)
|
||||||
self.addInfo4_btn.clicked.connect(self.addInfo4_btn_clicked)
|
self.addInfo4_btn.clicked.connect(self.addInfo4_btn_clicked)
|
||||||
self.addInfo_h2layout.addWidget(self.addInfo4_btn)
|
self.addInfo_h2layout.addWidget(self.addInfo4_btn)
|
||||||
# self.addInfo_layout.setStretch(0,3)
|
# self.addInfo_layout.setStretch(0,3)
|
||||||
|
|
@ -659,6 +670,35 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.setting_layout.addWidget(self.addInfoWidget) # self.addInfoWidget 설정 레이아웃에 추가
|
self.setting_layout.addWidget(self.addInfoWidget) # self.addInfoWidget 설정 레이아웃에 추가
|
||||||
|
|
||||||
|
|
||||||
|
# 경동택배 무게기준 조정 스핀박스
|
||||||
|
self.changeCurreny_btn = QtWidgets.QPushButton("CNY/KRW")
|
||||||
|
self.changeCurreny_btn.clicked.connect(self.changeCurreny_btn_clicked)
|
||||||
|
|
||||||
|
self.calcCurrency_label = QtWidgets.QLabel("")
|
||||||
|
self.calcCurrency_label.setText(" 원")
|
||||||
|
self.calcCurrency_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
calcCurrency_label_font = QFont()
|
||||||
|
calcCurrency_label_font.setBold(True) # 굵게
|
||||||
|
calcCurrency_label_font.setUnderline(True) # 밑줄
|
||||||
|
calcCurrency_label_font.setWeight(16) # 폰트크기
|
||||||
|
self.calcCurrency_label.setFont(calcCurrency_label_font)
|
||||||
|
|
||||||
|
self.currency_calc_box = QtWidgets.QSpinBox()
|
||||||
|
self.currency_calc_box.setRange(0, 1000000)
|
||||||
|
self.currency_calc_box.setSingleStep(10)
|
||||||
|
self.currency_calc_box.setValue(100)
|
||||||
|
self.currency_calc_box.setSuffix(" CNY")
|
||||||
|
self.currency_calc_box.setAlignment(QtCore.Qt.AlignRight) # 가운데 정렬
|
||||||
|
self.currency_calc_box.valueChanged.connect(self.calcCurrency)
|
||||||
|
self.currency_calc_box_layout = self.create_label_and_spin("환율", self.currency_calc_box)
|
||||||
|
self.currency_calc_box_layout.addWidget(self.calcCurrency_label)
|
||||||
|
self.currency_calc_box_layout.addWidget(self.changeCurreny_btn)
|
||||||
|
self.currency_calc_box_layout.setStretch(0,2)
|
||||||
|
self.currency_calc_box_layout.setStretch(1,4)
|
||||||
|
self.currency_calc_box_layout.setStretch(2,4)
|
||||||
|
self.currency_calc_box_layout.setStretch(3,2)
|
||||||
|
self.setting_layout.addLayout(self.currency_calc_box_layout)
|
||||||
|
|
||||||
# 항상 위에 토글 스위치
|
# 항상 위에 토글 스위치
|
||||||
self.alwaysOnTopSwitch = ToggleSwitch(self.setting_frame)
|
self.alwaysOnTopSwitch = ToggleSwitch(self.setting_frame)
|
||||||
self.alwaysOnTopSwitch.move(10, 10)
|
self.alwaysOnTopSwitch.move(10, 10)
|
||||||
|
|
@ -694,17 +734,17 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
|
|
||||||
# if current_type is not target_type:
|
# if current_type is not target_type:
|
||||||
# # 기존 객체가 다른 타입이면 삭제하고 새로 생성
|
# # 기존 객체가 다른 타입이면 삭제하고 새로 생성
|
||||||
# print(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
|
# logger.debug(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
|
||||||
# self.kiprisAPI.close_Kipris() # 기존객체 리소스 정리
|
# self.kiprisAPI.close_Kipris() # 기존객체 리소스 정리
|
||||||
# del self.kiprisAPI # 기존 객체 참조 제거
|
# del self.kiprisAPI # 기존 객체 참조 제거
|
||||||
# self.kiprisAPI = target_type(self.api_key) # 새 객체 생성
|
# self.kiprisAPI = target_type(self.api_key) # 새 객체 생성
|
||||||
# print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
# logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
||||||
# else:
|
# else:
|
||||||
# print(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
|
# logger.debug(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
|
||||||
# else:
|
# else:
|
||||||
# # 객체가 없으면 새로 생성
|
# # 객체가 없으면 새로 생성
|
||||||
# self.kiprisAPI = Kipris_API(self.api_key) if self.usage_mode == 'api' else Kipris_WEB(self.api_key)
|
# self.kiprisAPI = Kipris_API(self.api_key) if self.usage_mode == 'api' else Kipris_WEB(self.api_key)
|
||||||
# print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
# logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
||||||
|
|
||||||
def initSettings_for_kipris(self):
|
def initSettings_for_kipris(self):
|
||||||
if self.kiprisAPI:
|
if self.kiprisAPI:
|
||||||
|
|
@ -714,7 +754,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
|
|
||||||
if current_type is not target_type:
|
if current_type is not target_type:
|
||||||
# 기존 객체가 다른 타입이면 삭제하고 새로 생성
|
# 기존 객체가 다른 타입이면 삭제하고 새로 생성
|
||||||
print(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
|
logger.debug(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
|
||||||
if isinstance(self.kiprisAPI, AsyncWebSearchWorker):
|
if isinstance(self.kiprisAPI, AsyncWebSearchWorker):
|
||||||
self.kiprisAPI.deleteLater() # 비동기 작업자는 Qt 객체로 관리되므로 deleteLater 사용
|
self.kiprisAPI.deleteLater() # 비동기 작업자는 Qt 객체로 관리되므로 deleteLater 사용
|
||||||
self.kiprisAPI = None
|
self.kiprisAPI = None
|
||||||
|
|
@ -722,18 +762,20 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.kiprisAPI = Kipris_API(self.api_key) # 새 객체 생성
|
self.kiprisAPI = Kipris_API(self.api_key) # 새 객체 생성
|
||||||
else:
|
else:
|
||||||
web_scraper = WebScraper() # WebScraper 인스턴스 생성
|
web_scraper = WebScraper() # WebScraper 인스턴스 생성
|
||||||
self.kiprisAPI = AsyncWebSearchWorker(web_scraper, "") # 초기 키워드는 비워두기
|
self.web_scraper = web_scraper
|
||||||
print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
self.kiprisAPI = AsyncWebSearchWorker(self.web_scraper, "") # 초기 키워드는 비워두기
|
||||||
|
logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
||||||
else:
|
else:
|
||||||
print(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
|
logger.debug(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
|
||||||
else:
|
else:
|
||||||
# 객체가 없으면 새로 생성
|
# 객체가 없으면 새로 생성
|
||||||
if self.usage_mode == 'api':
|
if self.usage_mode == 'api':
|
||||||
self.kiprisAPI = Kipris_API(self.api_key)
|
self.kiprisAPI = Kipris_API(self.api_key)
|
||||||
else:
|
else:
|
||||||
web_scraper = WebScraper() # WebScraper 인스턴스 생성
|
web_scraper = WebScraper() # WebScraper 인스턴스 생성
|
||||||
|
self.web_scraper = web_scraper
|
||||||
self.kiprisAPI = AsyncWebSearchWorker(web_scraper, "") # 초기 키워드는 비워두기
|
self.kiprisAPI = AsyncWebSearchWorker(web_scraper, "") # 초기 키워드는 비워두기
|
||||||
print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
|
||||||
|
|
||||||
def addInfo1_btn_clicked(self):
|
def addInfo1_btn_clicked(self):
|
||||||
pass
|
pass
|
||||||
|
|
@ -761,6 +803,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
if self.use_kipris:
|
if self.use_kipris:
|
||||||
self.kiprisWidget.setVisible(True)
|
self.kiprisWidget.setVisible(True)
|
||||||
self.initSettings_for_kipris()
|
self.initSettings_for_kipris()
|
||||||
|
self.kipris_label.setText(f"키프리스 검색({self.usage_mode})")
|
||||||
else:
|
else:
|
||||||
self.kiprisWidget.setVisible(False)
|
self.kiprisWidget.setVisible(False)
|
||||||
|
|
||||||
|
|
@ -1061,6 +1104,26 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
self.addFeeInterval = value
|
self.addFeeInterval = value
|
||||||
self.updateDeliveryFee()
|
self.updateDeliveryFee()
|
||||||
|
|
||||||
|
def changeCurreny_btn_clicked(self):
|
||||||
|
selected = self.changeCurreny_btn.text()
|
||||||
|
if selected == 'CNY/KRW':
|
||||||
|
self.currency_calc_box.setSuffix(" USD")
|
||||||
|
self.changeCurreny_btn.setText('USD/KRW')
|
||||||
|
self.currentCurrency = self.setUSD
|
||||||
|
else:
|
||||||
|
self.currency_calc_box.setSuffix(" CNY")
|
||||||
|
self.changeCurreny_btn.setText('CNY/KRW')
|
||||||
|
self.currentCurrency = self.setCNY
|
||||||
|
self.calcCurrency(100)
|
||||||
|
|
||||||
|
def calcCurrency(self,value):
|
||||||
|
result = value * self.currentCurrency
|
||||||
|
result = round(result,0)
|
||||||
|
result = '{0:,}'.format(result)
|
||||||
|
# logger.debug(f"result{result}")
|
||||||
|
# logger.debug(f"round(result,2){str(round(result,0))}")
|
||||||
|
self.calcCurrency_label.setText(result+' 원')
|
||||||
|
|
||||||
def isSaveSetting(self, state):
|
def isSaveSetting(self, state):
|
||||||
if state:
|
if state:
|
||||||
self.setSaveSetting = True
|
self.setSaveSetting = True
|
||||||
|
|
@ -1075,10 +1138,10 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{self.search_keyword}]")
|
logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{self.search_keyword}]")
|
||||||
|
|
||||||
# result = self.kiprisAPI.run(self.search_keyword, self.set_status)
|
# result = self.kiprisAPI.run(self.search_keyword, self.set_status)
|
||||||
# print(f"result {result}")
|
# logger.debug(f"result {result}")
|
||||||
|
|
||||||
if self.search_keyword.strip(): # 검색어가 비어있지 않은 경우에만 검색 수행
|
if self.search_keyword.strip(): # 검색어가 비어있지 않은 경우에만 검색 수행
|
||||||
print(f"검색 호출방식 : {self.usage_mode}")
|
logger.debug(f"검색 호출방식 : {self.usage_mode}")
|
||||||
if self.usage_mode == 'web':
|
if self.usage_mode == 'web':
|
||||||
self.handle_search_for_web(self.search_keyword)
|
self.handle_search_for_web(self.search_keyword)
|
||||||
if self.usage_mode == 'api':
|
if self.usage_mode == 'api':
|
||||||
|
|
@ -1089,16 +1152,17 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
if self.asyncWorker: # 기존에 비동기 작업자가 존재한다면
|
if self.asyncWorker: # 기존에 비동기 작업자가 존재한다면
|
||||||
self.asyncWorker.thread.quit() # 기존 스레드 종료
|
self.asyncWorker.thread.quit() # 기존 스레드 종료
|
||||||
|
|
||||||
print(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
|
logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
|
||||||
self.asyncWorker = AsyncWebSearchWorker(keyword, self.set_status) # 새 비동기 작업자 생성
|
self.asyncWorker = AsyncWebSearchWorker(keyword, self.set_status) # 새 비동기 작업자 생성
|
||||||
self.asyncWorker.finished.connect(self.display_results_for_web) # 완료 시그널을 결과 표시 함수에 연결
|
self.asyncWorker.finished.connect(self.display_results_for_web) # 완료 시그널을 결과 표시 함수에 연결
|
||||||
self.asyncWorker.start() # 비동기 작업 시작
|
self.asyncWorker.start() # 비동기 작업 시작
|
||||||
print("비동기 검색 시작")
|
logger.debug("비동기 검색 시작")
|
||||||
|
|
||||||
def display_results_for_web(self, result, elapsed_time):
|
def display_results_for_web(self, result, elapsed_time):
|
||||||
print(f"result : {result}")
|
# logger.debug(f"result : {result}")
|
||||||
|
searchType = 'web'
|
||||||
self.searchDisplayWidget.show_results(result)
|
logger.debug(f"display_results_for_web - currentURL : {self.web_scraper.currentURL}")
|
||||||
|
self.searchDisplayWidget.show_results(result, searchType, elapsed_time, self.web_scraper.currentURL)
|
||||||
|
|
||||||
# self.searchDisplay.display_web_results(result, elapsed_time)
|
# self.searchDisplay.display_web_results(result, elapsed_time)
|
||||||
# self.searchDisplay.show()
|
# self.searchDisplay.show()
|
||||||
|
|
@ -1113,28 +1177,31 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
|
||||||
|
|
||||||
if self.searchThread is not None and self.searchThread.isRunning():
|
if self.searchThread is not None and self.searchThread.isRunning():
|
||||||
self.searchThread.quit() # 이전 스레드가 실행 중이라면 안전하게 종료
|
self.searchThread.quit() # 이전 스레드가 실행 중이라면 안전하게 종료
|
||||||
print("기존 쓰레드가 존재하므로 기존 쓰레드 종료")
|
logger.debug("기존 쓰레드가 존재하므로 기존 쓰레드 종료")
|
||||||
print(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
|
logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
|
||||||
|
|
||||||
worker = APISearchWorker(self.kiprisAPI, keyword, self.set_status)
|
worker = APISearchWorker(self.kiprisAPI, keyword, self.set_status)
|
||||||
|
|
||||||
# worker = SearchWorker(self.kiprisAPI, keyword, self.set_status)
|
# worker = SearchWorker(self.kiprisAPI, keyword, self.set_status)
|
||||||
|
|
||||||
print("워커 생성")
|
logger.debug("워커 생성")
|
||||||
self.searchThread = SearchThread(worker)
|
self.searchThread = SearchThread(worker)
|
||||||
print("쓰레드 생성")
|
logger.debug("쓰레드 생성")
|
||||||
worker.finished.connect(self.display_results_for_api)
|
worker.finished.connect(self.display_results_for_api)
|
||||||
self.searchThread.finished.connect(self.clear_thread_reference)
|
self.searchThread.finished.connect(self.clear_thread_reference)
|
||||||
self.searchThread.start_search()
|
self.searchThread.start_search()
|
||||||
print("검색 시작")
|
logger.debug("검색 시작")
|
||||||
|
|
||||||
def clear_thread_reference(self):
|
def clear_thread_reference(self):
|
||||||
# 스레드 종료 후 참조를 제거하여 다음 검색을 위해 준비
|
# 스레드 종료 후 참조를 제거하여 다음 검색을 위해 준비
|
||||||
self.searchThread = None
|
self.searchThread = None
|
||||||
|
|
||||||
def display_results_for_api(self, result, elapsed_time):
|
def display_results_for_api(self, result, elapsed_time):
|
||||||
|
searchType = 'api'
|
||||||
|
logger.debug(f"display_results_for_api result: {result}")
|
||||||
|
self.searchDisplayWidget.show_results(result, searchType, elapsed_time)
|
||||||
message = f"검색 결과 : {result}\n검색에 걸린 시간: {elapsed_time:.1f}초"
|
message = f"검색 결과 : {result}\n검색에 걸린 시간: {elapsed_time:.1f}초"
|
||||||
QtWidgets.QMessageBox.information(self, "Search Results", message)
|
# QtWidgets.QMessageBox.information(self, "Search Results", message)
|
||||||
|
|
||||||
def reset_action(self):
|
def reset_action(self):
|
||||||
self.lengthInput.setValue(1)
|
self.lengthInput.setValue(1)
|
||||||
|
|
@ -1171,7 +1238,7 @@ if __name__ == '__main__':
|
||||||
minimize_console()
|
minimize_console()
|
||||||
|
|
||||||
app = QtWidgets.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
logger = setup_logger('default_logger', 'delivery_calc.log', level=logging.INFO)
|
logger = setup_logger('default_logger', 'delivery_calc.log', level=logging.DEBUG)
|
||||||
ex = DeliveryFeeCalculator(logger)
|
ex = DeliveryFeeCalculator(logger)
|
||||||
ex.show()
|
ex.show()
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,10 @@
|
||||||
|
|
||||||
a = Analysis(
|
a = Analysis(
|
||||||
['delv.py'],
|
['delv.py'],
|
||||||
pathex=['H:\\py\\delvfee'],
|
pathex=[],
|
||||||
binaries=[],
|
binaries=[],
|
||||||
datas=[],
|
datas=[],
|
||||||
hiddenimports=[
|
hiddenimports=[],
|
||||||
'sip', 'jinja2'
|
|
||||||
],
|
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={},
|
||||||
runtime_hooks=[],
|
runtime_hooks=[],
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ from PyQt5.QtWidgets import QApplication, QMessageBox, QSizePolicy, QWidget, QVB
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
from PyQt5.QtCore import Qt, QByteArray, QBuffer, QIODevice
|
from PyQt5.QtCore import Qt, QByteArray, QBuffer, QIODevice
|
||||||
from kipris_web_from_playwright import WebScraper
|
from kipris_web_from_playwright import WebScraper
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
class MainApp(QWidget):
|
class MainApp(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
@ -163,7 +166,7 @@ class MainApp(QWidget):
|
||||||
self.results_widget.show()
|
self.results_widget.show()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error displaying results: {e}")
|
logger.debug(f"Error displaying results: {e}")
|
||||||
|
|
||||||
|
|
||||||
def close_results_widget(self):
|
def close_results_widget(self):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
import requests
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
|
|
||||||
|
class ExchangeRateScraper:
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.currencyInfo = {}
|
||||||
|
|
||||||
|
self.initUI()
|
||||||
|
|
||||||
|
def initUI(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def getCurrency(self, currencies):
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 동적으로 URL 구성하기
|
||||||
|
codes = ','.join([f'FRX.KRW{currency}' for currency in currencies])
|
||||||
|
url = f'https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes={codes}'
|
||||||
|
|
||||||
|
# url = 'https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes=FRX.KRWUSD,FRX.KRWCNY'
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
exchange_rates = response.json()
|
||||||
|
for rate in exchange_rates:
|
||||||
|
currency_code = rate['currencyCode']
|
||||||
|
if currency_code in currencies:
|
||||||
|
# 해당 통화 정보 저장
|
||||||
|
self.currencyInfo[currency_code] = {
|
||||||
|
'basePrice': rate['basePrice'],
|
||||||
|
'modifiedAt': rate['modifiedAt'],
|
||||||
|
'provider': rate['provider']
|
||||||
|
}
|
||||||
|
logger.debug("Exchange rates updated.")
|
||||||
|
else:
|
||||||
|
logger.error("Failed to retrieve data")
|
||||||
|
|
||||||
|
|
||||||
|
def get_Currency_Info(self, currency):
|
||||||
|
# 특정 통화 정보 출력 메서드
|
||||||
|
if currency in self.currencyInfo:
|
||||||
|
info = self.currencyInfo[currency]
|
||||||
|
|
||||||
|
logger.debug(f"Currency: {currency}")
|
||||||
|
logger.debug(f"Base Price: {info['basePrice']}")
|
||||||
|
logger.debug(f"Modified At: {info['modifiedAt']}")
|
||||||
|
logger.debug(f"Provider: {info['provider']}")
|
||||||
|
else:
|
||||||
|
logger.debug(f"No data available for {currency}")
|
||||||
|
|
||||||
|
# # 클래스 메서드 사용 예제
|
||||||
|
# scraper = ExchangeRateScraper()
|
||||||
|
# scraper.getCurrency(['USD', 'CNY']) # USD와 CNY 환율 정보를 요청
|
||||||
|
# scraper.get_Currency_Info('USD')
|
||||||
|
# scraper.get_Currency_Info('CNY')
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
||||||
import time
|
import time
|
||||||
from src.web_scraper_async import *
|
from src.web_scraper_async import *
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
class APISearchWorker(QObject):
|
class APISearchWorker(QObject):
|
||||||
finished = pyqtSignal(list, float)
|
finished = pyqtSignal(dict, float)
|
||||||
|
|
||||||
def __init__(self, kiprisObject, keyword, set_status):
|
def __init__(self, kiprisObject, keyword, set_status):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
@ -13,9 +16,9 @@ class APISearchWorker(QObject):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
start_time = time.time() # 검색 시작 시간
|
start_time = time.time() # 검색 시작 시간
|
||||||
print(f"Search keyword : [{self.keyword}], self.set_status : [{self.set_status}]")
|
logger.debug(f"Search keyword : [{self.keyword}], self.set_status : [{self.set_status}]")
|
||||||
result = self.kiprisObject.run(self.keyword, self.set_status)
|
result = self.kiprisObject.run(self.keyword, self.set_status)
|
||||||
print(f"Search finished | result \n [{result}]")
|
logger.debug(f"Search finished | result \n {result}")
|
||||||
elapsed_time = time.time() - start_time # 경과 시간 계산
|
elapsed_time = time.time() - start_time # 경과 시간 계산
|
||||||
self.finished.emit(result, elapsed_time)
|
self.finished.emit(result, elapsed_time)
|
||||||
|
|
||||||
|
|
@ -36,7 +39,7 @@ class SearchThread(QThread):
|
||||||
|
|
||||||
def handle_finished(self, result, elapsed_time):
|
def handle_finished(self, result, elapsed_time):
|
||||||
# 검색 작업이 완료되면 이 시그널이 발생합니다.
|
# 검색 작업이 완료되면 이 시그널이 발생합니다.
|
||||||
print(f"Search finished : [{elapsed_time}]초 경과")
|
logger.debug(f"Search finished : [{elapsed_time}]초 경과")
|
||||||
|
|
||||||
|
|
||||||
class AsyncWebSearchWorker(QObject):
|
class AsyncWebSearchWorker(QObject):
|
||||||
|
|
@ -68,7 +71,7 @@ class AsyncWebSearchWorker(QObject):
|
||||||
elapsed_time = time.time() - self.start_time # 소요 시간 계산
|
elapsed_time = time.time() - self.start_time # 소요 시간 계산
|
||||||
self.finished.emit(result, elapsed_time) # 작업 완료 신호 전송
|
self.finished.emit(result, elapsed_time) # 작업 완료 신호 전송
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error in AsyncWebSearchWorker: {e}")
|
logger.debug(f"Error in AsyncWebSearchWorker: {e}")
|
||||||
self.finished.emit(None, 0) # 에러 발생 시 None 전송
|
self.finished.emit(None, 0) # 에러 발생 시 None 전송
|
||||||
finally:
|
finally:
|
||||||
await self.scraper.close_Kipris() # 리소스 정리
|
await self.scraper.close_Kipris() # 리소스 정리
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
import requests
|
import requests, json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
|
|
||||||
class Kipris_API:
|
class Kipris_API:
|
||||||
def __init__(self, apikey=None):
|
def __init__(self, apikey=None):
|
||||||
self.url = 'http://kipo-api.kipi.or.kr/openapi/service/trademarkInfoSearchService/getWordSearch'
|
self.url = 'http://kipo-api.kipi.or.kr/openapi/service/trademarkInfoSearchService/getWordSearch'
|
||||||
self.apikey = apikey
|
self.apikey = apikey
|
||||||
self.results = []
|
self.results = {}
|
||||||
|
filename = 'categories.json'
|
||||||
|
self.category_description = self.load_category_descriptions(filename)
|
||||||
|
|
||||||
def fetch_and_decode(self, params):
|
def fetch_and_decode(self, params):
|
||||||
# API 요청 및 응답 받기
|
# API 요청 및 응답 받기
|
||||||
|
|
@ -14,7 +20,7 @@ class Kipris_API:
|
||||||
decoded_data = response.content.decode('utf-8')
|
decoded_data = response.content.decode('utf-8')
|
||||||
return decoded_data
|
return decoded_data
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"키프리스 요청 중 에러발생 : {e}")
|
logger.error(f"키프리스 요청 중 에러발생 : {e}")
|
||||||
|
|
||||||
def parse_xml(self, xml_data, status):
|
def parse_xml(self, xml_data, status):
|
||||||
# XML 데이터 파싱
|
# XML 데이터 파싱
|
||||||
|
|
@ -24,10 +30,15 @@ class Kipris_API:
|
||||||
status_published = 0
|
status_published = 0
|
||||||
|
|
||||||
# 'body/items/item' 경로에 맞춰 'item' 태그를 순회하면서 필요한 데이터 추출
|
# 'body/items/item' 경로에 맞춰 'item' 태그를 순회하면서 필요한 데이터 추출
|
||||||
for item in root.findall('.//body/items/item'):
|
for i, item in enumerate(root.findall('.//body/items/item')):
|
||||||
total_items += 1
|
total_items += 1
|
||||||
application_status = item.find('applicationStatus').text if item.find('applicationStatus') is not None else None
|
application_status = item.find('applicationStatus').text if item.find('applicationStatus') is not None else None
|
||||||
|
|
||||||
|
product_category = item.find('classificationCode').text if item.find('classificationCode') is not None else None
|
||||||
|
if product_category:
|
||||||
|
category_desc = self.add_category_description(product_category) if product_category else "No category description"
|
||||||
|
else:
|
||||||
|
category_desc = None
|
||||||
# 각 상태의 개수를 카운트
|
# 각 상태의 개수를 카운트
|
||||||
if application_status == "등록":
|
if application_status == "등록":
|
||||||
status_registered += 1
|
status_registered += 1
|
||||||
|
|
@ -36,7 +47,8 @@ class Kipris_API:
|
||||||
|
|
||||||
# if application_status in ["등록", "공개"]:
|
# if application_status in ["등록", "공개"]:
|
||||||
if application_status in status: # status는 self.set_status 리스트를 참조
|
if application_status in status: # status는 self.set_status 리스트를 참조
|
||||||
result = {
|
|
||||||
|
self.results[f"result_{i+1}"] = {
|
||||||
"index_no": item.find('indexNo').text if item.find('indexNo') is not None else None,
|
"index_no": item.find('indexNo').text if item.find('indexNo') is not None else None,
|
||||||
"application_number": item.find('applicationNumber').text if item.find('applicationNumber') is not None else None,
|
"application_number": item.find('applicationNumber').text if item.find('applicationNumber') is not None else None,
|
||||||
"application_date": item.find('applicationDate').text if item.find('applicationDate') is not None else None,
|
"application_date": item.find('applicationDate').text if item.find('applicationDate') is not None else None,
|
||||||
|
|
@ -51,14 +63,16 @@ class Kipris_API:
|
||||||
"big_drawing_url": item.find('bigDrawing').text if item.find('bigDrawing') is not None else None,
|
"big_drawing_url": item.find('bigDrawing').text if item.find('bigDrawing') is not None else None,
|
||||||
"full_text": item.find('fullText').text if item.find('fullText') is not None else None,
|
"full_text": item.find('fullText').text if item.find('fullText') is not None else None,
|
||||||
"application_status": application_status,
|
"application_status": application_status,
|
||||||
"classification_code": item.find('classificationCode').text if item.find('classificationCode') is not None else None
|
"classification_code": item.find('classificationCode').text if item.find('classificationCode') is not None else None,
|
||||||
|
"category_description": category_desc
|
||||||
}
|
}
|
||||||
self.results.append(result)
|
# self.results.append(result)
|
||||||
|
|
||||||
# 상태 개수와 총 아이템 개수 출력
|
# 상태 개수와 총 아이템 개수 출력
|
||||||
print(f"검색된 item 총 개수: {total_items}")
|
logger.debug(f"검색된 item 총 개수: {total_items}")
|
||||||
print(f"등록 상태인 item 개수: {status_registered}")
|
self.results['total_count'] = total_items
|
||||||
print(f"공개 상태인 item 개수: {status_published}")
|
logger.debug(f"등록 상태인 item 개수: {status_registered}")
|
||||||
|
logger.debug(f"공개 상태인 item 개수: {status_published}")
|
||||||
|
|
||||||
def get_results(self):
|
def get_results(self):
|
||||||
return self.results
|
return self.results
|
||||||
|
|
@ -73,9 +87,25 @@ class Kipris_API:
|
||||||
'drawing': '',
|
'drawing': '',
|
||||||
'bigDrawing': ''
|
'bigDrawing': ''
|
||||||
}
|
}
|
||||||
xml_data = self.fetch_and_decode(params)
|
logger.debug(f" Search params : {params}")
|
||||||
self.parse_xml(xml_data, status)
|
try:
|
||||||
|
xml_data = self.fetch_and_decode(params)
|
||||||
|
self.parse_xml(xml_data, status)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"API 요청 중 에러발생 : {e}")
|
||||||
|
|
||||||
return self.get_results()
|
return self.get_results()
|
||||||
|
|
||||||
def close_Kipris(self):
|
def close_Kipris(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def load_category_descriptions(self, filename):
|
||||||
|
"""JSON 파일에서 카테고리 설명을 로드합니다."""
|
||||||
|
with open(filename, 'r', encoding='utf-8') as file:
|
||||||
|
return json.load(file)
|
||||||
|
|
||||||
|
def add_category_description(self, category_code):
|
||||||
|
"""주어진 카테고리 코드에 따라 설명을 반환합니다."""
|
||||||
|
logger.debug(f"add_category_description => category_code: {category_code}")
|
||||||
|
return self.category_description.get(category_code, "카테고리 설명을 찾을 수 없습니다.")
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
|
@ -3,7 +3,10 @@ from PyQt5.QtCore import QUrl
|
||||||
from PyQt5.QtGui import QDesktopServices
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
|
||||||
from src.toggleSwitch import ToggleSwitch
|
from src.toggleSwitch import ToggleSwitch
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
class SettingsDialog(QtWidgets.QDialog):
|
class SettingsDialog(QtWidgets.QDialog):
|
||||||
def __init__(self, parent=None, initial_settings=None):
|
def __init__(self, parent=None, initial_settings=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
@ -42,6 +45,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||||
|
|
||||||
|
|
||||||
def setupUI(self):
|
def setupUI(self):
|
||||||
|
logger.debug(f"setupUI 시작")
|
||||||
# 셋업 메인 레이아웃
|
# 셋업 메인 레이아웃
|
||||||
self.mainLayout = QtWidgets.QVBoxLayout(self)
|
self.mainLayout = QtWidgets.QVBoxLayout(self)
|
||||||
|
|
||||||
|
|
@ -207,7 +211,9 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
def loadSettings(self, settings):
|
def loadSettings(self, settings):
|
||||||
# print(f"SettingsDialog settings : {settings}")
|
logger.debug(f"loadSettings 시작")
|
||||||
|
|
||||||
|
# logger.debug(f"SettingsDialog settings : {settings}")
|
||||||
|
|
||||||
self.use_kipris = settings.get('use_kipris', False) # 기본값 False로 설정
|
self.use_kipris = settings.get('use_kipris', False) # 기본값 False로 설정
|
||||||
self.usage_mode = settings.get('usage_mode', 'web') # 기본값 'web'로 설정
|
self.usage_mode = settings.get('usage_mode', 'web') # 기본값 'web'로 설정
|
||||||
|
|
@ -215,10 +221,10 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||||
self.set_status = settings.get('set_status', []) # 기본값 빈 리스트로 설정
|
self.set_status = settings.get('set_status', []) # 기본값 빈 리스트로 설정
|
||||||
|
|
||||||
# 상태 업데이트 로그 출력
|
# 상태 업데이트 로그 출력
|
||||||
# print(f"SettingsDialog Loaded settings: use_kipris={self.use_kipris}, usage_mode={self.usage_mode}, api_key={self.api_key}")
|
# logger.debug(f"SettingsDialog Loaded settings: use_kipris={self.use_kipris}, usage_mode={self.usage_mode}, api_key={self.api_key}")
|
||||||
|
|
||||||
|
|
||||||
# print(f"SettingsDialog self.use_kipris : {self.use_kipris}")
|
# logger.debug(f"SettingsDialog self.use_kipris : {self.use_kipris}")
|
||||||
# UI 업데이트
|
# UI 업데이트
|
||||||
self.isUseKiprisSwitch.setChecked(self.use_kipris)
|
self.isUseKiprisSwitch.setChecked(self.use_kipris)
|
||||||
self.apikeySwitch.setChecked(self.usage_mode == 'api')
|
self.apikeySwitch.setChecked(self.usage_mode == 'api')
|
||||||
|
|
@ -246,17 +252,19 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||||
def toggleCNYexchange(self, checked):
|
def toggleCNYexchange(self, checked):
|
||||||
self.exchangeCNYSwitch.setChecked(checked)
|
self.exchangeCNYSwitch.setChecked(checked)
|
||||||
self.setCNY = checked
|
self.setCNY = checked
|
||||||
print(f"self.setCNY : {self.setCNY}")
|
logger.debug(f"self.setCNY : {self.setCNY}")
|
||||||
def toggleUSDexchange(self, checked):
|
|
||||||
|
|
||||||
|
def toggleUSDexchange(self, checked):
|
||||||
self.exchangeUSDSwitch.setChecked(checked)
|
self.exchangeUSDSwitch.setChecked(checked)
|
||||||
self.setUSD = checked
|
self.setUSD = checked
|
||||||
print(f"self.setUSD : {self.setUSD}")
|
logger.debug(f"self.setUSD : {self.setUSD}")
|
||||||
|
|
||||||
def toggleKiprisUsage(self, checked):
|
def toggleKiprisUsage(self, checked):
|
||||||
self.settingKiprisWidget.setVisible(checked)
|
self.settingKiprisWidget.setVisible(checked)
|
||||||
self.checkWidget.setVisible(checked)
|
self.checkWidget.setVisible(checked)
|
||||||
self.use_kipris = checked
|
self.use_kipris = checked
|
||||||
|
logger.debug(f"self.use_kipris : {self.use_kipris}")
|
||||||
|
|
||||||
# self.kiprisFrame.setVisible(False)
|
# self.kiprisFrame.setVisible(False)
|
||||||
|
|
||||||
def toggleAPIUsage(self, checked):
|
def toggleAPIUsage(self, checked):
|
||||||
|
|
@ -264,12 +272,14 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||||
self.useWebSwitch.setChecked(not checked)
|
self.useWebSwitch.setChecked(not checked)
|
||||||
self.editAPIWidget.setVisible(checked)
|
self.editAPIWidget.setVisible(checked)
|
||||||
self.usage_mode = 'api' if checked else 'web'
|
self.usage_mode = 'api' if checked else 'web'
|
||||||
|
logger.debug(f"self.usage_mode : {self.usage_mode}")
|
||||||
|
|
||||||
def toggleWebUsage(self, checked):
|
def toggleWebUsage(self, checked):
|
||||||
self.useWebSwitch.setChecked(checked)
|
self.useWebSwitch.setChecked(checked)
|
||||||
self.apikeySwitch.setChecked(not checked)
|
self.apikeySwitch.setChecked(not checked)
|
||||||
self.editAPIWidget.setVisible(not checked)
|
self.editAPIWidget.setVisible(not checked)
|
||||||
self.usage_mode = 'web' if checked else 'api'
|
self.usage_mode = 'web' if checked else 'api'
|
||||||
|
logger.debug(f"self.usage_mode : {self.usage_mode}")
|
||||||
|
|
||||||
def create_label_and_switch(self, widget, label_text, target_switch):
|
def create_label_and_switch(self, widget, label_text, target_switch):
|
||||||
layout = QtWidgets.QHBoxLayout()
|
layout = QtWidgets.QHBoxLayout()
|
||||||
|
|
@ -306,36 +316,51 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||||
if status in self.set_status:
|
if status in self.set_status:
|
||||||
self.set_status.remove(status)
|
self.set_status.remove(status)
|
||||||
|
|
||||||
# print("Current Status List:", self.set_status)
|
logger.debug(f"self.set_status : {self.set_status}")
|
||||||
|
|
||||||
|
# logger.debug("Current Status List:", self.set_status)
|
||||||
|
|
||||||
def handle_all_checked(self, state):
|
def handle_all_checked(self, state):
|
||||||
if state == QtCore.Qt.Checked:
|
if state == QtCore.Qt.Checked:
|
||||||
for checkbox in self.checkboxes:
|
self.right_rejected_checkbox.setChecked(True)
|
||||||
checkbox.setChecked(True)
|
self.right_registered_checkbox.setChecked(True)
|
||||||
|
self.right_expiration_checkbox.setChecked(True)
|
||||||
|
self.right_void_checkbox.setChecked(True)
|
||||||
|
self.right_Withdrawal_checkbox.setChecked(True)
|
||||||
|
self.right_remise_checkbox.setChecked(True)
|
||||||
|
self.right_Disclosure_checkbox.setChecked(True)
|
||||||
|
|
||||||
elif state == QtCore.Qt.Unchecked:
|
elif state == QtCore.Qt.Unchecked:
|
||||||
for checkbox in self.checkboxes[1:]: # "등록" 체크박스 제외
|
self.right_rejected_checkbox.setChecked(False)
|
||||||
checkbox.setChecked(False)
|
self.right_expiration_checkbox.setChecked(False)
|
||||||
self.checkboxes[0].setChecked(True) # "등록" 체크박스는 항상 체크
|
self.right_void_checkbox.setChecked(False)
|
||||||
|
self.right_Withdrawal_checkbox.setChecked(False)
|
||||||
|
self.right_remise_checkbox.setChecked(False)
|
||||||
|
self.right_Disclosure_checkbox.setChecked(False)
|
||||||
|
|
||||||
def handle_checkbox_state_changed(self):
|
self.right_registered_checkbox.setChecked(True) # "등록" 체크박스는 항상 체크
|
||||||
for checkbox in self.checkboxes:
|
|
||||||
# 글자를 진하게 만들기
|
|
||||||
font = checkbox.font()
|
|
||||||
font.setBold(checkbox.isChecked())
|
|
||||||
checkbox.setFont(font)
|
|
||||||
|
|
||||||
# 전체 체크 상태 업데이트
|
logger.debug(f"all_checked : {state}")
|
||||||
all_checked = all(checkbox.isChecked() for checkbox in self.checkboxes)
|
|
||||||
all_unchecked = all(not checkbox.isChecked() for checkbox in self.checkboxes[1:]) # "등록" 제외
|
|
||||||
|
|
||||||
self.all_checkbox.blockSignals(True) # 시그널 일시 중지
|
# def handle_checkbox_state_changed(self):
|
||||||
if all_checked:
|
# for checkbox in self.checkboxes:
|
||||||
self.all_checkbox.setCheckState(QtCore.Qt.Checked)
|
# # 글자를 진하게 만들기
|
||||||
elif all_unchecked:
|
# font = checkbox.font()
|
||||||
self.all_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
# font.setBold(checkbox.isChecked())
|
||||||
else:
|
# checkbox.setFont(font)
|
||||||
self.all_checkbox.setCheckState(QtCore.Qt.PartiallyChecked)
|
|
||||||
self.all_checkbox.blockSignals(False) # 시그널 재개
|
# # 전체 체크 상태 업데이트
|
||||||
|
# all_checked = all(checkbox.isChecked() for checkbox in self.checkboxes)
|
||||||
|
# all_unchecked = all(not checkbox.isChecked() for checkbox in self.checkboxes[1:]) # "등록" 제외
|
||||||
|
|
||||||
|
# self.all_checkbox.blockSignals(True) # 시그널 일시 중지
|
||||||
|
# if all_checked:
|
||||||
|
# self.all_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||||
|
# elif all_unchecked:
|
||||||
|
# self.all_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||||
|
# else:
|
||||||
|
# self.all_checkbox.setCheckState(QtCore.Qt.PartiallyChecked)
|
||||||
|
# self.all_checkbox.blockSignals(False) # 시그널 재개
|
||||||
|
|
||||||
|
|
||||||
class HelpDialog(QtWidgets.QDialog):
|
class HelpDialog(QtWidgets.QDialog):
|
||||||
|
|
@ -354,9 +379,14 @@ class HelpDialog(QtWidgets.QDialog):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.resize(400, 300) # 단독 실행 시 크기 설정
|
self.resize(400, 300) # 단독 실행 시 크기 설정
|
||||||
|
|
||||||
|
logger.debug(f"HelpDialog 초기화")
|
||||||
|
|
||||||
self.setupUI()
|
self.setupUI()
|
||||||
|
|
||||||
def setupUI(self):
|
def setupUI(self):
|
||||||
|
logger.debug(f"HelpDialog setupUI 로드")
|
||||||
|
|
||||||
layout = QtWidgets.QVBoxLayout(self)
|
layout = QtWidgets.QVBoxLayout(self)
|
||||||
textBrowser = QtWidgets.QTextBrowser(self)
|
textBrowser = QtWidgets.QTextBrowser(self)
|
||||||
textBrowser.setOpenExternalLinks(False) # 외부 링크 자동 열기 비활성화
|
textBrowser.setOpenExternalLinks(False) # 외부 링크 자동 열기 비활성화
|
||||||
|
|
@ -387,10 +417,6 @@ class HelpDialog(QtWidgets.QDialog):
|
||||||
QDesktopServices.openUrl(url)
|
QDesktopServices.openUrl(url)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ※ 행정 상태 도움말
|
# ※ 행정 상태 도움말
|
||||||
# 거절 : 출원 후 특허 심사과정에서 실체적인 특허 등록요건을 만족하지 못할 경우에 심사관이 취하는 행정처분
|
# 거절 : 출원 후 특허 심사과정에서 실체적인 특허 등록요건을 만족하지 못할 경우에 심사관이 취하는 행정처분
|
||||||
# 등록 : 심사관이 심사한 결과 등록요건에 적합하여 설정등록을 받을 수 있다는 내용의 행정처분
|
# 등록 : 심사관이 심사한 결과 등록요건에 적합하여 설정등록을 받을 수 있다는 내용의 행정처분
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ import random, requests, json
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import os
|
import os
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
class Kipris_WEB:
|
class Kipris_WEB:
|
||||||
def __init__(self, apikey=None):
|
def __init__(self, apikey=None):
|
||||||
self.apikey = apikey
|
self.apikey = apikey
|
||||||
|
|
@ -42,45 +45,45 @@ class Kipris_WEB:
|
||||||
|
|
||||||
def run(self, term, status):
|
def run(self, term, status):
|
||||||
"""검색어로 검색하고 결과 수집"""
|
"""검색어로 검색하고 결과 수집"""
|
||||||
print(f"Playwright 검색시작 : 키워드 : [{term}]")
|
logger.debug(f"Playwright 검색시작 : 키워드 : [{term}]")
|
||||||
try:
|
try:
|
||||||
self.page.fill("#queryText", term)
|
self.page.fill("#queryText", term)
|
||||||
self.page.click(".input_btn")
|
self.page.click(".input_btn")
|
||||||
|
|
||||||
# JavaScript에 의해 결과가 동적으로 로드되기를 기다립니다.
|
# JavaScript에 의해 결과가 동적으로 로드되기를 기다립니다.
|
||||||
loaded = self.page.wait_for_function("document.querySelector('form#listForm section.search_section article') != null")
|
loaded = self.page.wait_for_function("document.querySelector('form#listForm section.search_section article') != null")
|
||||||
print("검색페이지 로드 완료")
|
logger.debug("검색페이지 로드 완료")
|
||||||
if not loaded:
|
if not loaded:
|
||||||
print("검색 결과가 시간 내에 로드되지 않았습니다.")
|
logger.debug("검색 결과가 시간 내에 로드되지 않았습니다.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 검색 결과가 없는지 확인
|
# 검색 결과가 없는지 확인
|
||||||
nodata_info = self.page.query_selector(".nodata_info")
|
nodata_info = self.page.query_selector(".nodata_info")
|
||||||
if nodata_info:
|
if nodata_info:
|
||||||
print("검색 결과가 없습니다.")
|
logger.debug("검색 결과가 없습니다.")
|
||||||
# 특정 메서드 호출 및 함수 종료
|
# 특정 메서드 호출 및 함수 종료
|
||||||
# self.handle_no_search_results()
|
# self.handle_no_search_results()
|
||||||
return None
|
return None
|
||||||
print("검색 결과 로딩 후 실제 요소 수집 시작")
|
logger.debug("검색 결과 로딩 후 실제 요소 수집 시작")
|
||||||
|
|
||||||
# 결과 로딩이 확인된 후, 실제 요소를 수집
|
# 결과 로딩이 확인된 후, 실제 요소를 수집
|
||||||
self.page.wait_for_selector("form#listForm section.search_section", state="visible", timeout=10000)
|
self.page.wait_for_selector("form#listForm section.search_section", state="visible", timeout=10000)
|
||||||
print("listForm")
|
logger.debug("listForm")
|
||||||
total_count = self.page.text_content("form#listForm section.search_section div p span.total")
|
total_count = self.page.text_content("form#listForm section.search_section div p span.total")
|
||||||
print(f"total_count : {total_count}")
|
logger.debug(f"total_count : {total_count}")
|
||||||
if total_count:
|
if total_count:
|
||||||
self.results['total_count'] = total_count.strip()
|
self.results['total_count'] = total_count.strip()
|
||||||
articles = self.page.query_selector_all("form#listForm section.search_section article")
|
articles = self.page.query_selector_all("form#listForm section.search_section article")
|
||||||
print(f"articles : {len(articles)}")
|
logger.debug(f"articles : {len(articles)}")
|
||||||
|
|
||||||
for i, article in enumerate(articles):
|
for i, article in enumerate(articles):
|
||||||
id_and_name_element = article.query_selector("div:nth-child(1) span input[type='checkbox']")
|
id_and_name_element = article.query_selector("div:nth-child(1) span input[type='checkbox']")
|
||||||
trademark_name = id_and_name_element.get_attribute("title") if id_and_name_element else "No name found"
|
trademark_name = id_and_name_element.get_attribute("title") if id_and_name_element else "No name found"
|
||||||
print(f"trademark_name : {trademark_name}")
|
logger.debug(f"trademark_name : {trademark_name}")
|
||||||
applno = id_and_name_element.get_attribute("value") if id_and_name_element else "No ID found"
|
applno = id_and_name_element.get_attribute("value") if id_and_name_element else "No ID found"
|
||||||
if applno:
|
if applno:
|
||||||
trademark_image_url_by_id = f"http://kdtj.kipris.or.kr/kdtj/remoteFile.do?method=bigImageTM&applno={applno}&no={applno}_tm000001.jpg"
|
trademark_image_url_by_id = f"http://kdtj.kipris.or.kr/kdtj/remoteFile.do?method=bigImageTM&applno={applno}&no={applno}_tm000001.jpg"
|
||||||
print(f"applno : {applno}")
|
logger.debug(f"applno : {applno}")
|
||||||
img_element = article.query_selector("div:nth-child(2) div a img")
|
img_element = article.query_selector("div:nth-child(2) div a img")
|
||||||
trademark_image = img_element.get_attribute("src") if img_element else "No image found"
|
trademark_image = img_element.get_attribute("src") if img_element else "No image found"
|
||||||
|
|
||||||
|
|
@ -107,7 +110,7 @@ class Kipris_WEB:
|
||||||
# Use the title attribute of the checkbox input for the trademark name
|
# Use the title attribute of the checkbox input for the trademark name
|
||||||
# name_element = article.query_selector("div:nth-child(1) span input[type='checkbox']")
|
# name_element = article.query_selector("div:nth-child(1) span input[type='checkbox']")
|
||||||
# trademark_name = name_element.get_attribute("title") if name_element else "No name found"
|
# trademark_name = name_element.get_attribute("title") if name_element else "No name found"
|
||||||
print(f"아이템 정보 변수 만들기")
|
logger.debug(f"아이템 정보 변수 만들기")
|
||||||
|
|
||||||
# if not admin_status == "소멸":
|
# if not admin_status == "소멸":
|
||||||
if admin_status in status:
|
if admin_status in status:
|
||||||
|
|
@ -123,12 +126,12 @@ class Kipris_WEB:
|
||||||
"publication_date": publication_date,
|
"publication_date": publication_date,
|
||||||
"registration_date": registration_date,
|
"registration_date": registration_date,
|
||||||
}
|
}
|
||||||
print("리턴")
|
logger.debug("리턴")
|
||||||
return self.results
|
return self.results
|
||||||
else:
|
else:
|
||||||
print("No total count element found, possibly incorrect selector or page structure has changed.")
|
logger.debug("No total count element found, possibly incorrect selector or page structure has changed.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"오류 발생 : {e}")
|
logger.debug(f"오류 발생 : {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def download_image(url, applno):
|
def download_image(url, applno):
|
||||||
|
|
@ -138,9 +141,9 @@ class Kipris_WEB:
|
||||||
filename = f"{applno}.jpeg" # 파일 이름을 ID로 설정
|
filename = f"{applno}.jpeg" # 파일 이름을 ID로 설정
|
||||||
with open(filename, 'wb') as file:
|
with open(filename, 'wb') as file:
|
||||||
file.write(response.content)
|
file.write(response.content)
|
||||||
print(f"이미지가 성공적으로 저장되었습니다: {filename}")
|
logger.debug(f"이미지가 성공적으로 저장되었습니다: {filename}")
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
||||||
|
|
||||||
def load_category_descriptions(self, filename):
|
def load_category_descriptions(self, filename):
|
||||||
"""JSON 파일에서 카테고리 설명을 로드합니다."""
|
"""JSON 파일에서 카테고리 설명을 로드합니다."""
|
||||||
|
|
@ -167,10 +170,10 @@ class Kipris_WEB:
|
||||||
image.save(buffer, 'JPEG') # 예시로 JPEG 포맷을 사용
|
image.save(buffer, 'JPEG') # 예시로 JPEG 포맷을 사용
|
||||||
return buffer.getvalue()
|
return buffer.getvalue()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"이미지 변환 실패: {e}")
|
logger.debug(f"이미지 변환 실패: {e}")
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def close_Kipris(self):
|
def close_Kipris(self):
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,16 @@ import sys
|
||||||
from PyQt5.QtWidgets import QSizePolicy, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QGridLayout
|
from PyQt5.QtWidgets import QSizePolicy, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QGridLayout
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
|
# from PyQt5.Qt import QDesktopServices
|
||||||
|
import webbrowser
|
||||||
import requests
|
import requests
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import asyncio, aiofiles, aiohttp
|
import asyncio, aiofiles, aiohttp
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
class ResultWidget(QWidget):
|
class ResultWidget(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
@ -15,64 +20,82 @@ class ResultWidget(QWidget):
|
||||||
def initUI(self):
|
def initUI(self):
|
||||||
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
|
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
|
||||||
|
|
||||||
def show_results(self, results):
|
def show_results(self, results, searchType, elapsed_time, currentURL=''):
|
||||||
|
searchType = searchType
|
||||||
|
elapsed_time = elapsed_time
|
||||||
|
currentURL = currentURL
|
||||||
|
logger.debug(f"show_results - searchType : {searchType}")
|
||||||
|
logger.debug(f"show_results - elapsed_time : {elapsed_time}")
|
||||||
|
# try:
|
||||||
|
# 결과 위젯 생성
|
||||||
|
self.results_widget = QWidget()
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
self.results_widget.setLayout(layout)
|
||||||
|
|
||||||
try:
|
# 결과 갯수 확인 및 레이아웃 동적 생성
|
||||||
# 결과 위젯 생성
|
total_count = int(results['total_count'])
|
||||||
self.results_widget = QWidget()
|
set_count = min(total_count, 10)
|
||||||
layout = QVBoxLayout()
|
grid_layout = QGridLayout()
|
||||||
self.results_widget.setLayout(layout)
|
layout.addLayout(grid_layout)
|
||||||
|
grid_index = 0
|
||||||
|
grid_columns = 5
|
||||||
|
logger.debug(f"show_results - set_count : {set_count}")
|
||||||
|
|
||||||
# 결과 갯수 확인 및 레이아웃 동적 생성
|
for i in range(1, set_count + 1):
|
||||||
total_count = int(results['total_count'])
|
result_key = f"result_{i}"
|
||||||
set_count = min(total_count, 10)
|
if result_key in results:
|
||||||
grid_layout = QGridLayout()
|
result = results[result_key]
|
||||||
layout.addLayout(grid_layout)
|
logger.debug(f"show_results - result_key : {result_key}")
|
||||||
grid_index = 0
|
|
||||||
grid_columns = 5
|
|
||||||
|
|
||||||
for i in range(1, set_count + 1):
|
# 테두리 설정
|
||||||
result_key = f"result_{i}"
|
border_style = ''
|
||||||
if result_key in results:
|
if result['application_status'] == '등록':
|
||||||
result = results[result_key]
|
border_style = 'border: 4px solid red;'
|
||||||
|
elif result['application_status'] == '공고':
|
||||||
|
border_style = 'border: 3px solid black;'
|
||||||
|
|
||||||
|
# 각 결과에 대한 레이아웃 생성
|
||||||
|
item_layout = QVBoxLayout()
|
||||||
|
item_widget = QWidget() # 위젯 생성
|
||||||
|
|
||||||
# 테두리 설정
|
# item_layout의 크기 정책 설정
|
||||||
border_style = ''
|
item_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)
|
||||||
if result['application_status'] == '등록':
|
|
||||||
border_style = 'border: 4px solid red;'
|
|
||||||
elif result['application_status'] == '공고':
|
|
||||||
border_style = 'border: 3px solid black;'
|
|
||||||
|
|
||||||
# 각 결과에 대한 레이아웃 생성
|
|
||||||
item_layout = QVBoxLayout()
|
|
||||||
item_widget = QWidget() # 위젯 생성
|
|
||||||
|
|
||||||
# item_layout의 크기 정책 설정
|
# 이미지 처리
|
||||||
item_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)
|
image_label = QLabel()
|
||||||
|
image_label.setFixedSize(150, 150)
|
||||||
|
image_data = self.fetch_image_data(result['drawing_url'])
|
||||||
|
pixmap = QPixmap()
|
||||||
|
pixmap.loadFromData(image_data)
|
||||||
|
# QLabel의 크기에 맞게 이미지 크기 조정
|
||||||
|
scaled_pixmap = pixmap.scaled(image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||||
|
image_label.setPixmap(scaled_pixmap)
|
||||||
|
# QLabel의 가로 세로 중앙에 이미지 표시
|
||||||
|
image_label.setAlignment(Qt.AlignCenter)
|
||||||
|
# 이미지 표시 위젯의 크기 조정 정책 설정
|
||||||
|
image_label.setScaledContents(True)
|
||||||
|
|
||||||
# 이미지 처리
|
#이미지 중앙배치를 위해
|
||||||
image_label = QLabel()
|
horizontal_layout = QHBoxLayout()
|
||||||
image_label.setFixedSize(150, 150)
|
horizontal_layout.addWidget(image_label)
|
||||||
image_data = self.fetch_image_data(result['drawing_url'])
|
horizontal_layout.setAlignment(Qt.AlignCenter)
|
||||||
pixmap = QPixmap()
|
item_layout.addLayout(horizontal_layout)
|
||||||
pixmap.loadFromData(image_data)
|
|
||||||
# QLabel의 크기에 맞게 이미지 크기 조정
|
|
||||||
scaled_pixmap = pixmap.scaled(image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
|
||||||
image_label.setPixmap(scaled_pixmap)
|
|
||||||
# QLabel의 가로 세로 중앙에 이미지 표시
|
|
||||||
image_label.setAlignment(Qt.AlignCenter)
|
|
||||||
# 이미지 표시 위젯의 크기 조정 정책 설정
|
|
||||||
image_label.setScaledContents(True)
|
|
||||||
|
|
||||||
#이미지 중앙배치를 위해
|
# item_layout.addWidget(image_label)
|
||||||
horizontal_layout = QHBoxLayout()
|
|
||||||
horizontal_layout.addWidget(image_label)
|
|
||||||
horizontal_layout.setAlignment(Qt.AlignCenter)
|
|
||||||
item_layout.addLayout(horizontal_layout)
|
|
||||||
|
|
||||||
# item_layout.addWidget(image_label)
|
if searchType =='api':
|
||||||
|
# API 정보 텍스트
|
||||||
# 정보 텍스트
|
# info_text = f"상표권명: {result['title']}\n등록상태: {result['admin_status']}\nCategory: {result['product_category']}\nApplicant: {result['applicant']}\nPublication Date: {result['publication_date']}\nRegistration Date: {result['registration_date']}"
|
||||||
|
info_text = f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>상표권명: {result['title']}</span><br>\n" \
|
||||||
|
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>등록상태: {result['application_status']}</span><br>\n" \
|
||||||
|
f"<span style='font-size: 9pt;'>카테고리: {result['classification_code']}</span><br>\n" \
|
||||||
|
f"<span style='font-size: 9pt;'>권리자: {result['applicant_name']}</span><br>\n" \
|
||||||
|
f"<span style='font-size: 9pt;'>출원일자 {result['application_date']}</span><br>\n" \
|
||||||
|
f"<span style='font-size: 9pt;'>공고일자 {result['publication_date']}</span><br>\n" \
|
||||||
|
f"<span style='font-size: 9pt;'>등록일자 {result['registration_date']}</span>\n" \
|
||||||
|
f"<span style='font-size: 9pt;'>전문 {result['full_text']}</span><br>\n"
|
||||||
|
elif searchType =='web':
|
||||||
|
# WEB 정보 텍스트
|
||||||
# info_text = f"상표권명: {result['title']}\n등록상태: {result['admin_status']}\nCategory: {result['product_category']}\nApplicant: {result['applicant']}\nPublication Date: {result['publication_date']}\nRegistration Date: {result['registration_date']}"
|
# info_text = f"상표권명: {result['title']}\n등록상태: {result['admin_status']}\nCategory: {result['product_category']}\nApplicant: {result['applicant']}\nPublication Date: {result['publication_date']}\nRegistration Date: {result['registration_date']}"
|
||||||
info_text = f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>상표권명: {result['title']}</span><br>\n" \
|
info_text = f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>상표권명: {result['title']}</span><br>\n" \
|
||||||
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>등록상태: {result['application_status']}</span><br>\n" \
|
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>등록상태: {result['application_status']}</span><br>\n" \
|
||||||
|
|
@ -81,38 +104,49 @@ class ResultWidget(QWidget):
|
||||||
f"<span style='font-size: 9pt;'> {result['publication_date']}</span><br>\n" \
|
f"<span style='font-size: 9pt;'> {result['publication_date']}</span><br>\n" \
|
||||||
f"<span style='font-size: 9pt;'> {result['registration_date']}</span>"
|
f"<span style='font-size: 9pt;'> {result['registration_date']}</span>"
|
||||||
|
|
||||||
info_label = QLabel(info_text)
|
info_label = QLabel(info_text)
|
||||||
info_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
if searchType =='web':
|
||||||
image_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
currentURL_btn = QPushButton("웹 열기")
|
||||||
item_layout.addWidget(info_label)
|
# currentURL_btn.clicked.connect(self.openCurrentPage(currentURL))
|
||||||
|
info_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
||||||
|
image_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
||||||
|
item_layout.addWidget(info_label)
|
||||||
|
|
||||||
image_label.setStyleSheet(border_style)
|
image_label.setStyleSheet(border_style)
|
||||||
info_label.setStyleSheet(border_style)
|
info_label.setStyleSheet(border_style)
|
||||||
|
|
||||||
# 레이아웃에 위젯 추가
|
# 레이아웃에 위젯 추가
|
||||||
row = grid_index // grid_columns
|
row = grid_index // grid_columns
|
||||||
col = grid_index % grid_columns
|
col = grid_index % grid_columns
|
||||||
grid_layout.addLayout(item_layout, row, col)
|
grid_layout.addLayout(item_layout, row, col)
|
||||||
grid_index += 1
|
grid_index += 1
|
||||||
|
|
||||||
# 결과 위젯에 닫기 버튼 추가
|
# 결과 위젯에 닫기 버튼 추가
|
||||||
close_button = QPushButton("Close")
|
close_button = QPushButton("Close")
|
||||||
close_button.clicked.connect(self.close_results_widget)
|
close_button.clicked.connect(self.close_results_widget)
|
||||||
layout.addWidget(close_button)
|
layout.addWidget(close_button)
|
||||||
|
|
||||||
|
# e
|
||||||
|
elapsed_time_Label = QLabel(f"Elapsed Time : {elapsed_time}")
|
||||||
|
layout.addWidget(elapsed_time_Label)
|
||||||
|
|
||||||
# 결과 위젯을 메인 윈도우에 추가
|
# 결과 위젯을 메인 윈도우에 추가
|
||||||
self.results_widget.setGeometry(300, 300, 600, 300) # 위치와 크기 설정
|
self.results_widget.setGeometry(300, 300, 600, 300) # 위치와 크기 설정
|
||||||
self.results_widget.setWindowTitle('Search Results') # 타이틀 설정
|
self.results_widget.setWindowTitle('Search Results') # 타이틀 설정
|
||||||
self.results_widget.show()
|
self.results_widget.show()
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error displaying results: {e}")
|
|
||||||
|
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.debug(f"Error displaying results: {e}")
|
||||||
|
|
||||||
def close_results_widget(self):
|
def close_results_widget(self):
|
||||||
# 결과 위젯닫기 함수를 호출할 때 사용하는 메서드
|
# 결과 위젯닫기 함수를 호출할 때 사용하는 메서드
|
||||||
self.results_widget.close()
|
self.results_widget.close()
|
||||||
|
|
||||||
|
def openCurrentPage(self, currentURL):
|
||||||
|
logger.debug(f"open the page : {currentURL}")
|
||||||
|
webbrowser.open('currentURL')
|
||||||
|
pass
|
||||||
|
# QDesktopServices.openUrl(self.currentURL)
|
||||||
|
|
||||||
def wrap_text(self, text, width=40):
|
def wrap_text(self, text, width=40):
|
||||||
"""주어진 너비에 맞게 텍스트를 줄바꿈합니다."""
|
"""주어진 너비에 맞게 텍스트를 줄바꿈합니다."""
|
||||||
|
|
@ -133,31 +167,31 @@ class ResultWidget(QWidget):
|
||||||
async def fetch_image_data_async(self, url):
|
async def fetch_image_data_async(self, url):
|
||||||
"""주어진 URL로부터 이미지 데이터를 비동기적으로 가져와 반환합니다."""
|
"""주어진 URL로부터 이미지 데이터를 비동기적으로 가져와 반환합니다."""
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
# print(f"download_image session Start!!")
|
# logger.debug(f"download_image session Start!!")
|
||||||
async with session.get(url) as response:
|
async with session.get(url) as response:
|
||||||
print(f"download_image url : {url}")
|
logger.debug(f"download_image url : {url}")
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
# print(f"response : {response}")
|
# logger.debug(f"response : {response}")
|
||||||
content_type = response.headers.get('Content-Type', '') # await 제거
|
content_type = response.headers.get('Content-Type', '') # await 제거
|
||||||
print(f"content_type : {content_type}")
|
logger.debug(f"content_type : {content_type}")
|
||||||
if 'image' in content_type or 'octet-stream' in content_type:
|
if 'image' in content_type or 'octet-stream' in content_type:
|
||||||
# print(f"image content type or octet-stream : {content_type}")
|
# logger.debug(f"image content type or octet-stream : {content_type}")
|
||||||
return await response.read()
|
return await response.read()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
|
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
|
||||||
data = await response.read()
|
data = await response.read()
|
||||||
# print(f"Content-Type이 이미지가 아님 : {data}")
|
# logger.debug(f"Content-Type이 이미지가 아님 : {data}")
|
||||||
image = Image.open(BytesIO(data))
|
image = Image.open(BytesIO(data))
|
||||||
with BytesIO() as buffer:
|
with BytesIO() as buffer:
|
||||||
image.save(buffer, 'JPEG')
|
image.save(buffer, 'JPEG')
|
||||||
print(f"image 를 JPEG로 저장")
|
logger.debug(f"image 를 JPEG로 저장")
|
||||||
return buffer.getvalue()
|
return buffer.getvalue()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"이미지 변환 실패: {e}")
|
logger.debug(f"이미지 변환 실패: {e}")
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -177,8 +211,8 @@ class ResultWidget(QWidget):
|
||||||
image.save(buffer, 'JPEG') # 예시로 JPEG 포맷을 사용
|
image.save(buffer, 'JPEG') # 예시로 JPEG 포맷을 사용
|
||||||
return buffer.getvalue()
|
return buffer.getvalue()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"이미지 변환 실패: {e}")
|
logger.debug(f"이미지 변환 실패: {e}")
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,11 @@ import requests, os
|
||||||
from PyQt5.QtWidgets import QWidget, QTextBrowser, QVBoxLayout
|
from PyQt5.QtWidgets import QWidget, QTextBrowser, QVBoxLayout
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
|
|
||||||
class TrademarkSearchDisplay(QWidget):
|
class TrademarkSearchDisplay(QWidget):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
@ -69,22 +74,22 @@ class TrademarkSearchDisplay(QWidget):
|
||||||
self.text_browser.append(html_content)
|
self.text_browser.append(html_content)
|
||||||
|
|
||||||
def display_web_results(self, data, elapsed_time):
|
def display_web_results(self, data, elapsed_time):
|
||||||
print(f"Processing results... Elapsed time: {elapsed_time}s")
|
logger.debug(f"Processing results... Elapsed time: {elapsed_time}s")
|
||||||
# data 딕셔너리 내의 키 중 'result_'로 시작하는 키를 찾아 그 값을 처리
|
# data 딕셔너리 내의 키 중 'result_'로 시작하는 키를 찾아 그 값을 처리
|
||||||
for key, item in data.items():
|
for key, item in data.items():
|
||||||
print(f"Checking key: {key}") # 로그 추가
|
logger.debug(f"Checking key: {key}") # 로그 추가
|
||||||
if key.startswith('result_'): # 'result_'로 시작하는 키 확인
|
if key.startswith('result_'): # 'result_'로 시작하는 키 확인
|
||||||
print(f"Found valid key: {key}, Processing item...") # 로그 추가
|
logger.debug(f"Found valid key: {key}, Processing item...") # 로그 추가
|
||||||
if isinstance(item, dict): # item이 딕셔너리인지 확인
|
if isinstance(item, dict): # item이 딕셔너리인지 확인
|
||||||
print(f"Item is a dictionary. Generating HTML for item with title: {item.get('title')}") # 로그 추가
|
logger.debug(f"Item is a dictionary. Generating HTML for item with title: {item.get('title')}") # 로그 추가
|
||||||
|
|
||||||
# 이미지 다운로드 시도
|
# 이미지 다운로드 시도
|
||||||
downloaded_image_path = self.download_image(item.get("drawing_url"), item.get("ID"))
|
downloaded_image_path = self.download_image(item.get("drawing_url"), item.get("ID"))
|
||||||
if downloaded_image_path:
|
if downloaded_image_path:
|
||||||
print(f"Image downloaded and saved to {downloaded_image_path}")
|
logger.debug(f"Image downloaded and saved to {downloaded_image_path}")
|
||||||
image_html = f'<img src="{downloaded_image_path}" style="width:100%; max-width:300px; height:auto;">'
|
image_html = f'<img src="{downloaded_image_path}" style="width:100%; max-width:300px; height:auto;">'
|
||||||
else:
|
else:
|
||||||
print("Failed to download image.")
|
logger.debug("Failed to download image.")
|
||||||
image_html = 'Image not available'
|
image_html = 'Image not available'
|
||||||
|
|
||||||
# HTML 콘텐츠 생성
|
# HTML 콘텐츠 생성
|
||||||
|
|
@ -123,11 +128,11 @@ class TrademarkSearchDisplay(QWidget):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.text_browser.append(html_content)
|
self.text_browser.append(html_content)
|
||||||
print("HTML content appended to QTextBrowser.") # 로그 추가
|
logger.debug("HTML content appended to QTextBrowser.") # 로그 추가
|
||||||
else:
|
else:
|
||||||
print(f"Error: Item associated with {key} is not a dictionary.") # 오류 로그
|
logger.debug(f"Error: Item associated with {key} is not a dictionary.") # 오류 로그
|
||||||
else:
|
else:
|
||||||
print(f"Ignored key: {key}") # 무시된 키 로그
|
logger.debug(f"Ignored key: {key}") # 무시된 키 로그
|
||||||
|
|
||||||
|
|
||||||
def download_image(self, image_url, identifier):
|
def download_image(self, image_url, identifier):
|
||||||
|
|
@ -160,7 +165,7 @@ class TrademarkSearchDisplay(QWidget):
|
||||||
img_resized.save(image_path)
|
img_resized.save(image_path)
|
||||||
return image_path
|
return image_path
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error resizing image: {e}")
|
logger.debug(f"Error resizing image: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
from kipris_api_from_publicdata import Kipris
|
|
||||||
|
|
||||||
# 테스트를 위한 URL 및 파라미터 설정
|
|
||||||
apikey = 'X9Tz3JqC/JcCwxnNewA6qdloIN6QFIitVBgS1a2KVDYk1AmddaDTvzr6+t3dyLZV3gh2TPXdNhxsRQwaKP673Q=='
|
|
||||||
search_keyword = "써지오"
|
|
||||||
url = 'http://kipo-api.kipi.or.kr/openapi/service/trademarkInfoSearchService/getWordSearch'
|
|
||||||
|
|
||||||
params = {
|
|
||||||
'serviceKey': apikey,
|
|
||||||
'searchString': search_keyword,
|
|
||||||
'searchRecentYear': '0',
|
|
||||||
'title': '',
|
|
||||||
'fullText': '',
|
|
||||||
'drawing': '',
|
|
||||||
'bigDrawing': ''
|
|
||||||
}
|
|
||||||
|
|
||||||
# XMLParser 인스턴스 생성 및 실행
|
|
||||||
parser = Kipris(url, params)
|
|
||||||
results = parser.run()
|
|
||||||
|
|
||||||
# 모든 아이템의 결과 출력
|
|
||||||
if results:
|
|
||||||
print("결과가 있는 아이템 목록:")
|
|
||||||
for index, item in enumerate(results, start=1):
|
|
||||||
print(f"\n아이템 {index} 정보:")
|
|
||||||
for key, value in item.items():
|
|
||||||
print(f"{key}: {value}")
|
|
||||||
else:
|
|
||||||
print("결과가 없습니다.")
|
|
||||||
|
|
||||||
|
|
||||||
# ※ 행정 상태 도움말
|
|
||||||
# 거절 : 출원 후 특허 심사과정에서 실체적인 특허 등록요건을 만족하지 못할 경우에 심사관이 취하는 행정처분
|
|
||||||
# 등록 : 심사관이 심사한 결과 등록요건에 적합하여 설정등록을 받을 수 있다는 내용의 행정처분
|
|
||||||
# 소멸 : 특허등록 후 존속기간이 만료되어 권리가 소멸된 상태
|
|
||||||
# 무효 : 출원 또는 등록된 상태에 대하여 특정 사유로 인해 그 권리나 행위가 무효화 된 상태
|
|
||||||
# 취하 : 출원한 특허가 등록되기전 여러 사유로 인하여 출원이 취소된 상태
|
|
||||||
# 포기 : 출원인의 포기서 제출, 등록료 불납 등으로 등록결정이나 권리를 포기한 상태
|
|
||||||
# 공개 : 출원이나 등록사실이 일반 공중에게 공표된 상태로 출원 후 18개월이 지난 건
|
|
||||||
# *조기공개신청시 18개월 미만도 공개가능
|
|
||||||
#
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
from PyQt5.QtCore import Qt, QRect, QPropertyAnimation, pyqtProperty, pyqtSignal, QPoint
|
from PyQt5.QtCore import Qt, QRect, QPropertyAnimation, pyqtProperty, pyqtSignal, QPoint
|
||||||
from PyQt5.QtGui import QPainter, QColor
|
from PyQt5.QtGui import QPainter, QColor
|
||||||
from PyQt5.QtWidgets import QWidget
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
|
|
||||||
class ToggleSwitch(QWidget):
|
class ToggleSwitch(QWidget):
|
||||||
clicked = pyqtSignal(bool)
|
clicked = pyqtSignal(bool)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ import random, requests, json
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
class WebScraper:
|
class WebScraper:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.results = {}
|
self.results = {}
|
||||||
|
|
@ -12,6 +15,7 @@ class WebScraper:
|
||||||
self.browser = None
|
self.browser = None
|
||||||
self.context = None
|
self.context = None
|
||||||
self.page = None
|
self.page = None
|
||||||
|
self.currentURL = ''
|
||||||
filename = 'categories.json'
|
filename = 'categories.json'
|
||||||
self.category_description = self.load_category_descriptions(filename)
|
self.category_description = self.load_category_descriptions(filename)
|
||||||
self.url = "http://kdtj.kipris.or.kr/kdtj/searchLogina.do?method=loginTM#page1"
|
self.url = "http://kdtj.kipris.or.kr/kdtj/searchLogina.do?method=loginTM#page1"
|
||||||
|
|
@ -42,9 +46,9 @@ class WebScraper:
|
||||||
try:
|
try:
|
||||||
await self.page.goto(self.url, wait_until='networkidle')
|
await self.page.goto(self.url, wait_until='networkidle')
|
||||||
self.is_page_loaded = True
|
self.is_page_loaded = True
|
||||||
print("Page loaded successfully.")
|
logger.debug("Page loaded successfully.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to load the page: {e}")
|
logger.debug(f"Failed to load the page: {e}")
|
||||||
self.is_page_loaded = False # 로드 실패 처리
|
self.is_page_loaded = False # 로드 실패 처리
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -52,9 +56,9 @@ class WebScraper:
|
||||||
try:
|
try:
|
||||||
await self.page.goto(url, wait_until='networkidle')
|
await self.page.goto(url, wait_until='networkidle')
|
||||||
self.is_page_loaded = True
|
self.is_page_loaded = True
|
||||||
print("Page loaded successfully.")
|
logger.debug("Page loaded successfully.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to load the page: {e}")
|
logger.debug(f"Failed to load the page: {e}")
|
||||||
self.is_page_loaded = False # 로드 실패 처리
|
self.is_page_loaded = False # 로드 실패 처리
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -65,23 +69,23 @@ class WebScraper:
|
||||||
# await self.page.fill("#queryText", term)
|
# await self.page.fill("#queryText", term)
|
||||||
await self.page.fill("#keywordTextarea", term)
|
await self.page.fill("#keywordTextarea", term)
|
||||||
|
|
||||||
print(f"검색어 입력 : {term}")
|
logger.debug(f"검색어 입력 : {term}")
|
||||||
await self.page.click(".input_btn")
|
await self.page.click(".input_btn")
|
||||||
print(f"검색버튼 클릭")
|
logger.debug(f"검색버튼 클릭")
|
||||||
|
|
||||||
# JavaScript에 의해 결과가 동적으로 로드되기를 기다립니다.
|
# JavaScript에 의해 결과가 동적으로 로드되기를 기다립니다.
|
||||||
loaded = await self.page.wait_for_function(
|
loaded = await self.page.wait_for_function(
|
||||||
"document.querySelector('form#listForm section.search_section article') != null"
|
"document.querySelector('form#listForm section.search_section article') != null"
|
||||||
)
|
)
|
||||||
if not loaded:
|
if not loaded:
|
||||||
print("검색 결과가 시간 내에 로드되지 않았습니다.")
|
logger.debug("검색 결과가 시간 내에 로드되지 않았습니다.")
|
||||||
return None
|
return None
|
||||||
print(f"결과가 동적으로 로드되기를 기다림 : {loaded}")
|
logger.debug(f"결과가 동적으로 로드되기를 기다림 : {loaded}")
|
||||||
|
|
||||||
# 검색 결과가 없는지 확인
|
# 검색 결과가 없는지 확인
|
||||||
nodata_info = await self.page.query_selector(".nodata_info")
|
nodata_info = await self.page.query_selector(".nodata_info")
|
||||||
if nodata_info:
|
if nodata_info:
|
||||||
print("검색 결과가 없습니다.")
|
logger.debug("검색 결과가 없습니다.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 결과 로딩이 확인된 후, 실제 요소를 수집
|
# 결과 로딩이 확인된 후, 실제 요소를 수집
|
||||||
|
|
@ -89,41 +93,44 @@ class WebScraper:
|
||||||
total_count = await self.page.text_content("form#listForm section.search_section div p span.total")
|
total_count = await self.page.text_content("form#listForm section.search_section div p span.total")
|
||||||
total_count = total_count.strip()
|
total_count = total_count.strip()
|
||||||
total_count = int(total_count.replace(',', ''))
|
total_count = int(total_count.replace(',', ''))
|
||||||
print(f"total_count : {total_count}")
|
logger.debug(f"total_count : {total_count}")
|
||||||
|
|
||||||
|
self.currentURL = self.page.url
|
||||||
|
logger.debug(f"currentURL : {self.currentURL}")
|
||||||
|
|
||||||
if total_count:
|
if total_count:
|
||||||
self.results['total_count'] = total_count
|
self.results['total_count'] = total_count
|
||||||
articles = await self.page.query_selector_all("form#listForm section.search_section article")
|
articles = await self.page.query_selector_all("form#listForm section.search_section article")
|
||||||
print(f"articles : {len(articles)} 개")
|
logger.debug(f"articles : {len(articles)} 개")
|
||||||
for i, article in enumerate(articles):
|
for i, article in enumerate(articles):
|
||||||
id_and_name_element = await article.query_selector("div:nth-child(1) span input[type='checkbox']")
|
id_and_name_element = await article.query_selector("div:nth-child(1) span input[type='checkbox']")
|
||||||
trademark_name = await id_and_name_element.get_attribute("title") if id_and_name_element else "No name found"
|
trademark_name = await id_and_name_element.get_attribute("title") if id_and_name_element else "No name found"
|
||||||
print(f"trademark_name : {trademark_name}")
|
logger.debug(f"trademark_name : {trademark_name}")
|
||||||
|
|
||||||
applno = await id_and_name_element.get_attribute("value") if id_and_name_element else "No ID found"
|
applno = await id_and_name_element.get_attribute("value") if id_and_name_element else "No ID found"
|
||||||
trademark_image_url_by_id = (
|
trademark_image_url_by_id = (
|
||||||
f"http://kdtj.kipris.or.kr/kdtj/remoteFile.do?method=bigImageTM&applno={applno}&no={applno}_tm000001.jpg"
|
f"http://kdtj.kipris.or.kr/kdtj/remoteFile.do?method=bigImageTM&applno={applno}&no={applno}_tm000001.jpg"
|
||||||
if applno else None
|
if applno else None
|
||||||
)
|
)
|
||||||
print(f"trademark_image_url_by_id : {trademark_image_url_by_id}")
|
logger.debug(f"trademark_image_url_by_id : {trademark_image_url_by_id}")
|
||||||
|
|
||||||
img_element = await article.query_selector("div:nth-child(2) div a img")
|
img_element = await article.query_selector("div:nth-child(2) div a img")
|
||||||
trademark_image = await img_element.get_attribute("src") if img_element else "No image found"
|
trademark_image = await img_element.get_attribute("src") if img_element else "No image found"
|
||||||
print(f"trademark_image : {trademark_image}")
|
logger.debug(f"trademark_image : {trademark_image}")
|
||||||
|
|
||||||
admin_status_element = await article.query_selector("div:nth-child(1) h1 a:nth-child(1) span")
|
admin_status_element = await article.query_selector("div:nth-child(1) h1 a:nth-child(1) span")
|
||||||
admin_status = await admin_status_element.text_content() if admin_status_element else "No status found"
|
admin_status = await admin_status_element.text_content() if admin_status_element else "No status found"
|
||||||
print(f"admin_status : {admin_status}")
|
logger.debug(f"admin_status : {admin_status}")
|
||||||
|
|
||||||
product_category_element = await article.query_selector("div:nth-child(2) ul li:nth-child(1) a span")
|
product_category_element = await article.query_selector("div:nth-child(2) ul li:nth-child(1) a span")
|
||||||
product_category = await product_category_element.text_content() if product_category_element else "No category found"
|
product_category = await product_category_element.text_content() if product_category_element else "No category found"
|
||||||
category_desc = self.add_category_description(product_category) if product_category else "No category description"
|
category_desc = self.add_category_description(product_category) if product_category else "No category description"
|
||||||
print(f"product_category : {product_category}")
|
logger.debug(f"product_category : {product_category}")
|
||||||
print(f"category_desc : {category_desc}")
|
logger.debug(f"category_desc : {category_desc}")
|
||||||
|
|
||||||
applicant_element = await article.query_selector("div:nth-child(2) ul li:nth-child(2) span[title]")
|
applicant_element = await article.query_selector("div:nth-child(2) ul li:nth-child(2) span[title]")
|
||||||
applicant = await applicant_element.get_attribute("title") if applicant_element else "No applicant found"
|
applicant = await applicant_element.get_attribute("title") if applicant_element else "No applicant found"
|
||||||
print(f"applicant : {applicant}")
|
logger.debug(f"applicant : {applicant}")
|
||||||
|
|
||||||
publication_date_element = await article.query_selector("div:nth-child(2) ul li:nth-child(8)")
|
publication_date_element = await article.query_selector("div:nth-child(2) ul li:nth-child(8)")
|
||||||
if publication_date_element:
|
if publication_date_element:
|
||||||
|
|
@ -131,7 +138,7 @@ class WebScraper:
|
||||||
publication_date = publication_date_content.strip() if publication_date_content else "No publication date found"
|
publication_date = publication_date_content.strip() if publication_date_content else "No publication date found"
|
||||||
else:
|
else:
|
||||||
publication_date = "No publication date found"
|
publication_date = "No publication date found"
|
||||||
print(f"publication_date : {publication_date}")
|
logger.debug(f"publication_date : {publication_date}")
|
||||||
|
|
||||||
registration_date_element = await article.query_selector("div:nth-child(2) ul li:nth-child(6)")
|
registration_date_element = await article.query_selector("div:nth-child(2) ul li:nth-child(6)")
|
||||||
if registration_date_element:
|
if registration_date_element:
|
||||||
|
|
@ -139,9 +146,9 @@ class WebScraper:
|
||||||
registration_date = registration_date_content.strip() if registration_date_content else "No registration date found"
|
registration_date = registration_date_content.strip() if registration_date_content else "No registration date found"
|
||||||
else:
|
else:
|
||||||
registration_date = "No registration date found"
|
registration_date = "No registration date found"
|
||||||
print(f"registration_date : {registration_date}")
|
logger.debug(f"registration_date : {registration_date}")
|
||||||
|
if admin_status in status: # status는 self.set_status 리스트를 참조
|
||||||
if not (admin_status == "소멸" or admin_status == "거절"):
|
# if not (admin_status == "소멸" or admin_status == "거절"):
|
||||||
self.results[f"result_{i+1}"] = {
|
self.results[f"result_{i+1}"] = {
|
||||||
"ID": applno,
|
"ID": applno,
|
||||||
"title": trademark_name,
|
"title": trademark_name,
|
||||||
|
|
@ -154,65 +161,65 @@ class WebScraper:
|
||||||
"publication_date": publication_date,
|
"publication_date": publication_date,
|
||||||
"registration_date": registration_date,
|
"registration_date": registration_date,
|
||||||
}
|
}
|
||||||
# print(f"results : {self.results}")
|
# logger.debug(f"results : {self.results}")
|
||||||
await self.navigate_to_page(self.url)
|
await self.navigate_to_page(self.url)
|
||||||
return self.results
|
return self.results
|
||||||
else:
|
else:
|
||||||
print("No total count element found, possibly incorrect selector or page structure has changed.")
|
logger.debug("No total count element found, possibly incorrect selector or page structure has changed.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"오류 발생 : {e}")
|
logger.debug(f"오류 발생 : {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def download_image(self, url, applno):
|
async def download_image(self, url, applno):
|
||||||
"""이미지를 비동기적으로 다운로드하고 applno를 파일 이름으로 사용하여 저장합니다."""
|
"""이미지를 비동기적으로 다운로드하고 applno를 파일 이름으로 사용하여 저장합니다."""
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
print(f"download_image session Start!!")
|
logger.debug(f"download_image session Start!!")
|
||||||
async with session.get(url) as response:
|
async with session.get(url) as response:
|
||||||
print(f"download_image url : {url}")
|
logger.debug(f"download_image url : {url}")
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
filename = f"{applno}.jpeg"
|
filename = f"{applno}.jpeg"
|
||||||
async with aiofiles.open(filename, 'wb') as file:
|
async with aiofiles.open(filename, 'wb') as file:
|
||||||
content = await response.read()
|
content = await response.read()
|
||||||
await file.write(content)
|
await file.write(content)
|
||||||
print(f"이미지가 성공적으로 저장되었습니다: {filename}")
|
logger.debug(f"이미지가 성공적으로 저장되었습니다: {filename}")
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status}")
|
||||||
|
|
||||||
async def fetch_image_data(self, url):
|
async def fetch_image_data(self, url):
|
||||||
"""주어진 URL로부터 이미지 데이터를 비동기적으로 가져와 반환합니다."""
|
"""주어진 URL로부터 이미지 데이터를 비동기적으로 가져와 반환합니다."""
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
# print(f"download_image session Start!!")
|
# logger.debug(f"download_image session Start!!")
|
||||||
async with session.get(url) as response:
|
async with session.get(url) as response:
|
||||||
print(f"download_image url : {url}")
|
logger.debug(f"download_image url : {url}")
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
# print(f"response : {response}")
|
# logger.debug(f"response : {response}")
|
||||||
content_type = response.headers.get('Content-Type', '') # await 제거
|
content_type = response.headers.get('Content-Type', '') # await 제거
|
||||||
print(f"content_type : {content_type}")
|
logger.debug(f"content_type : {content_type}")
|
||||||
if 'image' in content_type or 'octet-stream' in content_type:
|
if 'image' in content_type or 'octet-stream' in content_type:
|
||||||
# print(f"image content type or octet-stream : {content_type}")
|
# logger.debug(f"image content type or octet-stream : {content_type}")
|
||||||
return await response.read()
|
return await response.read()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
|
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
|
||||||
data = await response.read()
|
data = await response.read()
|
||||||
# print(f"Content-Type이 이미지가 아님 : {data}")
|
# logger.debug(f"Content-Type이 이미지가 아님 : {data}")
|
||||||
image = Image.open(BytesIO(data))
|
image = Image.open(BytesIO(data))
|
||||||
with BytesIO() as buffer:
|
with BytesIO() as buffer:
|
||||||
image.save(buffer, 'JPEG')
|
image.save(buffer, 'JPEG')
|
||||||
print(f"image 를 JPEG로 저장")
|
logger.debug(f"image 를 JPEG로 저장")
|
||||||
return buffer.getvalue()
|
return buffer.getvalue()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"이미지 변환 실패: {e}")
|
logger.debug(f"이미지 변환 실패: {e}")
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# async def load_category_descriptions(self, filename):
|
# async def load_category_descriptions(self, filename):
|
||||||
# """JSON 파일에서 카테고리 설명을 비동기적으로 로드합니다."""
|
# """JSON 파일에서 카테고리 설명을 비동기적으로 로드합니다."""
|
||||||
# async with aiofiles.open(filename, 'r', encoding='utf-8') as file:
|
# async with aiofiles.open(filename, 'r', encoding='utf-8') as file:
|
||||||
# content = await file.read()
|
# content = await file.read()
|
||||||
# print(f"JSON 파일에서 카테고리 설명을 비동기적으로 로드합니다: {content}")
|
# logger.debug(f"JSON 파일에서 카테고리 설명을 비동기적으로 로드합니다: {content}")
|
||||||
# return json.loads(content)
|
# return json.loads(content)
|
||||||
|
|
||||||
def load_category_descriptions(self, filename):
|
def load_category_descriptions(self, filename):
|
||||||
|
|
@ -222,7 +229,7 @@ class WebScraper:
|
||||||
|
|
||||||
def add_category_description(self, category_code):
|
def add_category_description(self, category_code):
|
||||||
"""주어진 카테고리 코드에 따라 설명을 반환합니다."""
|
"""주어진 카테고리 코드에 따라 설명을 반환합니다."""
|
||||||
print(f"add_category_description => category_code: {category_code}")
|
logger.debug(f"add_category_description => category_code: {category_code}")
|
||||||
return self.category_description.get(category_code, "카테고리 설명을 찾을 수 없습니다.")
|
return self.category_description.get(category_code, "카테고리 설명을 찾을 수 없습니다.")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
from requests_html import HTMLSession
|
from requests_html import HTMLSession
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 로거 인스턴스 가져오기
|
||||||
|
logger = logging.getLogger('default_logger')
|
||||||
class WebScraper:
|
class WebScraper:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.session = HTMLSession()
|
self.session = HTMLSession()
|
||||||
|
|
@ -23,7 +26,7 @@ class WebScraper:
|
||||||
"""지정된 URL로 이동하고 페이지를 로드합니다."""
|
"""지정된 URL로 이동하고 페이지를 로드합니다."""
|
||||||
response = self.session.get(url)
|
response = self.session.get(url)
|
||||||
response.html.render() # 필요 시 JavaScript 실행
|
response.html.render() # 필요 시 JavaScript 실행
|
||||||
print("Page loaded successfully.")
|
logger.debug("Page loaded successfully.")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def search_for_term(self, term):
|
def search_for_term(self, term):
|
||||||
|
|
@ -43,17 +46,17 @@ class WebScraper:
|
||||||
search_response.html.render()
|
search_response.html.render()
|
||||||
return search_response
|
return search_response
|
||||||
else:
|
else:
|
||||||
print("폼의 action URL을 찾을 수 없습니다.")
|
logger.debug("폼의 action URL을 찾을 수 없습니다.")
|
||||||
else:
|
else:
|
||||||
print("검색 폼을 찾을 수 없습니다.")
|
logger.debug("검색 폼을 찾을 수 없습니다.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"검색 실행 중 오류 발생: {e}")
|
logger.debug(f"검색 실행 중 오류 발생: {e}")
|
||||||
|
|
||||||
# response.html.render(script=script, reload=False)
|
# response.html.render(script=script, reload=False)
|
||||||
|
|
||||||
# # response.html.find('#keywordTextarea', first=True).fill(term)
|
# # response.html.find('#keywordTextarea', first=True).fill(term)
|
||||||
# self.page.evaluate(f"document.querySelector('#keywordTextarea').value = '{term}';")
|
# self.page.evaluate(f"document.querySelector('#keywordTextarea').value = '{term}';")
|
||||||
# print(f"검색어 입력: {term}")
|
# logger.debug(f"검색어 입력: {term}")
|
||||||
# input_field = response.html.find('#keywordTextarea', first=True)
|
# input_field = response.html.find('#keywordTextarea', first=True)
|
||||||
# script = f"document.querySelector('#keywordTextarea').value = '{term}';"
|
# script = f"document.querySelector('#keywordTextarea').value = '{term}';"
|
||||||
# response.html.page.evaluate(script) # JavaScript 실행
|
# response.html.page.evaluate(script) # JavaScript 실행
|
||||||
|
|
@ -64,7 +67,7 @@ class WebScraper:
|
||||||
|
|
||||||
articles = response.html.find('form#listForm section.search_section article')
|
articles = response.html.find('form#listForm section.search_section article')
|
||||||
if not articles:
|
if not articles:
|
||||||
print("검색 결과가 없습니다.")
|
logger.debug("검색 결과가 없습니다.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Store results in a structured format
|
# Store results in a structured format
|
||||||
|
|
@ -87,9 +90,9 @@ class WebScraper:
|
||||||
filename = f"{applno}.jpeg"
|
filename = f"{applno}.jpeg"
|
||||||
with open(filename, 'wb') as file:
|
with open(filename, 'wb') as file:
|
||||||
file.write(response.content)
|
file.write(response.content)
|
||||||
print(f"이미지가 성공적으로 저장되었습니다: {filename}")
|
logger.debug(f"이미지가 성공적으로 저장되었습니다: {filename}")
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
||||||
|
|
||||||
def fetch_image_data(self, url):
|
def fetch_image_data(self, url):
|
||||||
"""주어진 URL로부터 이미지 데이터를 직접 가져와 반환합니다."""
|
"""주어진 URL로부터 이미지 데이터를 직접 가져와 반환합니다."""
|
||||||
|
|
@ -97,7 +100,7 @@ class WebScraper:
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return response.content
|
return response.content
|
||||||
else:
|
else:
|
||||||
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def close_browser(self):
|
def close_browser(self):
|
||||||
|
|
@ -107,4 +110,4 @@ class WebScraper:
|
||||||
# # 사용 예시
|
# # 사용 예시
|
||||||
# scraper = WebScraper()
|
# scraper = WebScraper()
|
||||||
# results = scraper.search_for_term("특허")
|
# results = scraper.search_for_term("특허")
|
||||||
# print(results)
|
# logger.debug(results)
|
||||||
|
|
|
||||||