게임물관리위원회에서 REST API 호출
REST API, RESTful API?
REST API는 분산 하이퍼미디어 시스템을 연결하는 데 사용되는 스타일인 표현 상태 전송(REST) 아키텍처 스타일의 설계 원칙을 따르는 애플리케이션 프로그래밍 인터페이스(API)입니다.
(위 설명은 IBM 자료인용)
저는 그냥 쉽게 http 요청에 응답하는 서버, 클라이언트 모델이라고 생각합니다.
예를 들면 코로나 시기를 겪은 우리는 그날 그날의 확진자 수를 궁금해 합니다. 하지만 보건복지부에서 일일이 전화나 문의에 대응, 확진자 수를 말하기는 인력과 자원이 많이 듭니다.
하지만 COVID REST 서버를 구축하고 클라이언트가 날짜를 요청하면 그날의 확진자 수를 응답하는 형태라면 편리할 것 같습니다.
보건복지부관계자는 그날의 환자를 집계해 서버에 업데이트만 하면 되고, 사용자는 낮, 밤, 새벽이든 관계없이 필요한 경우 요청해 정보를 받아서 출력하면 그만입니다.
게임물관리위원회 REST 서버
공공기관인 게임물관리위원회도 게임정보에 대한 REST 서버를 운영하고 있습니다.
(공공데이터 포털에 가면 정부에서 수집된 대부분 정보가 다 이렇게 공개됩니다. 날씨앱, 버스앱도 이렇게 공공기관의 데이터를 수집해 제작)
서비스 요청 http URL 과 요청변수가 잘 정리되어 있습니다.
|
| [출처 : 게임물관리위원회] |
제공해준 정보로 클라이언트 앱을 파이썬, PyQt6로 만들어보니 꽤 괜찮습니다.
|
| [카트라이더 검색결과] |
중,고, 대학시절 즐겨했던 디아블로 시리즈도 검색되네요.
|
| [디아블로 검색결과] |
먼저 게임물관리위원회에서 제공하는 샘플 호출입니다.
https://www.grac.or.kr/WebService/GameSearchSvc.asmx/game?display=10&pageno=1
위 주소를 복사해 웹브라우저 주소창에 넣고 실행하면 XML을 미리 확인 가능합니다.
우리는 이걸 요청해 받고, 수신된 XML 문자열을 정리해 표시해야 합니다.
(모든 웹브라우저는 XML Parsing 기능이 포함)
그럼 어떻게 만들었는지 설명해볼까 합니다.
개발환경
- Python 3.12.10 64bit, Windows 11, VS code
- Modules : PyQt6 6.10.0, requests
소스코드
from PyQt6.QtWidgets import (QApplication, QWidget, QPushButton, QTableWidget, QVBoxLayout, QMessageBox,
QLineEdit, QGroupBox, QHBoxLayout,QTableWidgetItem, QLabel)
import sys
import requests
import xml.etree.ElementTree as et
class Window(QWidget):
def __init__(self):
super().__init__()
self.resize(1200,600)
self.initUi()
def initUi(self):
self.setWindowTitle('Ocean Coding School')
gbox = QGroupBox()
lb1 = QLabel('게임명')
lb2 = QLabel('게임제작사')
self.le1 = QLineEdit(self)
self.le2 = QLineEdit(self)
self.pb = QPushButton('검색', self)
self.pb.setDefault(True)
hbox = QHBoxLayout()
hbox.addWidget(lb1)
hbox.addWidget(self.le1)
hbox.addWidget(lb2)
hbox.addWidget(self.le2)
hbox.addWidget(self.pb)
gbox.setLayout(hbox)
self.tw = QTableWidget(self)
vbox = QVBoxLayout()
vbox.addWidget(gbox)
vbox.addWidget(self.tw)
self.setLayout(vbox)
# signal
self.pb.clicked.connect(self.onClick)
self.le1.returnPressed.connect(self.onClick)
self.le2.returnPressed.connect(self.onClick)
def onClick(self):
gn = self.le1.text()
gc = self.le2.text()
URL = 'https://www.grac.or.kr/WebService/GameSearchSvc.asmx/game?'
DSP = 'display=1000'
PAGE = '&pageno=1'
GN = f'&gametitle={gn}'
GC = f'&entname={gc}'
MSG = URL + DSP + PAGE + GN + GC
# request REST api
data = requests.get(MSG)
# decode : byte -> str
txt = data.content.decode('utf-8')
lst = self.xmlParsing(txt, 'item')
#print(lst)
if lst:
self.createTable(lst)
else:
QMessageBox.critical(self, '오류', '검색한 게임정보가 존재하지 않습니다')
def createTable(self, lst):
row = len(lst)
col = len(lst[0])
# row:행, col:열
self.tw.setRowCount(row)
self.tw.setColumnCount(col)
s = ['등급분류번호', '날짜등급분류일자', '게임명', '등급분류기관', '제작사',
'게임물개요', '결정등급', '장르', '게임플랫폼', '내용정보표시', '등급취소유무', '등급취소일자']
self.tw.setHorizontalHeaderLabels(s)
for i in range(row):
for j in range(col):
item = QTableWidgetItem(lst[i][j])
self.tw.setItem(i, j, item)
def xmlParsing(self, txt, item):
lst = []
root = et.fromstring(txt)
for tag in root.iter(tag=item):
temp = []
for st in tag:
temp.append(st.text)
lst.append(temp)
return lst
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec())
코드를 함수별로 정리해 설명해 보겠습니다. 🙂↕️
1. 초기화 및 설정: __init__(self)
이 메서드는 클래스(Window)가 생성될 때 가장 먼저 실행되는 생성자입니다.
- super().__init__(): 부모 클래스인 QWidget의 생성자를 호출하여 윈도우의 기본 기능을 설정
- self.resize(1200, 600): 프로그램 창의 크기를 가로 1200px, 세로 600px로 설정
- self.initUi(): 화면 구성을 담당하는 initUi 함수를 호출하여 UI 생성
2. UI 구성: initUi(self)
프로그램의 화면 레이아웃과 위젯(부품)들을 배치하고, 동작(이벤트)을 연결하는
함수입니다.
위젯 생성:
- QLabel: '게임명', '게임제작사'라는 텍스트 라벨생성
- QLineEdit: 사용자가 검색어를 입력할 수 있는 한 줄 입력창 생성
- QPushButton: '검색' 버튼을 생성하고, 엔터키를 눌렀을 때 기본으로 눌리도록 설정
- QTableWidget: 검색 결과를 보여줄 표(self.tw)를 생성
레이아웃 배치:
- QHBoxLayout: 라벨, 입력창, 버튼을 가로로 나란히 배치
- QVBoxLayout: 위에서 만든 가로 레이아웃(검색창 영역)과 아래의 테이블(결과 영역)을 세로로 배치
시그널(Signal) 연결:
- 버튼 클릭(clicked)이나 입력창에서 엔터키(returnPressed) 입력 시 self.onClick 함수가 실행되도록 연결
3. 이벤트 처리 및 API 요청: onClick(self)
사용자가 '검색'을 시도했을 때 실행되는 핵심 로직 함수입니다.
데이터 준비:
- 입력창(le1, le2)에 적힌 게임명과 제작사 이름얻기
URL 조합:
- 게임물관리위원회의 API 주소(URL)에 요청 변수들(검색 개수, 페이지 번호, 게임명, 제작사)을 문자열로 합쳐서 최종 요청 주소(MSG) 구성
API 요청 (Requests):
- requests.get(MSG): 완성된 주소로 데이터를 요청
- data.content.decode('utf-8'): 받아온 데이터를 UTF-8로 디코딩하여 문자열(txt)로 변환
데이터 파싱 및 처리:
- self.xmlParsing(txt, 'item'): XML 형태의 문자열을 분석하여 리스트 형태(lst)로 변환
결과 확인:
- 결과가 있다면 createTable(lst)를 호출하여 표 생성
- 결과가 없다면 QMessageBox를 띄워 "검색한 게임정보가 존재하지 않습니다"라는 오류 메시지출력
4. 테이블 생성: createTable(self, lst)
파싱된 데이터를 받아와서 화면의 QTableWidget에 채워 넣는 함수입니다.
행/열 설정:
- 데이터 리스트(lst)의 길이로 행(row)과 열(col)의 개수를 파악하고 테이블 크기 설정
헤더 설정:
- s = [...]: 테이블의 맨 윗줄에 들어갈 제목들(등급분류번호, 게임명, 등급 등)을 리스트로 정의
- setHorizontalHeaderLabels(s): 정의한 제목들을 테이블 헤더로 적용
데이터 입력:
- 이중 for 문을 사용, 리스트에 있는 데이터를 하나씩 꺼내 QTableWidgetItem으로 변환한 뒤, 테이블의 각 셀(i행 j열)에 삽입
5. 데이터 분석: xmlParsing(self, txt, item)
API에서 받아온 XML 형식의 텍스트를 파이썬에서 다루기 쉬운 리스트(List) 형태로
변환하는 함수입니다.
et.fromstring(txt):
- 문자열 형태의 XML 데이터를 파싱 가능한 트리 구조(root)로 변환
데이터 추출:
- root.iter(tag=item): XML 내부에서 <item>이라는 태그를 가진 요소를 모두 찾기 (각 게임 정보 하나하나가 item)
내부 for 문:
- 각 <item> 안에 있는 하위 태그(게임명, 등급 등)의 텍스트 값(st.text)을 추출하여 임시 리스트(temp)에 담기
반환:
- 추출된 게임 정보들의 리스트(lst)를 리턴
6. 메인 실행 블록: if __name__ == '__main__':
프로그램의 진입점입니다.
- QApplication(sys.argv): PyQt6 어플리케이션 객체를 생성
- w = Window(): 위에서 정의한 Window 클래스의 인스턴스를 생성
- w.show(): 화면에 창을 표시
- sys.exit(app.exec()): 이벤트 루프를 실행하여 프로그램이 종료될 때까지 대기
마무리
REST API, 특히 클라이언트는 난이도가 쉽습니다.
하지만 XML, JSON 으로 들어오는 데이터를 Parsing하고 보기좋게 정리, 시각화하는데 많은 수고가 필요합니다.
특히 XML Parsing은 C++의 경우 외부 Lib.를 사용하지 않으면 손이 많이가는 부분인데 Python은 무려 내장모듈로 XML Parsing class들을 제공합니다.
귀도에게 감사한 마음입니다.🥹🙏
이상으로 설명을 마칩니다.





댓글
댓글 쓰기