일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 해외주식
- 티스토리챌린지
- 코스피
- Python
- SK텔레콤
- Espressif
- homebridge
- Home Assistant
- matter
- ConnectedHomeIP
- Bestin
- MQTT
- 애플
- 나스닥
- 미국주식
- 배당
- 홈네트워크
- 오블완
- 월패드
- Apple
- esp32
- 매터
- RS-485
- 국내주식
- raspberry pi
- 현대통신
- 힐스테이트 광교산
- 파이썬
- 공모주
- cluster
- Today
- Total
YOGYUI
공공데이터포털::전기차 충전소 운영정보 조회 (REST API) 본문
공공데이터포털 Open API 목록을 훑어보던 중, 한국전력공사에서 제공하는 '전기차 충전소 운영정보'가 있어서 한번 구현해봤다
내년에 새 집 입주할 때 잔금 다 치르고 자금상황이 좀 안정화되면 전기차 한 대 뽑을까 계획중인데, 충전소 관련된 어플을 직접 만들어볼까 고민중~
1. 공공데이터포털 API 활용신청
데이터 타이틀은 "한국전력공사_전기차 충전소 운영정보", URL은 아래 링크 참고
https://www.data.go.kr/iim/api/selectAPIAcountView.do
API 활용신청(방법은 링크 참고)하고 인증키 획득
서비스 URL: http://openapi.kepco.co.kr/service/EvInfoServiceV2/getEvSearchList
요청 변수는 다음과 같다
특정 주소를 함께 입력할 수 있는 것이 특징이다
출력 결과는 다음과 같다
각 충전소별로 충전기 타입, 충전방식, 충전기 상태 등 다양한 정보를 얻어올 수 있다
스마트폰 네비게이션 앱에 충전소 관련 정보를 연동하기에 충분한 정보들을 제공하고 있다
2. 테스트 코드
간단하게 Python으로 테스트 코드를 짜보자
import requests
from urllib import parse
url = "http://openapi.kepco.co.kr/service/EvInfoServiceV2/getEvSearchList"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = parse.unquote(api_key_utf8)
params = {
"ServiceKey": api_key_decode,
"pageNo": 1,
"numOfRows": 5
}
response = requests.get(url, params=params)
테스트를 위해 5개만 조회해봤다
In [1]: print(response.text)
Out[1]:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<header>
<resultCode>00</resultCode>
<resultMsg>NORMAL SERVICE.</resultMsg>
</header>
<body>
<items>
<item>
<addr>서울특별시 중구 남대문로 92 1층 주차장</addr>
<chargeTp>2</chargeTp>
<cpId>811</cpId>
<cpNm>급속01</cpNm>
<cpStat>1</cpStat>
<cpTp>10</cpTp>
<csId>14</csId>
<csNm>서울직할</csNm>
<lat>37.565199</lat>
<longi>126.983339</longi>
<statUpdateDatetime>2021-06-29 23:05:00</statUpdateDatetime>
</item>
<item>
<addr>경상남도 남해군 남해읍 심천리 955-1 정문 우측</addr>
<chargeTp>2</chargeTp>
<cpId>464</cpId>
<cpNm>급속01</cpNm>
<cpStat>3</cpStat>
<cpTp>10</cpTp>
<csId>75</csId>
<csNm>남해지사</csNm>
<lat>34.851325596758144</lat>
<longi>127.8942036494668</longi>
<statUpdateDatetime>2021-06-29 23:02:07</statUpdateDatetime>
</item>
<item>
<addr>서울특별시 한강대로 23길 55 4.5F층 달주차장</addr>
<chargeTp>2</chargeTp>
<cpId>725</cpId>
<cpNm>급속06</cpNm>
<cpStat>1</cpStat>
<cpTp>10</cpTp>
<csId>120</csId>
<csNm>용산역 아이파크몰</csNm>
<lat>37.530561</lat>
<longi>126.965169</longi>
<statUpdateDatetime>2021-06-29 23:01:28</statUpdateDatetime>
</item>
<item>
<addr>경상남도 창원시 의창구 도계동 908 쎄씨헤어 앞</addr>
<chargeTp>1</chargeTp>
<cpId>229</cpId>
<cpNm>완속03</cpNm>
<cpStat>1</cpStat>
<cpTp>3</cpTp>
<csId>81</csId>
<csNm>의창구청</csNm>
<lat>35.254646</lat>
<longi>128.639178</longi>
<statUpdateDatetime>2021-06-29 23:02:59</statUpdateDatetime>
</item>
<item>
<addr>부산광역시 해운대구 우동 1413-4 지하주차장</addr>
<chargeTp>2</chargeTp>
<cpId>6891</cpId>
<cpNm>급속03</cpNm>
<cpStat>1</cpStat>
<cpTp>10</cpTp>
<csId>2605</csId>
<csNm>벡스코 제2전시장 지하주차장</csNm>
<lat>35.16556026063979</lat>
<longi>129.13480091423258</longi>
<statUpdateDatetime>2021-06-29 23:05:47</statUpdateDatetime>
</item>
</items>
<numOfRows>10</numOfRows>
<pageNo>1</pageNo>
<totalCount>2126</totalCount>
</body>
</response>
조회 가능한 충전소의 총 개수는 (totalCount) 2126개로 나온다
타 정보제공 사이트와는 차이가 큰 것 같긴 한데... 아무래도 민간 충전소는 조회가 되지 않고, 한국전력공사가 직영하는 충전소만 제공하는 것 같다
각 충전기의 주소명 및 위도, 경도로 정확한 주소를 알 수 있으며, 조회 시점의 상태(충전중인지, 수리중인지 여부) 및 충전방식(충전기 소켓) 등 다양한 정보를 얻을 수 있다
3. pandas DataFrame
import requests
from urllib import parse
import pandas as pd
from bs4 import BeautifulSoup
from datetime import datetime
url = "http://openapi.kepco.co.kr/service/EvInfoServiceV2/getEvSearchList"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = parse.unquote(api_key_utf8)
params = {
"ServiceKey": api_key_decode,
"pageNo": 1,
"numOfRows": 5000
}
response = requests.get(url, params=params)
xml = BeautifulSoup(response.text, "lxml")
items = xml.find("items")
item_list = []
for item in items:
item_dict = {
'addr': item.find("addr").text.strip(),
'chargetp': int(item.find("chargetp").text),
'cpid': int(item.find("cpid").text),
'cpnm': item.find("cpnm").text.strip(),
'cpstat': int(item.find("cpstat").text),
'cptp': int(item.find("cptp").text),
'csid': int(item.find("csid").text),
'csnm': item.find("csnm").text.strip(),
'lat': float(item.find("lat").text),
'longi': float(item.find("longi").text),
"statupdatedatetime": datetime.strptime(item.find("statupdatedatetime").text.strip(), '%Y-%m-%d %H:%M:%S')
}
item_list.append(item_dict)
df = pd.DataFrame(item_list)
In [2]: df.iloc[-1]
Out[2]:
addr 양정동 981 거제시보건소
chargetp 2
cpid 10489
cpnm 급속01
cpstat 1
cptp 1
csid 4311
csnm 거제시보건소
lat 33
longi 124
statupdatedatetime 2021-06-29 23:26:01
Name: 2125, dtype: object
총 2126개의 아이템이 데이터프레임으로 잘 생성된 것을 알 수 있다
API 문서를 보면 요청변수에 'addr'로 특정 주소를 함께 입력하면, 해당 주소의 근방 충전소만 조회해주는 것 처럼 적혀있어서 함수로 만들어봤다
import requests
from urllib import parse
import pandas as pd
from bs4 import BeautifulSoup
from datetime import datetime
def getEvCharger(addr: str) -> pd.DataFrame:
url = "http://openapi.kepco.co.kr/service/EvInfoServiceV2/getEvSearchList"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = parse.unquote(api_key_utf8)
params = {
"ServiceKey": api_key_decode,
"pageNo": 1,
"numOfRows": 5000,
"addr": addr
}
response = requests.get(url, params=params)
xml = BeautifulSoup(response.text, "lxml")
items = xml.find("items")
item_list = []
for item in items:
item_dict = {
'addr': item.find("addr").text.strip(),
'chargetp': int(item.find("chargetp").text),
'cpid': int(item.find("cpid").text),
'cpnm': item.find("cpnm").text.strip(),
'cpstat': int(item.find("cpstat").text),
'cptp': int(item.find("cptp").text),
'csid': int(item.find("csid").text),
'csnm': item.find("csnm").text.strip(),
'lat': float(item.find("lat").text),
'longi': float(item.find("longi").text),
"statupdatedatetime": datetime.strptime(item.find("statupdatedatetime").text.strip(), '%Y-%m-%d %H:%M:%S')
}
item_list.append(item_dict)
return pd.DataFrame(item_list)
In [3]: df = getEvCharger("서울")
In [4]: df.shape
Out[4]: (225, 11)
'서울' 키워드를 사용하면 총 225개 아이템이 조회된다
아이템들을 살펴보던 중 특이한 점을 발견했다
In [5]: df.iloc[102]
Out[5]:
addr 울산광역시 울주군 삼남면 교동리 1607-2 본관건물 고객지원팀 앞 2층 주차장 안
chargetp 2
cpid 452
cpnm 급속01
cpstat 1
cptp 10
csid 69
csnm 서울산지사(공용)
lat 35.5579
longi 129.113
statupdatedatetime 2021-06-29 23:38:09
Name: 102, dtype: object
충전소 명칭이 '서울산지사(공용)'인데 여기 '서울' 문자열이 있다고 해서 같이 조회가 된 것 같다 ㅋㅋㅋ
그냥 아이템들 문자열에 키워드가 포함되었는지 여부만 판단해서 리턴하는 것 같다...
4. 지도 시각화
충전소 위치를 지도에 그리기 위해 folium 라이브러리를 사용해보자
import folium
def convertGeoLoc(h, m, s):
return h + (m + s / 60) / 60
df = getEvCharger("서울")
fm = folium.Map(
location=[convertGeoLoc(37, 33, 6.89), convertGeoLoc(126, 59, 30.664)],
tiles='cartodbpositron',
zoom_start=12
)
for _, elem in df.iterrows():
folium.Circle(
location=(elem['lat'], elem['longi']),
tooltip=elem['csnm'],
radius=100,
color="#ff0000"
).add_to(fm)
fm.save('result.html')
5. 내 주변 충전소 찾기
네비게이션 등의 어플리케이션에 활용하기 위해서는 나의 현재 위치를 기반으로 특정 반경 내에 있는 충전소들만 조회하는 기능이 구현되어야 한다
지구와 같은 구면 좌표계에서 두 지점의 위도와 경도가 주어졌을 때, 두 지점간의 거리는 Haversine(하버사인) 공식을 활용하면 된다
https://en.wikipedia.org/wiki/Haversine_formula
공식이 복잡하지는 않지만, 직접 구현하기 귀찮으면 파이썬의 haversine 라이브러리를 활용하면 된다 (파이썬의 위대함)
pip install haversine
자세한 사용법은 PyPI 공식 문서 참고
https://pypi.org/project/haversine/
다음과 같이 조회되는 충전소들과의 거리도 함께 계산하는 함수를 만들어주자
import requests
from urllib import parse
import pandas as pd
from bs4 import BeautifulSoup
from datetime import datetime
from haversine import haversine
def getEvCharger2(cur_loc_latitude: float, cur_loc_longitude: float) -> pd.DataFrame:
url = "http://openapi.kepco.co.kr/service/EvInfoServiceV2/getEvSearchList"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = parse.unquote(api_key_utf8)
params = {
"ServiceKey": api_key_decode,
"pageNo": 1,
"numOfRows": 5000
}
response = requests.get(url, params=params)
xml = BeautifulSoup(response.text, "lxml")
items = xml.find("items")
item_list = []
for item in items:
lat = float(item.find("lat").text)
longi = float(item.find("longi").text)
item_dict = {
'addr': item.find("addr").text.strip(),
'chargetp': int(item.find("chargetp").text),
'cpid': int(item.find("cpid").text),
'cpnm': item.find("cpnm").text.strip(),
'cpstat': int(item.find("cpstat").text),
'cptp': int(item.find("cptp").text),
'csid': int(item.find("csid").text),
'csnm': item.find("csnm").text.strip(),
'lat': lat,
'longi': longi,
'statupdatedatetime': datetime.strptime(item.find("statupdatedatetime").text.strip(), '%Y-%m-%d %H:%M:%S'),
'distance': haversine((lat, longi), (cur_loc_latitude, cur_loc_longitude))
}
item_list.append(item_dict)
return pd.DataFrame(item_list)
테스트삼아, 지금 살고 있는 주소 (광교아이파크)를 중심으로 충전소들의 거리를 구해보자
(좌표 정보는 구글 지도에서 쉽게 구할 수 있다)
df = getEvCharger2(37.274133928822884, 127.06114948517133)
In [6]: df.iloc[0]
Out[6]:
addr 서울특별시 중구 남대문로 92 1층 주차장
chargetp 2
cpid 811
cpnm 급속01
cpstat 1
cptp 10
csid 14
csnm 서울직할
distance 33.0864
lat 37.5652
longi 126.983
statupdatedatetime 2021-06-30 00:15:00
Name: 0, dtype: object
거리(distance)는 33.0864 km로 계산되었다
구글 지도에서 측정한 거리는 33.24 km로, 유사한 값인 것을 알 수 있다
다음과 같이 반경 10km 내에 있는 충전소를 필터링할 수 있다
df_filter = df[df['distance'] <= 10.0]
In [7]: df_filter = df[df['distance'] <= 10.0]
Out[7]: (46, 12)
총 46군데가 필터링되었다
해당 지점들을 마찬가지로 지도에 그려보자
fm = folium.Map(
location=[37.274133928822884, 127.06114948517133],
tiles='cartodbpositron',
zoom_start=15
)
for _, elem in df_filter.iterrows():
folium.Circle(
location=(elem['lat'], elem['longi']),
tooltip=elem['csnm'],
radius=100,
color="#ff0000"
).add_to(fm)
fm.save('result.html')
동탄이랑 성남시에 있는 충전소까지 같이 조회가 된다 ㅎㅎ
여기에 각 충전소에 지금 충전기의 상태 및 충전기 종류 등을 같이 표시할 수 있으면 상당히 유용한 서비스를 제공할 수 있다
(이미 스마트폰 어플 시장에는 포화되어 있는 서비스인 것 같긴 하지만...^^;;)
전기차를 사는 그날까지!
열심히 돈을 모아야겠다 (기승전Money...)
목표는 포르쉐 마칸!
끝~!
'Data Analysis > Data Engineering' 카테고리의 다른 글
금융감독원::DART 공시문서 js 렌더링된 HTML 가져오기 (4) | 2021.09.24 |
---|---|
금융감독원::OPENDART 전자공시 Open API 사용하기 (17) | 2021.09.18 |
공공데이터포털::공휴일 데이터 조회 (REST API) (10) | 2021.04.03 |
Python::folium - 빅데이터분석기사 필기시험 고사장 위치 지도시각화 (0) | 2021.02.26 |
공공데이터포털::코로나19 감염현황 데이터 조회 (REST API) (0) | 2021.02.22 |