23.03.08 Day27

오윤범·2023년 3월 8일
0

MiniProject / NaverAPI 뉴스검색

1) QtDesigner을 통한 ui 작성



2) Naver 개발자 센터에서 OpenAPI 받아오기

https://developers.naver.com/main

Client-ID / Client-Secret 발급


3) NaverApi.py 작성(OpenApi를 통해 데이터 전달받음)


#NaverApi 클래스 - OpenApi : 인터넷을 통해 데이터 전달받음
from urllib.request import Request,urlopen
from urllib.parse import quote
import datetime
import json
class NaverApi:
    # 생성자
    def __init__(self) -> None:
        print(f'[{datetime.datetime.now()}] Naver API Search 생성')

    # NaverAPI를 요청
    def getRequestUrl(self,url):
        req=Request(url)
        #NaverAPI 개인 인증
        req.add_header('X-Naver-Client-ID','kflq_q32Q1Q3tf46AKDF')
        req.add_header('X-Naver-Client-Secret','kpYx2Ai7O5')
        try:
            res = urlopen(req) #요청결과 바로 반환
            if res.getcode() ==200: # reponse OK
                print(f'[{datetime.datetime.now()}] NaverAPI 요청 성공')
                return res.read().decode('utf-8') #사용자가 알아볼 수 있게 반환
            else:
                print(f'[{datetime.datetime.now()}]NaverAPI 요청 실패')
                return None

        except Exception as e:
            print(f'[{datetime.datetime.now()}] 예외발생 : {e}')
            return None

    # 호출
    def getNaverSearch(self,node,search,start,display):
        base_url='https://openapi.naver.com/v1/search'
        node_url=f'/{node}.json'
        params=f'?query={quote(search)}&start={start}&display={display}'

        url=base_url+node_url+params #전체 url

        retData=self.getRequestUrl(url)

        if retData==None : return None
        else : return json.loads(retData) # json 으로 return

4) NaverSearchApp.py 작성(NaverApiSearch.ui의 동작을 설정)


# Qt Designer 디자인 사용
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from NaverApi import * #만들어둔 NaverApi 클래스 사용
import webbrowser #웹브라우저 모듈(링크연결 등)
from PyQt5.QtGui import *

# NaverApiSearch.ui의 동작을 설정하는것

class qtApp(QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi('./PyQt_Practice/NaverApiSearch.ui',self)
        self.setWindowIcon(QIcon('./PyQt_practice/newspaper.png'))
        # 검색버튼 클릭시그널 / 슬롯함수
        self.btnSearch.clicked.connect(self.btnSearchClicked)
        # 텍스트박스에 검색어 입력 후 엔터 처리
        self.txtSearch.returnPressed.connect(self.txtSearchReturned)
        # 링크 더블클릭
        self.tblResult.doubleClicked.connect(self.tblResultDoubleClicked) 

    def tblResultDoubleClicked(self): #링크 더블클릭
        #row=self.tblResult.currentIndex().row()
        #column=self.tblResult.currentIndex().column()
        # print(row,column)
        selected=self.tblResult.currentRow() #선택한 뉴스 행
        url=self.tblResult.item(selected,1).text() #뉴스 기사 링크 뽑아냄 
        webbrowser.open(url) #해당 링크 연결

    def txtSearchReturned(self): # 검색어 입력 후 엔터쳤을 때 처리 부분
        self.btnSearchClicked()

    def btnSearchClicked(self):
        search=self.txtSearch.text()

        if search=='':
            QMessageBox.warning(self,'경고','검색어를 입력하세요')
            return
        else:
            api=NaverApi() # NaverApi 클래스 객체 생성
            node='news'
            display=100 #검색결과 100개만 뽑아오겠다는 의미

            result=api.getNaverSearch(node,search,1,display)
            #print(result)

            #QTableWidget에 출력하기
            items=result['items'] # json전체 결과 중 items 아래 배열만 잘라오는 의미 
            self.makeTable(items) # 테이블위젯에 데이터들을 할당한다


    # 테이블 위젯에 데이터 표시
    def makeTable(self,items) -> None:
        self.tblResult.setSelectionMode(QAbstractItemView.SingleSelection)# 단일선택모드
        self.tblResult.setColumnCount(2)
        self.tblResult.setRowCount(len(items)) #display값으로 설정하여 나온 결과값 100개 행 생성
        self.tblResult.setHorizontalHeaderLabels(['기사제목','뉴스링크']) #행 제목 변경
        self.tblResult.setColumnWidth(0,310)
        self.tblResult.setColumnWidth(1,260)
        self.tblResult.setEditTriggers(QAbstractItemView.NoEditTriggers) #컬럼데이터 수정금지

        for i,post in enumerate(items): #0,뉴스... / 1,뉴스... 형태
            title=self.replaceHtmlTab(post['title']) # HTMl 특수문자 변환
            originallink=post['originallink']
            #setItem(행,열,넣을데이터)
            self.tblResult.setItem(i,0,QTableWidgetItem(title))
            self.tblResult.setItem(i,1,QTableWidgetItem(originallink))

    # HTMl 특수문자 변환하는 함수
    def replaceHtmlTab(self,sentence) -> str: #->str :함수 끝에서 str을 반환한다는뜻
        #제목에 그대로 출력되는 HTML 기호들을 가독성 좋게 변환
        result=sentence.replace('&lt;', '<').replace('&gt;', '>').replace('<b>', 
        '').replace('</b>', '').replace('&apos;', "'").replace('&quot;', '"') 
        return result

if __name__=='__main__':
    app=QApplication(sys.argv)
    ex=qtApp()
    ex.show()
    sys.exit(app.exec_())
  • 결과화면




  • 소스코드(Github)


https://github.com/OHYUNBEOM/MiniProjects/tree/main/part1

기술스택

1. Python
2. PyQt
3. Qt Designer
  • 어려웠던 부분


  1. NaverAPi.py에서 NaverAPi를 요청하고 실제로 호출한 함수 getNaverSearch에서 전체 url을 json형태로 재변환하는것
  2. NaverSearchApp.py에서 NaverApiSearch.ui 가 하는 동작을 해당 동작에 맞게 함수로 구현해 주는것
  3. json파일로 받아오는 result를 ui에 뿌려줄 때 가독성이 좋을 수 있게 replaceHtmlTab 함수를 통해 HTML 기호를 변환하는것




네이버 API 영화검색(기존 뉴스검색에서 일정부분 변경)

# Qt Designer 디자인 사용
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from NaverApi import * #만들어둔 NaverApi 클래스 사용
import webbrowser #웹브라우저 모듈(링크연결 등)
from PyQt5.QtGui import *
from urllib.request import urlopen # 빠른 이미지 다운(포스터)

# NaverApiSearch.ui의 동작을 설정하는것

class qtApp(QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi('./PyQt_Practice/NaverApiMovie.ui',self)
        self.setWindowIcon(QIcon('./PyQt_practice/newspaper.png'))
        # 검색버튼 클릭시그널 / 슬롯함수
        self.btnSearch.clicked.connect(self.btnSearchClicked)
        # 텍스트박스에 검색어 입력 후 엔터 처리
        self.txtSearch.returnPressed.connect(self.txtSearchReturned)
        # 링크 더블클릭
        self.tblResult.doubleClicked.connect(self.tblResultDoubleClicked) 

    def tblResultDoubleClicked(self): #링크 더블클릭
        selected=self.tblResult.currentRow() #선택한 영화 행
        url=self.tblResult.item(selected,5).text() #네이버 영화 링크 뽑아냄 
        webbrowser.open(url) #해당 링크 연결

    def txtSearchReturned(self): # 검색어 입력 후 엔터쳤을 때 처리 부분
        self.btnSearchClicked()

    def btnSearchClicked(self):
        search=self.txtSearch.text()

        if search=='':
            QMessageBox.warning(self,'경고','영화명을 입력하세요')
            return
        else:
            api=NaverApi() # NaverApi 클래스 객체 생성
            node='movie'
            display=100 #검색결과 100개만 뽑아오겠다는 의미

            result=api.getNaverSearch(node,search,1,display)
            #print(result)

            #QTableWidget에 출력하기
            items=result['items'] # json전체 결과 중 items 아래 배열만 잘라오는 의미 
            self.makeTable(items) # 테이블위젯에 데이터들을 할당한다


    # 테이블 위젯에 데이터 표시 --> 네이버 영화 결과에 맞춰 변경
    def makeTable(self,items) -> None:
        self.tblResult.setSelectionMode(QAbstractItemView.SingleSelection)# 단일선택모드
        self.tblResult.setColumnCount(7) 
        self.tblResult.setRowCount(len(items)) #display값으로 설정하여 나온 결과값 100개 행 생성
        self.tblResult.setHorizontalHeaderLabels(['영화제목','개봉년도','감독',
                                                  '출연진','평점','링크','포스터']) #행 제목 변경
        self.tblResult.setColumnWidth(0,150)
        self.tblResult.setColumnWidth(1,60) #개봉년도
        self.tblResult.setColumnWidth(4,50)
        self.tblResult.setEditTriggers(QAbstractItemView.NoEditTriggers) #컬럼데이터 수정금지

        for i,post in enumerate(items): #0,영화
            title=self.replaceHtmlTab(post['title']) # HTMl 특수문자 변환
            pubDate=post['pubDate']
            director = post['director']
            actor = post['actor']
            userRating=post['userRating']
            link=post['link']
            #image=QImage(requests.get(post['image'], stream=True))
            #영화 포스터 넣기
            # imgData=urlopen(post['image']).read()
            # image = QPixmap()
            # image.loadFromData(imgData)
            # imgLabel=QLabel()
            # imgLabel.setPixmap(image)
            # imgLabel.setGeometry(0,0,60,100)
            # imgLabel.resize(60,100)
            #setItem(행,열,넣을데이터)
            self.tblResult.setItem(i,0,QTableWidgetItem(title))
            self.tblResult.setItem(i,1,QTableWidgetItem(pubDate))
            self.tblResult.setItem(i,2,QTableWidgetItem(director))
            self.tblResult.setItem(i,3,QTableWidgetItem(actor))
            self.tblResult.setItem(i,4,QTableWidgetItem(userRating))
            self.tblResult.setItem(i,5,QTableWidgetItem(link))
            # self.tblResult.setCellWidget(i,6,imgLabel)


    # HTMl 특수문자 변환하는 함수
    def replaceHtmlTab(self,sentence) -> str: #->str :함수 끝에서 str을 반환한다는뜻
        #제목에 그대로 출력되는 HTML 기호들을 가독성 좋게 변환
        result=sentence.replace('&lt;', '<').replace('&gt;', '>').replace('<b>', 
        '').replace('</b>', '').replace('&apos;', "'").replace('&quot;', '"') 
        return result

if __name__=='__main__':
    app=QApplication(sys.argv)
    ex=qtApp()
    ex.show()
    sys.exit(app.exec_())

0개의 댓글