Skip to content

Commit 305193f

Browse files
committed
API 요청 테이블 추가
1 parent ed4d967 commit 305193f

4 files changed

Lines changed: 151 additions & 1 deletion

File tree

consts.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@
101101
IVD_BASEMAP="IVD_BASEMAP",
102102
)
103103

104+
CONST_NETWORK_APISTRMAP = {
105+
"개별공시지가속성조회":"getIndvdLandPriceAttr",
106+
"개별주택가격정보조회":"getIndvdHousingPriceAttr",
107+
"토지소유정보속성조회":"getPossessionAttr",
108+
"토지이동이력속성조회":"getLandMoveAttr",
109+
}
110+
104111
CONST_TABLEKEY_STRMAP = DotMap(
105112
STDMT="기준월",
106113
PNU="토지코드",

gui.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import time
33

44
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QFileDialog, QWidget, QSplitter, QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox, QDialog
5-
from PyQt5.QtGui import QPixmap
65
from PyQt5.QtCore import QSettings, QPoint, QSize, QCoreApplication
76

87
from consts import SAVE_KEY_MAP, ENUM_SAVE_COLUMN, ENUM_SAVE_ROW, ERRORCODE_LOAD, ENUM_TABLEVIEW_INITMODE, ENUM_TABLEVIEW_HVFUNC
@@ -16,6 +15,7 @@
1615
from network import get_mapinfo_from_pnu
1716
from clipboard import clipboard_copy_csvte_info, clipboard_paste_csvte_info
1817
from theme import apply_theme
18+
from gui_apitable import APIInfoLayout
1919

2020
TITLE_NAME = "CSV Table Editor"
2121
TOP_NAME = "mgj"
@@ -174,6 +174,11 @@ def init_content(self):
174174
self.mapinfo_table = mapinfo_table
175175
info_layout.addWidget(mapinfo_table)
176176

177+
# API Type Selection
178+
api_info_layout = APIInfoLayout(self)
179+
self.api_info_layout = api_info_layout
180+
info_layout.addLayout(api_info_layout)
181+
177182
# 5. buttons_layout
178183
buttons_layout = QVBoxLayout()
179184
layout_right.addLayout(buttons_layout)
@@ -234,6 +239,7 @@ def load(self, src, load_mode):
234239
self.info_table.set_info_text("왼쪽의 테이블을 눌러 자세히 보기!")
235240
self.search_widget.set_info_text("왼쪽의 버튼을 눌러 필터를 추가!")
236241
self.mapinfo_table.clear_table()
242+
self.api_info_layout.clear()
237243
self.export_button.setEnabled(True)
238244
self.openimg_button.setEnabled(True)
239245
else:
@@ -345,6 +351,10 @@ def refresh_tables(self, row):
345351
epsglist = e
346352
self.mapinfo_table.set_mapinfo(mapinfolist, epsglist)
347353

354+
# 3. api_info_layout
355+
if pnu:
356+
self.api_info_layout.set_pnu(pnu)
357+
348358
def on_value_edit_callback(self, row, col, value):
349359
target_index = row + (self.table_widget.get_page() - 1) * \
350360
self.table_widget.page_size

gui_apitable.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
from PyQt5.QtWidgets import QVBoxLayout, QTableWidget, QLabel, QComboBox, QTableWidgetItem, QHeaderView, QAbstractItemView
2+
from PyQt5.QtCore import Qt
3+
4+
from network import get_api_data
5+
from consts import SAVE_KEY_MAP, CONST_NETWORK_APISTRMAP
6+
7+
class APITable(QTableWidget):
8+
def __init__(self):
9+
super().__init__()
10+
self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
11+
self.horizontalHeader().setHidden(True)
12+
self.verticalHeader().setHidden(True)
13+
self.setEditTriggers(QAbstractItemView.NoEditTriggers)
14+
self.setSelectionMode(QAbstractItemView.SingleSelection)
15+
self.clear()
16+
17+
def clear_table(self):
18+
self.setRowCount(0)
19+
self.setColumnCount(0)
20+
21+
def set_data(self, data):
22+
self.clear_table()
23+
self.setRowCount(len(data))
24+
self.setColumnCount(2)
25+
for row, (key, value) in enumerate(data.items()):
26+
self.setItem(row, 0, QTableWidgetItem(str(key)))
27+
self.setItem(row, 1, QTableWidgetItem(str(value)))
28+
29+
30+
class APIInfoLayout(QVBoxLayout):
31+
def __init__(self, parent):
32+
self.pnu = ""
33+
self.message_label = QLabel("", alignment=Qt.AlignCenter)
34+
self.message_label.setMinimumHeight(70)
35+
36+
super().__init__()
37+
self.parent = parent
38+
api_type_label = QLabel("API 요청 설정:")
39+
self.addWidget(api_type_label)
40+
41+
self.api_type_combo = QComboBox()
42+
self.api_type_combo.addItems(CONST_NETWORK_APISTRMAP.keys())
43+
self.api_type_combo.currentTextChanged.connect(
44+
self.on_combobox_changed)
45+
self.addWidget(self.api_type_combo)
46+
47+
self.api_table = APITable()
48+
self.addWidget(self.api_table, stretch=1)
49+
50+
self.addWidget(self.message_label)
51+
52+
self.refresh()
53+
54+
def set_pnu(self, pnu):
55+
self.pnu = pnu
56+
57+
self.refresh()
58+
59+
def clear(self):
60+
self.pnu = ""
61+
62+
self.refresh()
63+
64+
def refresh(self):
65+
self.message_label.hide()
66+
self.api_table.hide()
67+
68+
# 1. check api
69+
apikey = self.parent.settings.value(SAVE_KEY_MAP.OPTION_APIKEY, "")
70+
if not apikey:
71+
self.show_message("API 키가 설정되지 않았습니다.")
72+
return
73+
74+
# 2. check selected
75+
if not self.pnu:
76+
self.show_message("PNU가 포함된 행을 눌러주세요.")
77+
return
78+
79+
# 3. connect, and check success
80+
api_type = CONST_NETWORK_APISTRMAP.get(self.api_type_combo.currentText(), "")
81+
if not api_type:
82+
return
83+
84+
data = get_api_data(apikey, self.pnu, api_type)
85+
if not data:
86+
self.show_message("데이터를 가져오는데 실패했습니다.\n해당하는 데이터가 없거나 apikey가 잘못되었을 수 있습니다.")
87+
return
88+
89+
self.api_table.set_data(data)
90+
self.api_table.show()
91+
92+
def show_message(self, message):
93+
self.message_label.setText(message)
94+
self.message_label.show()
95+
96+
def on_combobox_changed(self, __text):
97+
self.refresh()

network.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import requests
22
from urllib.parse import quote
3+
import xml.etree.ElementTree as ET
34

45
URL_ADDR = "https://api.vworld.kr/req/address"
56
URL_PNU = "https://api.vworld.kr/req/data?service=data&request=GetFeature&attrFilter=pnu:=:{pnu}&data=LP_PA_CBND_BUBUN&key={apikey}"
@@ -94,6 +95,41 @@ def get_map_img(api_key, epsg, zoom=18, width=1024, height=1024, basemap="PHOTO_
9495
return not ("error" in res.text), res.content
9596

9697

98+
def get_api_data(apikey, pnu, api_type):
99+
base_url = "http://api.vworld.kr/ned/data/"
100+
url = f"{base_url}{api_type}"
101+
params = {
102+
"key": apikey,
103+
"pnu": pnu,
104+
"format": "xml",
105+
"numOfRows": "1000",
106+
"pageNo": "1"
107+
}
108+
109+
try:
110+
response = requests.get(url, params=params)
111+
if response.status_code != 200:
112+
print(f"비정상 상태 코드 수신: {response.status_code}")
113+
return {}
114+
115+
response_body = response.content
116+
root = ET.fromstring(response_body)
117+
total_count = int(root.findtext('.//totalCount'))
118+
fields = root.findall('.//field')
119+
120+
if total_count == 0 or len(fields) < total_count:
121+
print("응답에서 충분한 필드를 찾을 수 없거나 총 개수가 올바르지 않습니다")
122+
return {}
123+
124+
field = fields[total_count - 1]
125+
data = {elem.tag: elem.text for elem in field}
126+
return data
127+
128+
except requests.exceptions.RequestException as e:
129+
print(f"오류가 발생했습니다: {e}")
130+
return {}
131+
132+
97133
if __name__ == '__main__':
98134
apikey = ""
99135
pnu = "4377034032102800000"

0 commit comments

Comments
 (0)