개발고생일지/파이썬

공공데이터 포털에서 Open API의 데이터 json으로 파싱하기

Fartist 2023. 3. 10. 20:00
- 목차
1. 공공데이터 포털에서 xml로 파싱 할 때 발생한 문제
2. 공공데이터 포털에서 Open API의 데이터 json으로 파싱 하기
갈무리

[그림 1] 썸네일


1.  공공데이터 포털에서 xml로 파싱 할 때 발생한 문제

 파이썬의 웹 크롤링 교재를 보면 공공데이터 포털에서 Open API의 데이터를 불러오는 실습이 있습니다. 실습 내용을 살펴보면 교재에서 제시하는 공공데이터 포털의 화면의 구성과 절차가 현재와 많이 다릅니다. 하지만 불러오는 데이터의 형식이 그대로라면 그 과정의 변화는 그렇게 문제가 되지 않습니다.

 하지만 아쉽게도  Open API에서 제공하는 데이터의 양식도 조금 바뀌었습니다. 다음은 '한국부동산원_부동산 거래 현황 통계 조회 서비스'의 Open API에서 '부동산 거래 건수 조회' API에서 받아온 xml 타입의 데이터입니다.

 데이터의 '요청변수'의 값은 다음과 같습니다.

조사일자(GTE) : 201301
조사일자(LTE) : 201312
지역코드 : 11000
거래유형 : 01
<results>
<currentcount>12</currentcount>
<data>
	<item>
    	<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201308<col name="ALL_CNT"/>12902
    </item>
    <item>
    	<col name="RESEARCH_DATE"/>201309<col name="ALL_CNT"/>14378<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울
    </item>
    <item>
    	<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201301<col name="ALL_CNT"/>9917<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0
    </item>
    <item>
    	<col name="ALL_CNT"/>20262<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201310
    </item>
    <item>
    	<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201311<col name="ALL_CNT"/>19293
    </item>
    <item>
    	<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201302<col name="ALL_CNT"/>10028<col name="DEAL_OBJ"/>01
    </item>
    <item>
    	<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201304<col name="ALL_CNT"/>17911<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0
    </item>
    <item>
    	<col name="ALL_CNT"/>19902<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201305
    </item>
    <item>
    	<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201312<col name="ALL_CNT"/>21605
    </item>
    <item>
    	<col name="ALL_CNT"/>15322<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201303
    </item>
    <item>
    	<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201306<col name="ALL_CNT"/>25636<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0<col name="REGION_CD"/>11000
    </item>
    <item>
    	<col name="REGION_CD"/>11000<col name="REGION_NM"/>서울<col name="RESEARCH_DATE"/>201307<col name="ALL_CNT"/>13051<col name="DEAL_OBJ"/>01<col name="LEVEL_NO"/>0
    </item>
</data>
<matchcount>12</matchcount>
<page>1</page>
<perpage>12</perpage>
<totalcount>411531</totalcount>
</results>

[코드 1]  '한국부동산원_부동산 거래 통계 조회 서비스_부동산 거래 건수 조회_xml 타입의 데이터 

 다음은 교재에서 제공하는 xml 타입 데이터의 예시 코드입니다.

<?xml version="1.0" encoding="UTF=8" standalone="yes"?>
<response>
	<header>
    	<resultcode>
        	00
        </resultcode>
        <resultsmg>
        	NORMAL SERVICE.
        </resultsmg>
    </header>
    <body>
    	<itme>
        	<regioncd>
            	11000
            </regioncd>
            <regionnm>
            	서울
            </regionnm>
            <rsrow>
            	201301,9917|201302,10028|201303,15322|201304,17911|201305,19902|201306,25636|201307,13051|201308,12902|201309,14378|201310,20262|201311,19293|201312,21605
            </rsrow>
        </item>
    </body>
</response>

[코드 2]  교재에서 제공하는 '한국부동산원_부동산 거래 통계 조회 서비스_부동산 거래 건수 조회_xml 타입의 데이터 

 교재에서 제공하는 코드에서는 <body> 태그 안에 가공이 안 된 데이터의 형태로 <rsrow> 태그로 감싸져 있었습니다. 하지만 실제로 공공데이터 포털에서 내려받은 xml 데이터는 각각의 데이터가 <item> 태그로 묶여서 <data> 태그로 제공되는 것을 확인할 수 있습니다. 아직 제가 html 코드를 잘 보지 못하기 때문에 이를 다시 분해해서 저만의 방식으로 파싱 할 수 없었습니다. 교재에서 제공하는 방식을 조금만 변형해서 시도하고자 했지만 그마저도 녹록지 않았습니다. 구글에서 찾아본 결과 제가 찾아본 모든 xml 타입의 데이터를 다루는 글은 교재와 동일한 형식으로 진행하였습니다. 결국 xml은 좀 더 내공이 쌓이면 도전해 보는 것으로 하고, 교재의 뒷부분을 공부하기 위해서 이 부분을 'json' 타입의 데이터를 파싱 하는 것으로 대체하고자 합니다.


2.  공공데이터 포털에서 Open API의 데이터 json으로 파싱 하기

 공공데이터 포털에서 Open API를 사용하는 방법은 아래의 링크를 확인하시기 바랍니다.

2023.03.10 - [개발고생일지/API] - 공공데이터 포털에서 Open API 사용 방법

 

공공데이터 포털에서 Open API 사용 방법

- 목차 들어가는 말 1. 공공데이터 포털 회원가입 2. 공공데이터 포털 Open API 인증키 신청하기 3. 공공데이터 포털 Open API 사용 방법 4. 실습 갈무리 들어가는 말 현재 파이썬으로 웹 크롤링을 하는

applecoconut.tistory.com


import requests
import json

url = "(API-json URL)"

[코드 3] json 데이터 다루기 01

  먼저 'requests'와 'json' 라이브러리를 불러오고 url 변수에 API 호출로 돌려받은 URL을 문자열로 넣어줍니다.

server_response = requests.get(url)
contents = server_response.text

print(contents)

[코드 3] json 데이터 다루기 02

  URL 속의 데이터는 공공데이터 포털에서 server_response로 받은 것이므로 일단 동일한 이름으로 변수를 만들어 url을 불러옵니다. 이후 내부의 데이터를. text 메서드로 뽑아 변수 contents에 할당합니다. contents의 내용을 확인해 보면 다음과 같습니다.

{"currentCount":24,"data":[{"ALL_CNT":51,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201901"},{"ALL_CNT":56,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201902"},{"ALL_CNT":78,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201903"},{"ALL_CNT":64,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201904"},{"ALL_CNT":43,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201905"},{"ALL_CNT":55,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201906"},{"ALL_CNT":115,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201911"},{"ALL_CNT":75,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201907"},{"ALL_CNT":63,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201909"},{"ALL_CNT":83,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201908"},{"ALL_CNT":194,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202001"},{"ALL_CNT":79,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201910"},{"ALL_CNT":204,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"201912"},{"ALL_CNT":106,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202006"},{"ALL_CNT":68,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202005"},{"ALL_CNT":104,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202003"},{"ALL_CNT":91,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202002"},{"ALL_CNT":55,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202004"},{"ALL_CNT":51,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202010"},{"ALL_CNT":57,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202009"},{"ALL_CNT":80,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202008"},{"ALL_CNT":173,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202007"},{"ALL_CNT":102,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202012"},{"ALL_CNT":100,"DEAL_OBJ":"05","LEVEL_NO":"1","REGION_CD":"11110","REGION_NM":"종로구","RESEARCH_DATE":"202011"}],"matchCount":24,"page":1,"perPage":30,"totalCount":411531}

[코드 4] 불러온 contents 데이터


 딕셔너리의 형태로 보이지만 print(type(contents)로 실행해 보면 데이터 타입이 'str'로 나옵니다. 이것을 활용할 수 있는 데이터의 형태로 만들어야 합니다.

json_ob = json.loads(contents)

realEstate = json_ob["data"]

[코드 5] 문자열을 딕셔너리 타입으로 만들고 필요한 값이 있는 키만 추출

 .loads 메서드를 이용해 contents를 json 객체로 불러옵니다. 이때 변수 json_ob의 데이터 타입은 딕셔너리가 됩니다.

 이 딕셔너리 타입의 데이터에서 우리가 필요한 값의 키(Key)는 "data"입니다.  딕셔너리명["Key"]을 이용해 realEstate 변수에 key"data"에 속한 값(value)만 할당합니다.


import pandas as pd

dataframe = pd.json_normalize(realEstate)

print(dataframe)

 [코드 6] pandas를 활용한 데이터프레임 가공

 이제 딕셔너리에 저장된 데이터들을 표 형태로 가공해야 합니다. 'pandas' 라이브러리를 불러오고 pd라는 간략한 이름을 할당합니다. as "문자열"은 불러오는 라이브러리를 간략하게 "문자열"로 호출하겠다는 것입니다. dataframe이라는 변수에 .json_normalize() 메서드를 이용해 realEstate를 표 형태로 가공합니다. 가공된 표 dataframe을 확인해 보면 다음과 같습니다.


[그림 2] 정렬이 되지 않은 데이터 표
[그림 2] 정렬이 되지 않은 데이터 표

 이제 시각화 라이브러리나 기타 데이터 가공 도구를 활용할 수 있는 기초적인 형태로 가공되었습니다. 다만 가장 우측 날짜 데이터를 보면 날짜순으로 정렬이 되지 않은 것을 알 수 있습니다. 날짜순으로 데이터를 한 번 더 가공해 주어야 합니다.

df = dataframe.sort_values(by=['RESEARCH_DATE'])

print(df)

[코드 7] 정렬 메서드를 활용한 날짜순 정렬

 변수 df에 .sort_values(by=['정렬하고픈 값-이름']) 메서드를 사용해서 정렬된 새로운 표를 입력합니다.


[그림 3] 정렬된 데이터 표
[그림 3] 정렬된 데이터 표

 


갈무리

코드 전체 보기

import requests
import json

url = "API_URL"

server_response = requests.get(url)
contents = server_response.text
print(type(contents))

json_ob = json.loads(contents)
realEstate = json_ob["data"]


import pandas as pd

dataframe = pd.json_normalize(realEstate)
df = dataframe.sort_values(by=['RESEARCH_DATE'])

print(df)

[코드 8] 전체 코드 표

 공공데이터 포털에서 내려받은 json 데이터를 파싱 하는 법에 대해서 알아보았습니다. 이 글이 제작된 배경은 교재 '웹 크롤링 & 데이터 분석 with 파이썬'에서 예제가 제대로 적용이 되지 않아 작성하게 된 문서입니다. 이후 이 책을 통해서 웹 크롤링을 배우는 분들에게 조금이나마 도움이 되었기를 바라면서 이만 글을 마칩니다.

반응형