본문 바로가기

BLOG/오픈소스 리뷰기

[오픈소스 리뷰기] 공공데이터포털(1) - 지역별 코로나19 감염현황 데이터 API 이용하기

오프소스 리뷰 : 슬기로운 오픈소스 사용법 리뷰해드립니다!
#1 공공데이터포털(1) - 지역별 코로나19 감염현황 데이터 API이용하기

 

600

공공데이터포털은 행정안전부에서 운영하는 공공데이터 통합제공 시스템으로, 대한민국 정부가 보유한 다양한 공공데이터를 누구나 편리하고 손쉽게 활용할 수 있습니다. 아이디만 만들면 누구나 손쉽게 API를 활용할 수 있으며, '무료' 로 사용가능하다는 점에서 가장 쉽게 접근할 수 있는 API 중 하나라고 할 수 있습니다.

이러한 공공데이터포털을 이용하는 절차는 아래와 같습니다.

 

  1. 공공데이터포털 회원가입
  2. 원하는 데이터 or API 검색
  3. API 사용신청 및 API key 확보
  4. 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를 활용하여 정부에서 제공하는 데이터를 손쉽게 수집할 수 있답니다!!