공공데이터 API 사용하기
- 국토교통부_버스정류소정보의 데이터를 사용하여 좌표기반 근접 정류소 목록을 조회한다.
- 목적 : 공공주택 근처의 버스정류장은 몇개인지 구하기 위해 사용하였다.
- 일일 조회 트래픽이 많이 필요할 것 같아서 운영계정으로 신청했다.
- 공공주택근처에 위치한 정류장의 개수를 구한다.
요청변수
항목명(한굴) |
항목명(영문) |
항목크기 |
항목구분 |
항목설명 |
서비스키 |
serviceKey |
- |
필수 |
공공데이터 신청시 제공 받는 인증키 |
GPS Y좌표 |
gpsLati |
20 |
필수 |
WGS84위도 좌표 |
GPS X좌표 |
gpsLong |
20 |
필수 |
WGS84경도 좌표 |
출력결과
- 형식 : XML
- 결과
- 정류소의 Y좌표
- 정류소의 X좌표
- 정류소 ID
- 정류소명
- 도시코드
- 결과 예시
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<header>
<resultCode>00</resultCode>
<resultMsg>NORMAL SERVICE.</resultMsg>
</header>
<body>
<items>
<item>
<citycode>도시코드</citycode>
<gpslati>위도(Y)</gpslati>
<gpslong>경도(X)</gpslong>
<nodeid>정류소 ID</nodeid>
<nodenm>정류소 명</nodenm>
<nodeno>정류소 번호</nodeno>
</item>
</items>
<numOfRows>10</numOfRows>
<pageNo>1</pageNo>
<totalCount>2</totalCount>
</body>
</response>
데이터 사용
01. 전처리
- 전처리 : LH주택공사에서 제공한 공공주택 도로명주소 데이터 사용
- 도로명주소가 담긴 API데이터를 수집하였다.
- 표준데이터셋 점검 서비스를 사용하여 변환하였고, 안나오는 데이터는 구글
Geocode Awesome Table
을 이용했다.
{도로명주소 : {'위도' : 36.3, '경도' : 127.3 }
의 형식을 지닌 딕셔너리로 변환 lhdict
02. API 호출
from urllib.request import Request
from urllib.request import urlopen
from urllib.parse import urlencode
from urllib.parse import quote_plus
import json
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import Element, dump, ElementTree
import pandas as pd
import time
from tqdm import tqdm
- 호출코드
- 버스정류장 정보를 조회할 필요없이 내가 필요한 정보는 전체 개수이다.
- xml의 body 태그 아래에는
<totalCount>
가 있는데 전체 개수를 의미하기 때문에 이것을 파싱하기로 했다.
idx = 0
errs =[]
result = dict()
for lh in tqdm(lhdict):
url = 'http://openapi.tago.go.kr/openapi/service/BusSttnInfoInqireService/getCrdntPrxmtSttnList'
queryParams = '?' + urlencode({ quote_plus('ServiceKey') : '제공된 ServiceKey',
quote_plus('gpsLati') :str(lhdict[lh]['위도']), # 위도
quote_plus('gpsLong') : str(lhdict[lh]['경도']) }) # 경도
request = Request(url + queryParams)
request.get_method = lambda: 'GET'
response_body = urlopen(request).read()
resStr = response_body.decode('utf-8')
xmldata = ET.fromstring(resStr)
iterList = xmldata.findall('body')
for ite in iterList:
cnt = ite.find('totalCount').text
result[str(idx)] = {'rnAdres':lh, 'bus_cnt': cnt}
idx +=1
- 이러면 result 딕셔너리를 반환해준다.
- API 서버 상태로 인해 반도 못가서 자꾸 오류가 발생했다 ㅠㅠ
- 그래서 예외처리하는 코드 + sleep을 추가했다.
from time import sleep
idx = 0
errs =[]
result = dict()
for lh in tqdm(lhdict):
try:
url = 'http://openapi.tago.go.kr/openapi/service/BusSttnInfoInqireService/getCrdntPrxmtSttnList'
queryParams = '?' + urlencode({ quote_plus('ServiceKey') : '제공된 ServiceKey',
quote_plus('gpsLati') :str(lhdict[lh]['위도']), # 위도
quote_plus('gpsLong') : str(lhdict[lh]['경도']) }) # 경도
sleep(2) # 로딩을 위해 2초 휴식
request = Request(url + queryParams)
request.get_method = lambda: 'GET'
response_body = urlopen(request).read()
resStr = response_body.decode('utf-8')
xmldata = ET.fromstring(resStr)
iterList = xmldata.findall('body')
for ite in iterList:
cnt = ite.find('totalCount').text
result[str(idx)] = {'rnAdres':lh, 'bus_cnt': cnt}
idx +=1
except: # 예외처리
# 에러가 나면 해당 주소를 출력하고 errs 리스트에 추가
errs.append(lh)
print(idx,' : ',lh)
idx+=1
사용 후기
- 굉장히 오래걸린다… 약 15시간정도?
- csv형식의 전국 버스정류장 위도, 경도가 담긴 데이터가 있다면 그걸 쓰는게 훨씬 빠를 것 같다.
- 전국버스정류소 위치를 csv형식으로 국도교통부에서 제공하고있기 때문에 이것을 사용해볼 예정이다.
- 국토교통부_전국 버스정류장 위치정보
- 버스정보시스템(BIS)이 구축된 지자체 중 국가대중교통정보센터(TAGO)와 연계된 115개 지자체에 대한 버스정류장 위치정보 데이터입니다.