- 목차
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 사용 방법
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을 확인해 보면 다음과 같습니다.
이제 시각화 라이브러리나 기타 데이터 가공 도구를 활용할 수 있는 기초적인 형태로 가공되었습니다. 다만 가장 우측 날짜 데이터를 보면 날짜순으로 정렬이 되지 않은 것을 알 수 있습니다. 날짜순으로 데이터를 한 번 더 가공해 주어야 합니다.
df = dataframe.sort_values(by=['RESEARCH_DATE'])
print(df)
[코드 7] 정렬 메서드를 활용한 날짜순 정렬
변수 df에 .sort_values(by=['정렬하고픈 값-이름']) 메서드를 사용해서 정렬된 새로운 표를 입력합니다.
갈무리
코드 전체 보기
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 파이썬'에서 예제가 제대로 적용이 되지 않아 작성하게 된 문서입니다. 이후 이 책을 통해서 웹 크롤링을 배우는 분들에게 조금이나마 도움이 되었기를 바라면서 이만 글을 마칩니다.
'개발고생일지 > 파이썬' 카테고리의 다른 글
pandas Dataframe(데이터프레임) 만드는 방법 총정리 (0) | 2023.03.24 |
---|---|
pandas Empty Dataframe(빈 데이터 프레임) 만드는 방법 (0) | 2023.03.24 |
[Selenium] DeprecationWarning: executable_path has been deprecated 오류 해결 방법 (1) | 2023.03.05 |
M1 Mac(맥북)에서 아나콘다 초기 설정 (0) | 2023.02.26 |
M1, M2 (ARM) Mac에서 아나콘다 설치와 제거 방법 (0) | 2023.02.24 |