로그추가
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,
|
||||
"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
|
|
@ -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_())
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@
|
|||
|
||||
a = Analysis(
|
||||
['delv.py'],
|
||||
pathex=['H:\\py\\delvfee'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[
|
||||
'sip', 'jinja2'
|
||||
],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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() # 리소스 정리
|
||||
|
|
|
|||
|
|
@ -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, "카테고리 설명을 찾을 수 없습니다.")
|
||||
|
||||
|
|
|
|||
|
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 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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ※ 행정 상태 도움말
|
||||
# 거절 : 출원 후 특허 심사과정에서 실체적인 특허 등록요건을 만족하지 못할 경우에 심사관이 취하는 행정처분
|
||||
# 등록 : 심사관이 심사한 결과 등록요건에 적합하여 설정등록을 받을 수 있다는 내용의 행정처분
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.QtGui import QPainter, QColor
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
import logging
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
|
||||
class ToggleSwitch(QWidget):
|
||||
clicked = pyqtSignal(bool)
|
||||
|
|
|
|||
|
|
@ -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, "카테고리 설명을 찾을 수 없습니다.")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||