KiprisAPI/main_async.py

249 lines
11 KiB
Python

import sys
import asyncio
from tkinter import EXCEPTION
import qasync
from PyQt5.QtWidgets import QApplication, QGridLayout, QSizePolicy, QProgressDialog, QMessageBox, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QTextEdit
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from web_scraper_async import WebScraper
class MainApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.scraper = WebScraper()
self.results_widget = None # 초기에는 결과 위젯이 없음
def initUI(self):
searchLayout = QHBoxLayout()
self.searchLabel = QLabel('검색어 입력:', self)
self.searchButton = QPushButton('검색 실행', self)
# 검색 버튼 클릭 시 start_search를 비동기로 실행
self.searchButton.clicked.connect(self.on_search_button_clicked)
self.searchButton.setEnabled(False) # 초기에 버튼을 비활성화합니다.
self.searchLineEdit = QLineEdit(self)
# 엔터 키를 누를 때 start_search를 비동기로 실행
self.searchLineEdit.returnPressed.connect(self.on_search_button_clicked)
# self.searchLineEdit.setEnabled(False) # 초기에 입력 필드도 비활성화
searchLayout.addWidget(self.searchLabel)
searchLayout.addWidget(self.searchLineEdit)
searchLayout.addWidget(self.searchButton)
logLayout = QVBoxLayout()
self.logTextEdit = QTextEdit(self)
self.logTextEdit.setReadOnly(True)
logLayout.addWidget(self.logTextEdit)
mainLayout = QVBoxLayout()
mainLayout.addLayout(searchLayout)
mainLayout.addLayout(logLayout)
self.setLayout(mainLayout)
self.setWindowTitle('Web Scraper')
self.setGeometry(300, 300, 300, 400)
def start_search_process(self):
# 검색 프로세스 시작 시 QProgressDialog 설정
self.progress_dialog = QProgressDialog("검색 진행 중... 잠시만 기다려 주세요.", "취소", 0, 100, self)
self.progress_dialog.setWindowTitle("검색 진행 상태")
self.progress_dialog.setWindowModality(Qt.WindowModal)
self.progress_dialog.setAutoClose(True)
self.progress_dialog.setAutoReset(True)
self.progress_dialog.canceled.connect(self.cancel_search)
self.progress_dialog.show()
# 검색 시작
asyncio.ensure_future(self.perform_search(self.searchLineEdit.text()))
async def perform_search(self, term):
# 검색어를 사용하여 실제 검색 수행을 시뮬레이션합니다.
for i in range(101):
if self.progress_dialog.wasCanceled():
break
self.progress_dialog.setValue(i) # 진행 상황 업데이트
await asyncio.sleep(0.05) # 검색 시간을 시뮬레이션
if not self.progress_dialog.wasCanceled():
self.progress_dialog.setValue(100) # 작업 완료
def cancel_search(self):
# 검색 취소 로직
print("검색이 사용자에 의해 취소되었습니다.")
def on_search_button_clicked(self):
asyncio.ensure_future(self.start_search())
async def prepare_search(self):
# setup_browser에서 페이지 로딩을 관리하므로 여기서는 로딩 완료를 기다립니다.
print(f"prepare_search Start : is_page_loaded : {self.scraper.is_page_loaded}")
while not self.scraper.is_page_loaded:
print(f"is_page_loaded : {self.scraper.is_page_loaded}")
await asyncio.sleep(1) # 로딩 상태를 주기적으로 체크합니다.
self.searchButton.setEnabled(True)
# self.searchLineEdit.setEnabled(True)
async def start_search(self):
term = self.searchLineEdit.text()
if not term:
self.logTextEdit.append("검색어를 입력해주세요.")
QMessageBox.warning(self, "경고", "검색어를 입력해주세요.")
return
self.logTextEdit.append("검색을 시작합니다...")
try:
results = await self.scraper.search_for_term(term)
if results:
self.logTextEdit.append("검색 완료. 결과를 처리합니다...")
await self.show_results(results)
else:
self.logTextEdit.append("검색 결과가 없거나 오류가 발생했습니다.")
QMessageBox.information(self, "검색 결과 없음", "검색 결과가 없으므로 지재권에 안심하시면 됩니다.", QMessageBox.Ok)
except Exception as e:
self.logTextEdit.append(f"검색 중 오류 발생: {str(e)}")
async def show_results(self, results):
try:
# 이전 결과 위젯이 있으면 닫기
if self.results_widget is not None:
self.results_widget.close() # 기존 위젯 닫기
self.results_widget = None # 참조 제거
# 새 결과 위젯 생성
self.results_widget = QWidget()
layout = QVBoxLayout()
self.results_widget.setLayout(layout)
total_count = results['total_count']
if total_count is not int:
total_count = int(results['total_count'])
set_count = min(total_count, 10)
grid_layout = QGridLayout()
layout.addLayout(grid_layout)
grid_index = 0
grid_columns = 5
for i in range(1, set_count + 1):
result_key = f"result_{i}"
if result_key in results:
result = results[result_key]
print(f"result num {i}: {result}")
# 테두리 설정
border_style = ''
if result['admin_status'] == '등록':
border_style = 'border: 4px solid red;'
elif result['admin_status'] == '공고':
border_style = 'border: 3px solid black;'
item_layout = QVBoxLayout()
item_widget = QWidget()
item_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)
print("item_widget set")
try:
image_label = QLabel()
image_label.setFixedSize(150, 150)
image_data = await self.scraper.fetch_image_data(result['IDimageURL'])
print(f"image_data : {image_data}")
pixmap = QPixmap()
if image_data:
pixmap.loadFromData(image_data)
scaled_pixmap = pixmap.scaled(image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
image_label.setPixmap(scaled_pixmap)
image_label.setAlignment(Qt.AlignCenter)
image_label.setScaledContents(True)
print(f"image URL : [{result['IDimageURL']}]")
print("image set")
horizontal_layout = QHBoxLayout()
horizontal_layout.addWidget(image_label)
horizontal_layout.setAlignment(Qt.AlignCenter)
item_layout.addLayout(horizontal_layout)
print("horizontal_layout set")
except Exception as e:
print(f" 이미지 데이터 처리 중 에러 : {e}")
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['admin_status']}</span><br>\n" \
f"<span style='font-size: 9pt;'>카테고리: {result['product_category']}</span><br>\n" \
f"<span style='font-size: 9pt;'>권리자: {result['applicant']}</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>"
print(f"info_text : {info_text}")
info_label = QLabel(info_text)
print(f"result['category_description'] : {result['category_description']}")
tooltip_text = self.wrap_text(result['category_description'], 50)
info_label.setToolTip(tooltip_text)
image_label.setToolTip(tooltip_text)
item_layout.addWidget(info_label)
image_label.setStyleSheet(border_style)
info_label.setStyleSheet(border_style)
print("item_layout set")
# 레이아웃에 위젯 추가
row = grid_index // grid_columns
col = grid_index % grid_columns
grid_layout.addLayout(item_layout, row, col)
# grid_layout.addLayout(item_layout, grid_index // grid_columns, grid_index % grid_columns)
grid_index += 1
close_button = QPushButton("Close")
close_button.clicked.connect(self.close_results_widget)
layout.addWidget(close_button)
print("close_button set")
self.results_widget.setGeometry(300, 300, 800, 600)
self.results_widget.setWindowTitle('Search Results')
print("Search Results results_widget set")
self.results_widget.show()
except Exception as e:
print(f"Error displaying results: {e}")
def wrap_text(self, text, width=40):
"""주어진 너비에 맞게 텍스트를 줄바꿈합니다."""
words = text.split()
wrapped_text = ''
line_length = 0
for word in words:
if line_length + len(word) + 1 > width:
wrapped_text += '\n'
line_length = 0
wrapped_text += word + ' '
line_length += len(word) + 1
return wrapped_text.strip()
def close_results_widget(self):
self.results_widget.close()
def closeEvent(self, event):
asyncio.create_task(self.scraper.close_browser())
super().closeEvent(event) # QWidget의 기본 closeEvent 처리
if __name__ == '__main__':
app = qasync.QApplication(sys.argv)
ex = MainApp()
loop = qasync.QEventLoop(app)
asyncio.set_event_loop(loop)
ex.show()
# `setup_browser`가 완료될 때까지 기다립니다.
loop.create_task(ex.scraper.setup_browser())
loop.create_task(ex.prepare_search())
# `loop.run_forever()`를 사용하여 이벤트 루프를 시작합니다.
loop.run_forever()