오프소스 리뷰 : 슬기로운 오픈소스 사용법 리뷰해드립니다!
#1 공공데이터포털(1) - 지역별 코로나19 감염현황 데이터 API이용하기
공공데이터포털은 행정안전부에서 운영하는 공공데이터 통합제공 시스템으로, 대한민국 정부가 보유한 다양한 공공데이터를 누구나 편리하고 손쉽게 활용할 수 있습니다. 아이디만 만들면 누구나 손쉽게 API를 활용할 수 있으며, '무료' 로 사용가능하다는 점에서 가장 쉽게 접근할 수 있는 API 중 하나라고 할 수 있습니다.
이러한 공공데이터포털을 이용하는 절차는 아래와 같습니다.
- 공공데이터포털 회원가입
- 원하는 데이터 or API 검색
- API 사용신청 및 API key 확보
- API 호출 및 사용
우선 원하는 데이터를 활용하기전 가장 먼저 공공데이터포털에서 회원가입을 완료해주세요!
공공데이터 포털
국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase
www.data.go.kr
이와 관련하여 가장 먼저 근2년간의 가장 이슈였던, 지역별 코로나19 감염현황 데이터를 API를 통해 확인해보겠습니다.
위와 같이 '코로나19 감염' 을 검색하게 되면 다음과 같은 검색결과를 확인할 수 있습니다.
우리는 이들 중 파일데이터가 아닌 오픈 API를 활용할 건데요.
이 중 지역별 감염자 통계와 현황을 확인할 수 있는 '공공데이터활용지원센터_보건복지부 코로나19 시·도발생 현황' 에서 제공하는 데이터를 API를 통해 수집하겠습니다.
'공공데이터활용지원센터_보건복지부 코로나19 시·도발생 현황' 클릭 후 오른쪽에 있는 '활용신청' 버튼을 클릭하여 활용목적을 작성한 뒤 API 활용을 위한 key를 발급받아야 합니다!
대부분의 경우 신청후 1~2시간 내에 승인이 완료되며 이후에는 key를 활용하여 API호출이 가능합니다.
'마이페이지'-'오픈API'-'계발계정' 에 들어가면 아래와 같이 활용신청한 API가 승인된 것을 확인할 수 있습니다.
이후 신청한 서비스를 클릭하게 되면 위와 같이 서비스를 이용할 수 있는 key가 생성됩니다!
다시 활용 신청한 서비스인 '공공데이터활용지원센터_보건복지부 코로나19 시·도발생 현황' 의 상세 페이지를 들어가보면 아래와 같이 데이터를 제공하는 API정보를 확인할 수 있습니다.
지역별 코로나19 감염현황의 경우 데이터는 XML 형식으로 제공하는데,
참고로 XML 형식이란 다음과 같이 트리구조로 데이터를 전달하는 것을 말합니다.
<?xml version="1.0" encoding="UTF-8"?>
<response>
<header>
<resultCode>00</resultCode>
<resultMsg>NORMAL SERVICE.</resultMsg>
</header>
<body>
<items>
<item>
<createDt>2020-04-10 11:17:34.589</createDt>
<deathCnt>0</deathCnt>
<defCnt>352</defCnt>
<gubun>검역</gubun>
<gubunCn>隔離區</gubunCn>
<gubunEn>Lazaretto</gubunEn>
<incDec>4</incDec>
<isolClearCnt>3</isolClearCnt>
<isolIngCnt>349</isolIngCnt>
<localOccCnt>0</localOccCnt>
<overFlowCnt>4</overFlowCnt>
<qurRate>-</qurRate>
<seq>1014</seq>
<stdDay>2020년 04월 10일 00시</stdDay>
<updateDt />
</item>
<item>
<createDt>2020-04-10 11:17:34.589</createDt>
<deathCnt>0</deathCnt>
<defCnt>12</defCnt>
<gubun>제주</gubun>
<gubunCn>济州</gubunCn>
<gubunEn>Jeju</gubunEn>
<incDec>0</incDec>
<isolClearCnt>4</isolClearCnt>
<isolIngCnt>8</isolIngCnt>
<localOccCnt>0</localOccCnt>
<overFlowCnt>0</overFlowCnt>
<qurRate>1.79</qurRate>
<seq>1013</seq>
<stdDay>2020년 04월 10일 00시</stdDay>
<updateDt />
</item>
</items>
<numOfRows>10</numOfRows>
<pageNo>1</pageNo>
<totalCount>38</totalCount>
</body>
</response>
위와 같은 XML 구조에서 <item>으로 시작하여 </item>으로 끝나는 부분들을 살펴보면,
우리가 수집하려는 데이터를 가지고 있는 것을 알 수 있으며 <totalCount>에서 API에서 제공하는 전체 <item>의 개수를 알 수 있답니다.
다음으로는 요청변수(Request Parameter)에 대해 알아보겠습니다.
요청변수란 데이터를 활용하기 위해 서버에 호출하는 파라미터로, 요청변수에 따라 API에서 제공하는 데이터가 달라지게 되는데요.
위의 경우 필수적인 서비스키를 제외하면 페이지번호, 한 페이지 결과 수, 데이터 생성일 시작/종료범위는 선택적으로 추가할 수 있습니다.
출력결과(Response Element)는 API를 통해 결과값으로 받게 되는 데이터로 필요한 데이터를 선택적으로 확인할 수 있습니다.
그럼 이제, API를 활용하여 데이터를 수집해보겠습니다! 우선 필수 라이브러리를 불러와주세요.
from urllib.request import Request, urlopen
from urllib.parse import urlencode, quote_plus
from xml.etree import ElementTree
import pandas as pd
다음으로는 서비스를 불러오기 위한 서비스URL과 인증key를 변수에 저장합니다.
서비스URL은 서비스 상세페이지에서, 인증key는 마이페이지의 승인목록에서 신청한 서비스를 클릭하면 확인할 수 있습니다.
일반인증키(Encoding)이 아닌 아래의 일반인증키(Decoding)을 입력해야 데이터를 불러올 수 있는 경우도 있으므로 오류가 발생할 경우 Decoding된 인증키를 입력하세요.
url = 'http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19SidoInfStateJson'
service_key = '서비스키를 입력하세요'
다음으로는 요청변수를 params 라는 변수에 저장합니다.
항목명은 반드시 영문으로 입력해야하며, 필수 입력변수인 ServiceKey는 반드시! 입력해야합니다.
# 국내 코로나19 확진자가 급증한 6월부터 8월까지의 데이터를 수집해보겠습니다.
params = '?' + \
urlencode({
quote_plus('ServiceKey') : service_key,
quote_plus('pageNo') : '0',
# quote_plus('numOfRows') : '20',
quote_plus('startCreateDt') : '20210601',
quote_plus('endCreateDt') : '20210831',
})
이제 서비스URL과 요청변수를 API에 전달하여 XML 형식으로 데이터를 불러옵니다.
# url과 params를 결했을 때 아래 주소를 확인해보면 우리가 원하는 결과값을 얻을 수 있는 것을 확인할 수 있습니다.
url+params
request = Request(url + params) # url과 요청파라미터를 결합하여 서버에 데이터를 요청합니다.
response_body = urlopen(request).read() # response 를 text 형태로 읽어옵니다.
root = ElementTree.fromstring(response_body) # text를 XML 형태로 변환합니다.
조금 더 다루기 쉬운 형태인 데이터프레임으로 결과값을 저장해봅시다.
df = pd.DataFrame()
for item in root.iter('item'): # XML 구조에 있는 <item>에서 필요한 정보들만 수집합니다.
item_dict = {}
item_dict['기준일시'] = item.find('stdDay').text
item_dict['시도명'] = item.find('gubun').text
item_dict['확진자'] = item.find('defCnt').text
item_dict['전일대비증감'] = item.find('incDec').text
item_dict['해외유입'] = item.find('overFlowCnt').text
item_dict['지역발생'] = item.find('localOccCnt').text
item_dict['사망자수'] = item.find('deathCnt').text
df = df.append(item_dict, ignore_index = True)
df
기준일시 사망자수 시도명 전일대비증감 지역발생 해외유입 확진자
0 2021년 08월 31일 00시 13 검역 13 0 13 5836
1 2021년 08월 31일 00시 2 제주 9 8 1 2602
2 2021년 08월 31일 00시 31 경남 56 56 0 9980
3 2021년 08월 31일 00시 88 경북 27 27 0 7100
4 2021년 08월 31일 00시 19 전남 14 13 1 2600
... ... ... ... ... ... ... ...
1743 2021년 06월 01일 00시 61 인천 17 16 1 6215
1744 2021년 06월 01일 00시 221 대구 42 39 3 9958
1745 2021년 06월 01일 00시 124 부산 28 28 0 5696
1746 2021년 06월 01일 00시 491 서울 146 145 1 44062
1747 2021년 06월 01일 00시 1963 합계 458 448 10 140797
1748 rows × 7 columns
# 간단한 전처리 작업을 합니다.
df['기준일시'] = pd.to_datetime(df['기준일시'], format = '%Y년 %m월 %d일 %H시')
df.sort_values(['기준일시'], inplace=True)
df.reset_index(drop=True, inplace=True)
df.head(19)
기준일시 사망자수 시도명 전일대비증감 지역발생 해외유입 확진자
0 2021-06-01 1963 합계 458 448 10 140797
1 2021-06-01 4 검역 4 0 4 3848
2 2021-06-01 1 제주 12 12 0 1042
3 2021-06-01 19 경남 8 8 0 4707
4 2021-06-01 85 경북 9 9 0 4701
5 2021-06-01 15 전남 5 5 0 1468
6 2021-06-01 58 전북 6 6 0 2231
7 2021-06-01 39 충남 12 11 1 3550
8 2021-06-01 68 충북 11 11 0 2954
9 2021-06-01 491 서울 146 145 1 44062
10 2021-06-01 639 경기 116 116 0 39197
11 2021-06-01 124 부산 28 28 0 5696
12 2021-06-01 221 대구 42 39 3 9958
13 2021-06-01 61 인천 17 16 1 6215
14 2021-06-01 51 강원 13 13 0 3198
15 2021-06-01 24 대전 19 19 0 2097
16 2021-06-01 40 울산 2 2 0 2580
17 2021-06-01 1 세종 3 3 0 483
18 2021-06-01 22 광주 5 5 0 2810
# 다음과 같이 groupby 기능을 이용해 기준일시와 시도명을 기준으로 데이터를 확인할 수 있습니다.
df.groupby(['기준일시','시도명'])['확진자','전일대비증감','지역발생','해외유입','사망자수'].sum()
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:2: FutureWarning:
Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead.
확진자 전일대비증감 지역발생 해외유입 사망자수
기준일시 시도명
2021-06-01 강원 3198 13 13 0 51
검역 3848 4 0 4 4
경기 39197 116 116 0 639
경남 4707 8 8 0 19
경북 4701 9 9 0 85
... ... ... ... ... ... ...
2021-08-31 전북 3588 26 26 0 60
제주 2602 9 8 1 2
충남 6937 38 37 1 55
충북 5152 15 15 0 73
합계 251416 1370 1331 39 2285
1748 rows × 5 columns
이제 API를 통해 수집한 데이터를 아래와 같이 간단하게 시각화 할 수 있습니다.
import plotly.express as px
import plotly.graph_objects as go
df_korea = df[df['시도명']=='합계']
fig = px.bar(df_korea, x='기준일시', y='전일대비증감', title='Covid19 in Korea')
fig.show()
fig = px.line(df_korea, x='기준일시', y='확진자')
fig.show()
df_sido = df[df['시도명']!='합계']
fig = px.line(df_sido, x='기준일시', y='전일대비증감',
color='시도명', line_group='시도명', hover_name='시도명')
fig.show()
sorted_df = df[(df.기준일시 == df.기준일시.max()) & (df.시도명 != '검역') & (df.시도명 != '합계')]
max_date = sorted_df.기준일시.iloc[0]
fig = px.bar(
sorted_df,
x=sorted_df.시도명,
y=sorted_df.확진자,
title='시.도',
text='확진자',
color='시도명',
)
fig.update_layout(
title=dict(
text=f"<b>국내 시.도 확진자 발생 현황</b><br>집계일자: {max_date}",
x=0.5,
),
xaxis_title='시.도',
yaxis_title='확진자 수',
bargap=0.3,
)
fig.show()
df_seoul = df[df['시도명'] == '서울']
fig = go.Figure([
go.Bar(x=df_seoul['기준일시'], y=df_seoul['해외유입'], name='해외유입', text=df_seoul['해외유입'], marker_color='red'),
go.Bar(x=df_seoul['기준일시'], y=df_seoul['지역발생'], name='지역발생', text=df_seoul['지역발생'], marker_color='blue'),
])
fig.update_layout(barmode='stack')
fig.show()
이렇게 오늘은 지역별 코로나19 감염현황을 API를 활용해 데이터를 수집해보는 방법을 알려드렸는데 어떠셨나요? :-)
이제 위와 같은 방식을 활용하면 공공데이터포털에서 제공하는 API를 활용하여 정부에서 제공하는 데이터를 손쉽게 수집할 수 있답니다!!
'BLOG > 오픈소스 리뷰기' 카테고리의 다른 글
[오픈소스 리뷰기] 번역 API 이용하기(2) - 네이버파파고, 카카오 번역 (0) | 2021.11.09 |
---|---|
[오픈소스 리뷰기] 번역 API 이용하기(1) - Google 번역 (3) | 2021.11.08 |
[오픈소스 리뷰기] YouTube API 이용하기(2) - API 키 활용하기 (2) | 2021.11.04 |
[오픈소스 리뷰기] YouTube API 이용하기(1) - API 키 발급하기 (0) | 2021.11.03 |
[오픈소스 리뷰기] 공공데이터포털(2) - 전기차 충전소 정보 데이터 API 이용하기 (0) | 2021.11.01 |