로그추가

This commit is contained in:
Envy_PC 2024-05-09 09:27:53 +09:00
parent 1f502713e2
commit bd343ed691
29 changed files with 502 additions and 318 deletions

View File

@ -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 = ['°ÅÀý', 'µî·Ï']

View File

@ -6,19 +6,17 @@
"addFeeInterval": 5,
"addFeeSetting": 20,
"addFee": 1000,
"fontSize": 10,
"fontSize": 12,
"weightInterval": 0.5,
"setSaveSetting": true,
"favoriteDelv": "\ub178\ube60\uafb8\ud574\uc6b4(\ubc30\uc1a1\ube44)"
},
"Kipris": {
"use_kipris": true,
"usage_mode": "web",
"api_key": "",
"usage_mode": "api",
"api_key": "X9Tz3JqC/JcCwxnNewA6qdloIN6QFIitVBgS1a2KVDYk1AmddaDTvzr6+t3dyLZV3gh2TPXdNhxsRQwaKP673Q==",
"set_status": [
"\ub4f1\ub85d",
"\ucde8\ud558",
"\ud3ec\uae30"
"\ub4f1\ub85d"
]
}
}

137
delv.py
View File

@ -14,9 +14,9 @@ from src.kipris_settingUI import SettingsDialog
from src.kipris_api_from_publicdata import Kipris_API
# from src.kipris_web_from_playwright import Kipris_WEB
from src.kiprisThread import *
from src.search_display import TrademarkSearchDisplay
# from src.search_display import TrademarkSearchDisplay
from src.result_widget import ResultWidget
from src.currencyInfo import ExchangeRateScraper
def minimize_console():
""" 콘솔 창을 최소화하는 함수 """
@ -40,7 +40,8 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
self.asyncWorker = None
self.search_keyword = None
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.maxWeightSet = 25
@ -58,12 +59,12 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
self.addFeeSetting = 20
self.addFeeInterval = 5
self.setUSD = None
self.setCNY = None
self.searchDisplay = TrademarkSearchDisplay()
self.currentCurrency = None
# self.searchDisplay = TrademarkSearchDisplay()
self.searchDisplayWidget = ResultWidget()
self.currencyInfoObject = ExchangeRateScraper()
self.favoriteDelv = ""
@ -108,6 +109,14 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
}
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):
""" 설정을 JSON 파일에 저장합니다. """
try:
@ -220,7 +229,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
# self.api_key = self.config.get('Kipris', 'api_key', 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:
# logger.error(f"설정을 불러오는 중 오류가 발생했습니다: {e}", exc_info=True)
@ -283,17 +292,17 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
if keyword:
if keyword and keyword not in self.history: # 중복된 검색어가 아니면 추가
self.history.append(keyword)
print(f"검색어 [{keyword}] 히스토리에 추가")
logger.debug(f"검색어 [{keyword}] 히스토리에 추가")
def load_history(self):
try:
with open("search_history.json", "r") as 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):
self.history = []
print(f"self.history{self.history}")
logger.debug(f"self.history{self.history}")
def save_history(self):
with open("search_history.json", "w") as file:
@ -599,7 +608,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
self.kipris_layout = QtWidgets.QHBoxLayout(self.kiprisWidget)
self.kiprisWidget.setLayout(self.kipris_layout)
self.kiprisWidget.setVisible(False)
self.kipris_label = QtWidgets.QLabel("키프리스 검색")
self.kipris_label = QtWidgets.QLabel(f"키프리스 검색")
self.kipris_edit = QtWidgets.QLineEdit()
self.kipris_btn = QtWidgets.QPushButton("검색")
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_h1layout = 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_h1layout)
self.addInfoWidget.setLayout(self.addInfo_vlayout)
self.addInfoWidget.setVisible(True)
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.addInfo_h2layout.addWidget(self.addInfo2_btn)
self.addInfo3_btn = QtWidgets.QPushButton("타냐어록")
self.addInfo3_btn.setEnabled(False)
self.addInfo3_btn.clicked.connect(self.addInfo3_btn_clicked)
self.addInfo_h2layout.addWidget(self.addInfo3_btn)
self.addInfo4_btn = QtWidgets.QPushButton("딥러닝번역")
self.addInfo4_btn.setEnabled(False)
self.addInfo4_btn.clicked.connect(self.addInfo4_btn_clicked)
self.addInfo_h2layout.addWidget(self.addInfo4_btn)
# self.addInfo_layout.setStretch(0,3)
@ -659,6 +670,35 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
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.move(10, 10)
@ -694,17 +734,17 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
# if current_type is not target_type:
# # 기존 객체가 다른 타입이면 삭제하고 새로 생성
# print(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
# logger.debug(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
# self.kiprisAPI.close_Kipris() # 기존객체 리소스 정리
# del self.kiprisAPI # 기존 객체 참조 제거
# 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:
# print(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
# logger.debug(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
# else:
# # 객체가 없으면 새로 생성
# 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):
if self.kiprisAPI:
@ -714,7 +754,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
if current_type is not target_type:
# 기존 객체가 다른 타입이면 삭제하고 새로 생성
print(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
logger.debug(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
if isinstance(self.kiprisAPI, AsyncWebSearchWorker):
self.kiprisAPI.deleteLater() # 비동기 작업자는 Qt 객체로 관리되므로 deleteLater 사용
self.kiprisAPI = None
@ -722,18 +762,20 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
self.kiprisAPI = Kipris_API(self.api_key) # 새 객체 생성
else:
web_scraper = WebScraper() # WebScraper 인스턴스 생성
self.kiprisAPI = AsyncWebSearchWorker(web_scraper, "") # 초기 키워드는 비워두기
print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
self.web_scraper = web_scraper
self.kiprisAPI = AsyncWebSearchWorker(self.web_scraper, "") # 초기 키워드는 비워두기
logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
else:
print(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
logger.debug(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
else:
# 객체가 없으면 새로 생성
if self.usage_mode == 'api':
self.kiprisAPI = Kipris_API(self.api_key)
else:
web_scraper = WebScraper() # WebScraper 인스턴스 생성
self.web_scraper = 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):
pass
@ -761,6 +803,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
if self.use_kipris:
self.kiprisWidget.setVisible(True)
self.initSettings_for_kipris()
self.kipris_label.setText(f"키프리스 검색({self.usage_mode})")
else:
self.kiprisWidget.setVisible(False)
@ -1061,6 +1104,26 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
self.addFeeInterval = value
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):
if state:
self.setSaveSetting = True
@ -1075,10 +1138,10 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{self.search_keyword}]")
# result = self.kiprisAPI.run(self.search_keyword, self.set_status)
# print(f"result {result}")
# logger.debug(f"result {result}")
if self.search_keyword.strip(): # 검색어가 비어있지 않은 경우에만 검색 수행
print(f"검색 호출방식 : {self.usage_mode}")
logger.debug(f"검색 호출방식 : {self.usage_mode}")
if self.usage_mode == 'web':
self.handle_search_for_web(self.search_keyword)
if self.usage_mode == 'api':
@ -1089,16 +1152,17 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
if self.asyncWorker: # 기존에 비동기 작업자가 존재한다면
self.asyncWorker.thread.quit() # 기존 스레드 종료
print(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
self.asyncWorker = AsyncWebSearchWorker(keyword, self.set_status) # 새 비동기 작업자 생성
self.asyncWorker.finished.connect(self.display_results_for_web) # 완료 시그널을 결과 표시 함수에 연결
self.asyncWorker.start() # 비동기 작업 시작
print("비동기 검색 시작")
logger.debug("비동기 검색 시작")
def display_results_for_web(self, result, elapsed_time):
print(f"result : {result}")
self.searchDisplayWidget.show_results(result)
# logger.debug(f"result : {result}")
searchType = 'web'
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.show()
@ -1113,28 +1177,31 @@ class DeliveryFeeCalculator(QtWidgets.QWidget):
if self.searchThread is not None and self.searchThread.isRunning():
self.searchThread.quit() # 이전 스레드가 실행 중이라면 안전하게 종료
print("기존 쓰레드가 존재하므로 기존 쓰레드 종료")
print(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
logger.debug("기존 쓰레드가 존재하므로 기존 쓰레드 종료")
logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
worker = APISearchWorker(self.kiprisAPI, keyword, self.set_status)
# worker = SearchWorker(self.kiprisAPI, keyword, self.set_status)
print("워커 생성")
logger.debug("워커 생성")
self.searchThread = SearchThread(worker)
print("쓰레드 생성")
logger.debug("쓰레드 생성")
worker.finished.connect(self.display_results_for_api)
self.searchThread.finished.connect(self.clear_thread_reference)
self.searchThread.start_search()
print("검색 시작")
logger.debug("검색 시작")
def clear_thread_reference(self):
# 스레드 종료 후 참조를 제거하여 다음 검색을 위해 준비
self.searchThread = None
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}"
QtWidgets.QMessageBox.information(self, "Search Results", message)
# QtWidgets.QMessageBox.information(self, "Search Results", message)
def reset_action(self):
self.lengthInput.setValue(1)
@ -1171,7 +1238,7 @@ if __name__ == '__main__':
minimize_console()
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.show()
sys.exit(app.exec_())

BIN
delv.xlsx

Binary file not shown.

View File

@ -3,12 +3,10 @@
a = Analysis(
['delv.py'],
pathex=['H:\\py\\delvfee'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[
'sip', 'jinja2'
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],

View File

@ -3,7 +3,10 @@ from PyQt5.QtWidgets import QApplication, QMessageBox, QSizePolicy, QWidget, QVB
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt, QByteArray, QBuffer, QIODevice
from kipris_web_from_playwright import WebScraper
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class MainApp(QWidget):
def __init__(self):
super().__init__()
@ -163,7 +166,7 @@ class MainApp(QWidget):
self.results_widget.show()
except Exception as e:
print(f"Error displaying results: {e}")
logger.debug(f"Error displaying results: {e}")
def close_results_widget(self):

63
src/currencyInfo.py Normal file
View File

@ -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')

View File

@ -1,9 +1,12 @@
from PyQt5.QtCore import QThread, pyqtSignal, QObject
import time
from src.web_scraper_async import *
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class APISearchWorker(QObject):
finished = pyqtSignal(list, float)
finished = pyqtSignal(dict, float)
def __init__(self, kiprisObject, keyword, set_status):
super().__init__()
@ -13,9 +16,9 @@ class APISearchWorker(QObject):
def run(self):
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)
print(f"Search finished | result \n [{result}]")
logger.debug(f"Search finished | result \n {result}")
elapsed_time = time.time() - start_time # 경과 시간 계산
self.finished.emit(result, elapsed_time)
@ -36,7 +39,7 @@ class SearchThread(QThread):
def handle_finished(self, result, elapsed_time):
# 검색 작업이 완료되면 이 시그널이 발생합니다.
print(f"Search finished : [{elapsed_time}]초 경과")
logger.debug(f"Search finished : [{elapsed_time}]초 경과")
class AsyncWebSearchWorker(QObject):
@ -68,7 +71,7 @@ class AsyncWebSearchWorker(QObject):
elapsed_time = time.time() - self.start_time # 소요 시간 계산
self.finished.emit(result, elapsed_time) # 작업 완료 신호 전송
except Exception as e:
print(f"Error in AsyncWebSearchWorker: {e}")
logger.debug(f"Error in AsyncWebSearchWorker: {e}")
self.finished.emit(None, 0) # 에러 발생 시 None 전송
finally:
await self.scraper.close_Kipris() # 리소스 정리

View File

@ -1,11 +1,17 @@
import xml.etree.ElementTree as ET
import requests
import requests, json
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class Kipris_API:
def __init__(self, apikey=None):
self.url = 'http://kipo-api.kipi.or.kr/openapi/service/trademarkInfoSearchService/getWordSearch'
self.apikey = apikey
self.results = []
self.results = {}
filename = 'categories.json'
self.category_description = self.load_category_descriptions(filename)
def fetch_and_decode(self, params):
# API 요청 및 응답 받기
@ -14,7 +20,7 @@ class Kipris_API:
decoded_data = response.content.decode('utf-8')
return decoded_data
except Exception as e:
print(f"키프리스 요청 중 에러발생 : {e}")
logger.error(f"키프리스 요청 중 에러발생 : {e}")
def parse_xml(self, xml_data, status):
# XML 데이터 파싱
@ -24,10 +30,15 @@ class Kipris_API:
status_published = 0
# '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
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 == "등록":
status_registered += 1
@ -36,7 +47,8 @@ class Kipris_API:
# if application_status in ["등록", "공개"]:
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,
"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,
@ -51,14 +63,16 @@ class Kipris_API:
"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,
"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}")
print(f"등록 상태인 item 개수: {status_registered}")
print(f"공개 상태인 item 개수: {status_published}")
logger.debug(f"검색된 item 총 개수: {total_items}")
self.results['total_count'] = total_items
logger.debug(f"등록 상태인 item 개수: {status_registered}")
logger.debug(f"공개 상태인 item 개수: {status_published}")
def get_results(self):
return self.results
@ -73,9 +87,25 @@ class Kipris_API:
'drawing': '',
'bigDrawing': ''
}
logger.debug(f" Search params : {params}")
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()
def close_Kipris(self):
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, "카테고리 설명을 찾을 수 없습니다.")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

View File

@ -3,7 +3,10 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices
from src.toggleSwitch import ToggleSwitch
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class SettingsDialog(QtWidgets.QDialog):
def __init__(self, parent=None, initial_settings=None):
super().__init__(parent)
@ -42,6 +45,7 @@ class SettingsDialog(QtWidgets.QDialog):
def setupUI(self):
logger.debug(f"setupUI 시작")
# 셋업 메인 레이아웃
self.mainLayout = QtWidgets.QVBoxLayout(self)
@ -207,7 +211,9 @@ class SettingsDialog(QtWidgets.QDialog):
self.accept()
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.usage_mode = settings.get('usage_mode', 'web') # 기본값 'web'로 설정
@ -215,10 +221,10 @@ class SettingsDialog(QtWidgets.QDialog):
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 업데이트
self.isUseKiprisSwitch.setChecked(self.use_kipris)
self.apikeySwitch.setChecked(self.usage_mode == 'api')
@ -246,17 +252,19 @@ class SettingsDialog(QtWidgets.QDialog):
def toggleCNYexchange(self, checked):
self.exchangeCNYSwitch.setChecked(checked)
self.setCNY = checked
print(f"self.setCNY : {self.setCNY}")
def toggleUSDexchange(self, checked):
logger.debug(f"self.setCNY : {self.setCNY}")
def toggleUSDexchange(self, checked):
self.exchangeUSDSwitch.setChecked(checked)
self.setUSD = checked
print(f"self.setUSD : {self.setUSD}")
logger.debug(f"self.setUSD : {self.setUSD}")
def toggleKiprisUsage(self, checked):
self.settingKiprisWidget.setVisible(checked)
self.checkWidget.setVisible(checked)
self.use_kipris = checked
logger.debug(f"self.use_kipris : {self.use_kipris}")
# self.kiprisFrame.setVisible(False)
def toggleAPIUsage(self, checked):
@ -264,12 +272,14 @@ class SettingsDialog(QtWidgets.QDialog):
self.useWebSwitch.setChecked(not checked)
self.editAPIWidget.setVisible(checked)
self.usage_mode = 'api' if checked else 'web'
logger.debug(f"self.usage_mode : {self.usage_mode}")
def toggleWebUsage(self, checked):
self.useWebSwitch.setChecked(checked)
self.apikeySwitch.setChecked(not checked)
self.editAPIWidget.setVisible(not checked)
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):
layout = QtWidgets.QHBoxLayout()
@ -306,36 +316,51 @@ class SettingsDialog(QtWidgets.QDialog):
if status in self.set_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):
if state == QtCore.Qt.Checked:
for checkbox in self.checkboxes:
checkbox.setChecked(True)
self.right_rejected_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:
for checkbox in self.checkboxes[1:]: # "등록" 체크박스 제외
checkbox.setChecked(False)
self.checkboxes[0].setChecked(True) # "등록" 체크박스는 항상 체크
self.right_rejected_checkbox.setChecked(False)
self.right_expiration_checkbox.setChecked(False)
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):
for checkbox in self.checkboxes:
# 글자를 진하게 만들기
font = checkbox.font()
font.setBold(checkbox.isChecked())
checkbox.setFont(font)
self.right_registered_checkbox.setChecked(True) # "등록" 체크박스는 항상 체크
# 전체 체크 상태 업데이트
all_checked = all(checkbox.isChecked() for checkbox in self.checkboxes)
all_unchecked = all(not checkbox.isChecked() for checkbox in self.checkboxes[1:]) # "등록" 제외
logger.debug(f"all_checked : {state}")
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) # 시그널 재개
# def handle_checkbox_state_changed(self):
# for checkbox in self.checkboxes:
# # 글자를 진하게 만들기
# font = checkbox.font()
# font.setBold(checkbox.isChecked())
# checkbox.setFont(font)
# # 전체 체크 상태 업데이트
# 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):
@ -354,9 +379,14 @@ class HelpDialog(QtWidgets.QDialog):
)
else:
self.resize(400, 300) # 단독 실행 시 크기 설정
logger.debug(f"HelpDialog 초기화")
self.setupUI()
def setupUI(self):
logger.debug(f"HelpDialog setupUI 로드")
layout = QtWidgets.QVBoxLayout(self)
textBrowser = QtWidgets.QTextBrowser(self)
textBrowser.setOpenExternalLinks(False) # 외부 링크 자동 열기 비활성화
@ -387,10 +417,6 @@ class HelpDialog(QtWidgets.QDialog):
QDesktopServices.openUrl(url)
# ※ 행정 상태 도움말
# 거절 : 출원 후 특허 심사과정에서 실체적인 특허 등록요건을 만족하지 못할 경우에 심사관이 취하는 행정처분
# 등록 : 심사관이 심사한 결과 등록요건에 적합하여 설정등록을 받을 수 있다는 내용의 행정처분

View File

@ -3,7 +3,10 @@ import random, requests, json
from PIL import Image
import os
from io import BytesIO
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class Kipris_WEB:
def __init__(self, apikey=None):
self.apikey = apikey
@ -42,45 +45,45 @@ class Kipris_WEB:
def run(self, term, status):
"""검색어로 검색하고 결과 수집"""
print(f"Playwright 검색시작 : 키워드 : [{term}]")
logger.debug(f"Playwright 검색시작 : 키워드 : [{term}]")
try:
self.page.fill("#queryText", term)
self.page.click(".input_btn")
# JavaScript에 의해 결과가 동적으로 로드되기를 기다립니다.
loaded = self.page.wait_for_function("document.querySelector('form#listForm section.search_section article') != null")
print("검색페이지 로드 완료")
logger.debug("검색페이지 로드 완료")
if not loaded:
print("검색 결과가 시간 내에 로드되지 않았습니다.")
logger.debug("검색 결과가 시간 내에 로드되지 않았습니다.")
return None
# 검색 결과가 없는지 확인
nodata_info = self.page.query_selector(".nodata_info")
if nodata_info:
print("검색 결과가 없습니다.")
logger.debug("검색 결과가 없습니다.")
# 특정 메서드 호출 및 함수 종료
# self.handle_no_search_results()
return None
print("검색 결과 로딩 후 실제 요소 수집 시작")
logger.debug("검색 결과 로딩 후 실제 요소 수집 시작")
# 결과 로딩이 확인된 후, 실제 요소를 수집
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")
print(f"total_count : {total_count}")
logger.debug(f"total_count : {total_count}")
if total_count:
self.results['total_count'] = total_count.strip()
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):
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"
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"
if applno:
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")
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
# 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"
print(f"아이템 정보 변수 만들기")
logger.debug(f"아이템 정보 변수 만들기")
# if not admin_status == "소멸":
if admin_status in status:
@ -123,12 +126,12 @@ class Kipris_WEB:
"publication_date": publication_date,
"registration_date": registration_date,
}
print("리턴")
logger.debug("리턴")
return self.results
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:
print(f"오류 발생 : {e}")
logger.debug(f"오류 발생 : {e}")
return None
def download_image(url, applno):
@ -138,9 +141,9 @@ class Kipris_WEB:
filename = f"{applno}.jpeg" # 파일 이름을 ID로 설정
with open(filename, 'wb') as file:
file.write(response.content)
print(f"이미지가 성공적으로 저장되었습니다: {filename}")
logger.debug(f"이미지가 성공적으로 저장되었습니다: {filename}")
else:
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
def load_category_descriptions(self, filename):
"""JSON 파일에서 카테고리 설명을 로드합니다."""
@ -167,10 +170,10 @@ class Kipris_WEB:
image.save(buffer, 'JPEG') # 예시로 JPEG 포맷을 사용
return buffer.getvalue()
except Exception as e:
print(f"이미지 변환 실패: {e}")
logger.debug(f"이미지 변환 실패: {e}")
return None
else:
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
return None
def close_Kipris(self):

View File

@ -2,11 +2,16 @@ import sys
from PyQt5.QtWidgets import QSizePolicy, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QGridLayout
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
# from PyQt5.Qt import QDesktopServices
import webbrowser
import requests
from PIL import Image
from io import BytesIO
import asyncio, aiofiles, aiohttp
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class ResultWidget(QWidget):
def __init__(self):
super().__init__()
@ -15,9 +20,13 @@ class ResultWidget(QWidget):
def initUI(self):
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
def show_results(self, results):
try:
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()
@ -30,11 +39,13 @@ class ResultWidget(QWidget):
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):
result_key = f"result_{i}"
if result_key in results:
result = results[result_key]
logger.debug(f"show_results - result_key : {result_key}")
# 테두리 설정
border_style = ''
@ -72,7 +83,19 @@ class ResultWidget(QWidget):
# 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"<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" \
@ -82,6 +105,9 @@ class ResultWidget(QWidget):
f"<span style='font-size: 9pt;'> {result['registration_date']}</span>"
info_label = QLabel(info_text)
if searchType =='web':
currentURL_btn = QPushButton("웹 열기")
# 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)
@ -100,19 +126,27 @@ class ResultWidget(QWidget):
close_button.clicked.connect(self.close_results_widget)
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.setWindowTitle('Search Results') # 타이틀 설정
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):
# 결과 위젯닫기 함수를 호출할 때 사용하는 메서드
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):
"""주어진 너비에 맞게 텍스트를 줄바꿈합니다."""
@ -133,31 +167,31 @@ class ResultWidget(QWidget):
async def fetch_image_data_async(self, url):
"""주어진 URL로부터 이미지 데이터를 비동기적으로 가져와 반환합니다."""
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:
print(f"download_image url : {url}")
logger.debug(f"download_image url : {url}")
if response.status == 200:
# print(f"response : {response}")
# logger.debug(f"response : {response}")
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:
# 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()
else:
try:
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
data = await response.read()
# print(f"Content-Type이 이미지가 아님 : {data}")
# logger.debug(f"Content-Type이 이미지가 아님 : {data}")
image = Image.open(BytesIO(data))
with BytesIO() as buffer:
image.save(buffer, 'JPEG')
print(f"image 를 JPEG로 저장")
logger.debug(f"image 를 JPEG로 저장")
return buffer.getvalue()
except Exception as e:
print(f"이미지 변환 실패: {e}")
logger.debug(f"이미지 변환 실패: {e}")
return None
else:
print(f"이미지 다운로드 실패: HTTP {response.status}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status}")
return None
@ -177,8 +211,8 @@ class ResultWidget(QWidget):
image.save(buffer, 'JPEG') # 예시로 JPEG 포맷을 사용
return buffer.getvalue()
except Exception as e:
print(f"이미지 변환 실패: {e}")
logger.debug(f"이미지 변환 실패: {e}")
return None
else:
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
return None

View File

@ -2,6 +2,11 @@ import requests, os
from PyQt5.QtWidgets import QWidget, QTextBrowser, QVBoxLayout
from PyQt5.QtCore import Qt
from PIL import Image
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class TrademarkSearchDisplay(QWidget):
def __init__(self, parent=None):
super().__init__()
@ -69,22 +74,22 @@ class TrademarkSearchDisplay(QWidget):
self.text_browser.append(html_content)
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_'로 시작하는 키를 찾아 그 값을 처리
for key, item in data.items():
print(f"Checking key: {key}") # 로그 추가
logger.debug(f"Checking key: {key}") # 로그 추가
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이 딕셔너리인지 확인
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"))
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;">'
else:
print("Failed to download image.")
logger.debug("Failed to download image.")
image_html = 'Image not available'
# HTML 콘텐츠 생성
@ -123,11 +128,11 @@ class TrademarkSearchDisplay(QWidget):
'''
self.text_browser.append(html_content)
print("HTML content appended to QTextBrowser.") # 로그 추가
logger.debug("HTML content appended to QTextBrowser.") # 로그 추가
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:
print(f"Ignored key: {key}") # 무시된 키 로그
logger.debug(f"Ignored key: {key}") # 무시된 키 로그
def download_image(self, image_url, identifier):
@ -160,7 +165,7 @@ class TrademarkSearchDisplay(QWidget):
img_resized.save(image_path)
return image_path
except Exception as e:
print(f"Error resizing image: {e}")
logger.debug(f"Error resizing image: {e}")
return None

View File

@ -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개월 미만도 공개가능
#

View File

@ -1,6 +1,10 @@
from PyQt5.QtCore import Qt, QRect, QPropertyAnimation, pyqtProperty, pyqtSignal, QPoint
from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import QWidget
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class ToggleSwitch(QWidget):
clicked = pyqtSignal(bool)

View File

@ -4,7 +4,10 @@ import random, requests, json
from PIL import Image
from io import BytesIO
import os
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class WebScraper:
def __init__(self):
self.results = {}
@ -12,6 +15,7 @@ class WebScraper:
self.browser = None
self.context = None
self.page = None
self.currentURL = ''
filename = 'categories.json'
self.category_description = self.load_category_descriptions(filename)
self.url = "http://kdtj.kipris.or.kr/kdtj/searchLogina.do?method=loginTM#page1"
@ -42,9 +46,9 @@ class WebScraper:
try:
await self.page.goto(self.url, wait_until='networkidle')
self.is_page_loaded = True
print("Page loaded successfully.")
logger.debug("Page loaded successfully.")
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 # 로드 실패 처리
@ -52,9 +56,9 @@ class WebScraper:
try:
await self.page.goto(url, wait_until='networkidle')
self.is_page_loaded = True
print("Page loaded successfully.")
logger.debug("Page loaded successfully.")
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 # 로드 실패 처리
@ -65,23 +69,23 @@ class WebScraper:
# await self.page.fill("#queryText", term)
await self.page.fill("#keywordTextarea", term)
print(f"검색어 입력 : {term}")
logger.debug(f"검색어 입력 : {term}")
await self.page.click(".input_btn")
print(f"검색버튼 클릭")
logger.debug(f"검색버튼 클릭")
# JavaScript에 의해 결과가 동적으로 로드되기를 기다립니다.
loaded = await self.page.wait_for_function(
"document.querySelector('form#listForm section.search_section article') != null"
)
if not loaded:
print("검색 결과가 시간 내에 로드되지 않았습니다.")
logger.debug("검색 결과가 시간 내에 로드되지 않았습니다.")
return None
print(f"결과가 동적으로 로드되기를 기다림 : {loaded}")
logger.debug(f"결과가 동적으로 로드되기를 기다림 : {loaded}")
# 검색 결과가 없는지 확인
nodata_info = await self.page.query_selector(".nodata_info")
if nodata_info:
print("검색 결과가 없습니다.")
logger.debug("검색 결과가 없습니다.")
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 = total_count.strip()
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:
self.results['total_count'] = total_count
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):
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"
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"
trademark_image_url_by_id = (
f"http://kdtj.kipris.or.kr/kdtj/remoteFile.do?method=bigImageTM&applno={applno}&no={applno}_tm000001.jpg"
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")
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 = 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 = 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"
print(f"product_category : {product_category}")
print(f"category_desc : {category_desc}")
logger.debug(f"product_category : {product_category}")
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 = 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)")
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"
else:
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)")
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"
else:
registration_date = "No registration date found"
print(f"registration_date : {registration_date}")
if not (admin_status == "소멸" or admin_status == "거절"):
logger.debug(f"registration_date : {registration_date}")
if admin_status in status: # status는 self.set_status 리스트를 참조
# if not (admin_status == "소멸" or admin_status == "거절"):
self.results[f"result_{i+1}"] = {
"ID": applno,
"title": trademark_name,
@ -154,65 +161,65 @@ class WebScraper:
"publication_date": publication_date,
"registration_date": registration_date,
}
# print(f"results : {self.results}")
# logger.debug(f"results : {self.results}")
await self.navigate_to_page(self.url)
return self.results
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:
print(f"오류 발생 : {e}")
logger.debug(f"오류 발생 : {e}")
return None
async def download_image(self, url, applno):
"""이미지를 비동기적으로 다운로드하고 applno를 파일 이름으로 사용하여 저장합니다."""
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:
print(f"download_image url : {url}")
logger.debug(f"download_image url : {url}")
if response.status == 200:
filename = f"{applno}.jpeg"
async with aiofiles.open(filename, 'wb') as file:
content = await response.read()
await file.write(content)
print(f"이미지가 성공적으로 저장되었습니다: {filename}")
logger.debug(f"이미지가 성공적으로 저장되었습니다: {filename}")
else:
print(f"이미지 다운로드 실패: HTTP {response.status}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status}")
async def fetch_image_data(self, url):
"""주어진 URL로부터 이미지 데이터를 비동기적으로 가져와 반환합니다."""
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:
print(f"download_image url : {url}")
logger.debug(f"download_image url : {url}")
if response.status == 200:
# print(f"response : {response}")
# logger.debug(f"response : {response}")
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:
# 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()
else:
try:
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
data = await response.read()
# print(f"Content-Type이 이미지가 아님 : {data}")
# logger.debug(f"Content-Type이 이미지가 아님 : {data}")
image = Image.open(BytesIO(data))
with BytesIO() as buffer:
image.save(buffer, 'JPEG')
print(f"image 를 JPEG로 저장")
logger.debug(f"image 를 JPEG로 저장")
return buffer.getvalue()
except Exception as e:
print(f"이미지 변환 실패: {e}")
logger.debug(f"이미지 변환 실패: {e}")
return None
else:
print(f"이미지 다운로드 실패: HTTP {response.status}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status}")
return None
# async def load_category_descriptions(self, filename):
# """JSON 파일에서 카테고리 설명을 비동기적으로 로드합니다."""
# async with aiofiles.open(filename, 'r', encoding='utf-8') as file:
# content = await file.read()
# print(f"JSON 파일에서 카테고리 설명을 비동기적으로 로드합니다: {content}")
# logger.debug(f"JSON 파일에서 카테고리 설명을 비동기적으로 로드합니다: {content}")
# return json.loads(content)
def load_category_descriptions(self, filename):
@ -222,7 +229,7 @@ class WebScraper:
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, "카테고리 설명을 찾을 수 없습니다.")

View File

@ -1,7 +1,10 @@
from requests_html import HTMLSession
import json
import requests
import logging
# 로거 인스턴스 가져오기
logger = logging.getLogger('default_logger')
class WebScraper:
def __init__(self):
self.session = HTMLSession()
@ -23,7 +26,7 @@ class WebScraper:
"""지정된 URL로 이동하고 페이지를 로드합니다."""
response = self.session.get(url)
response.html.render() # 필요 시 JavaScript 실행
print("Page loaded successfully.")
logger.debug("Page loaded successfully.")
return response
def search_for_term(self, term):
@ -43,17 +46,17 @@ class WebScraper:
search_response.html.render()
return search_response
else:
print("폼의 action URL을 찾을 수 없습니다.")
logger.debug("폼의 action URL을 찾을 수 없습니다.")
else:
print("검색 폼을 찾을 수 없습니다.")
logger.debug("검색 폼을 찾을 수 없습니다.")
except Exception as e:
print(f"검색 실행 중 오류 발생: {e}")
logger.debug(f"검색 실행 중 오류 발생: {e}")
# response.html.render(script=script, reload=False)
# # response.html.find('#keywordTextarea', first=True).fill(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)
# script = f"document.querySelector('#keywordTextarea').value = '{term}';"
# response.html.page.evaluate(script) # JavaScript 실행
@ -64,7 +67,7 @@ class WebScraper:
articles = response.html.find('form#listForm section.search_section article')
if not articles:
print("검색 결과가 없습니다.")
logger.debug("검색 결과가 없습니다.")
return None
# Store results in a structured format
@ -87,9 +90,9 @@ class WebScraper:
filename = f"{applno}.jpeg"
with open(filename, 'wb') as file:
file.write(response.content)
print(f"이미지가 성공적으로 저장되었습니다: {filename}")
logger.debug(f"이미지가 성공적으로 저장되었습니다: {filename}")
else:
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
def fetch_image_data(self, url):
"""주어진 URL로부터 이미지 데이터를 직접 가져와 반환합니다."""
@ -97,7 +100,7 @@ class WebScraper:
if response.status_code == 200:
return response.content
else:
print(f"이미지 다운로드 실패: HTTP {response.status_code}")
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
return None
def close_browser(self):
@ -107,4 +110,4 @@ class WebScraper:
# # 사용 예시
# scraper = WebScraper()
# results = scraper.search_for_term("특허")
# print(results)
# logger.debug(results)