본문 바로가기
코딩/Python

공공데이터포털 API 활용해 부동산 실거래가 데이터 가져오기/파이썬에서 xml 데이터 처리하는 방법

by 나홀로코더 2022. 5. 1.
반응형

목차

1. 주제 소개

2. XML 데이터 처리하기(xml 모듈)

3. XML 데이터를 판다스 데이터프레임으로 변환하기


 

1.  주제 소개

 

앞서 파이썬으로 공공데이터포털 오픈 API를 활용하는 방법을 소개한 적이 있다.

 

파이썬으로 공공데이터포털(data.go.kr) 오픈 API 활용하기 예제/국세청 사업자등록 상태 조회

 

파이썬으로 공공데이터포털(data.go.kr) 오픈 API 활용하기 예제/국세청 사업자등록 상태 조회

목차 1. 주제 소개 2. API 활용신청하고 포털에서 API 사용해 보기 3. 파이썬으로 API 활용하기 1. 주제 소개 정부에서는 공공데이터의 제공 및 이용 활성화에 관한 법률 제21조에 따라 공공데이터포

codealone.tistory.com

 

위 예제의 경우 API 응답이 json 형식이라서 requests 모듈의 json() 메서드를 이용하면 바로 파이썬 딕셔너리와 똑같이 다룰 수가 있었다.

 

이번에는 응답 형식이 xml인 API의 예제로서 부동산 실거래가 API를 다뤄보려고 한다.

 

아파트 실거래자료 API 상세 화면

 

먼저 사업자등록상태 조회를 했을 때와 마찬가지로 requests를 이용해 API를 호출하는 코드를 작성한다. 

 

import requests

url ="http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade"
serviceKey = requests.utils.unquote("공공데이터포털 개발계정 상세보기에서 API키를 확인(인코딩 키를 사용)")
dealMon = "202204" # yyyymm
StanReginCd = "11110" # www.code.go.kr

params = {
        "serviceKey": serviceKey,
        "LAWD_CD": StanReginCd,
        "DEAL_YMD": dealMon 
        }

res = requests.get(url, params=params)

 

사업자등록상태 호출과 다른 점이 크게 2가지 보인다.

 

첫째로, post가 아니라 get 요청을 보내는 점이 다르다. 어떤 요청을 보내야 하는지는 매 경우마다 다른데, 부동산 실거래가 API의 기술문서를 보면 다음과 같이 get 요청을 보내야 한다고 설명되어 있다.

 

기술문서 내용

 

둘째로, 서비스키를 그냥 사용하지 않고 requests.utils.unquote() 메서드를 이용해 디코딩하는 점이다. 이 부분은 필자에게만 해당하는지 일반적인지 모르겠는데,  필자의 경우 디코딩 없이 API를 호출하려 하면 "SERVICE KEY IS NOT REGISTERED" 에러가 발생한다. unquote()  메서드의 인자로는 개발계정에서 제공되는 2개의 API 중에서 인코딩 버전(% 표시가 포함된 것)을 넘겨 주면 된다.

 

위와 같이 코드를 작성하면 API가 호출된다. res를 그대로 출력하면 <Response [200]>이 출력되고, res.text를 출력하면 다음과 같이 xml 데이터가 텍스트 형태로 출력된다.

 

'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><response><header><resultCode>00</resultCode><resultMsg>NORMAL SERVICE.</resultMsg></header><body><items><item><거래금액>...'

 

이같은 xml 데이터를 다루기 위한 파이썬 내장 모듈 사용법을 알아 보자.

 

 

반응형

 

2. XML 데이터 처리하기(xml 모듈)

 

파이썬은 예제와 같은 xml 데이터를 처리하기 위한 내장 모듈을 가지고 있다. 

 

https://docs.python.org/ko/3/library/xml.etree.elementtree.html

 

xml.etree.ElementTree — ElementTree XML API — Python 3.10.4 문서

소스 코드: Lib/xml/etree/ElementTree.py xml.etree.ElementTree 모듈은 XML 데이터를 구문 분석하고 만들기 위한 단순하고 효율적인 API를 구현합니다. 버전 3.3에서 변경: 이 모듈은 가능할 때마다 빠른 구현을

docs.python.org

 

위 문서를 보면 사용법을 알 수 있는데, 그중 몇 가지를 여기에 소개한다.

 

먼저 아래와 같이 모듈을 불러오자.

 

from xml.etree import ElementTree as ET

 

그런 다음 위에서 얻은 API 호출 결과를 xml 객체로 만들기 위해 다음과 같이 코드를 작성한다.

 

tree = ET.fromstring(res.content)

 

tree를 출력해 보면 <Element 'response' at 0x74737306d0>와 같이 출력이 된다. xml 객체로 변환되었다.

 

xml 요소의 내용을 출력하는 메서드인 .dump()를 사용하면 xml 요소의 내용을 볼 수가 있다. 출력 결과는 앞에서 res.text를 출럭한 것과 비슷하게 보일 것이다.

 

ET.dump(tree)

 

가독성이 떨어지니 보기 좋게 들여쓰기를 해주자.

 

ET.indent(tree, space="  ")

 

다시 dump로 tree를 출력해 보면 이제 훨씬 보기 좋게 출력이 된다.

 

<response>
  <header>
    <resultCode>00</resultCode>
    <resultMsg>NORMAL SERVICE.</resultMsg>
  </header>
  <body>
    <items>
      <item>
        <거래금액>    34,800</거래금액>
        <거래유형>직거래</거래유형>
        <건축년도>2021</건축년도>
        <년>2022</년>
        <법정동> 효제동</법정동>
        <아파트>이지마루종로</아파트>
        <월>4</월>
        <일>11</일>
        <전용면적>25.55</전용면적>
        <중개사소재지> </중개사소재지>
        <지번>126-2</지번>
        <지역코드>11110</지역코드>
        <층>5</층>
        <해제사유발생일> </해제사유발생일>
        <해제여부> </해제여부>
      </item>
      <item>
        <거래금액>    17,700</거래금액>
...
      </item>
    </items>
    <numOfRows>10</numOfRows>
    <pageNo>1</pageNo>
    <totalCount>13</totalCount>
  </body>
</response>

 

xml 트리의 구조를 보면, response 요소 안에 header와 body가 있고, body 안에는 items,  numOfRows, pageNo, totalCount 요소가 나란히 있고, 그 중 items 요소 안에 각 실거래가 정보가 담긴 item 요소들이 나열되어 있다.

 

xml 객체는 파이썬 리스트와 마찬가지로 각 요소의 인덱스를 이용해 접근할 수 있다. 예제의 xml 트리를 리스트로 표현해 보면 다음과 같을 것이다.

 

tree = [header, [[item, item, ...],  numOfRows, pageNo, totalCount]]

 

따라서 우리가 관심 있는 items 요소에는 다음과 같이 접근할 수 있다.

 

items = tree[1][0]

 

[참고]
리스트와 마찬가지로 음수로도 인덱싱할 수 있다.
(실거래가 데이터의 개수인 totalCount 요소: tree[1][-1])

 

반응형

 

3. XML 데이터를 판다스 데이터프레임으로 변환하기

 

xml 객체 다루는 방법을 어느 정도 익혔으니 xml 객체를 판다스 데이터프레임으로 변환하는 방법을 알아보자.

 

[참고]
판다스는 read_xml() 메서드를 제공하지만, 예제의 xml 데이터를 넘겨줄 경우 에러가 발생한다. 
판다스 문서의 설명을 보면 예제의 데이터가 중첩된 구조를 가지고 있어서 에러가 나는 것으로 보인다.
https://pandas.pydata.org/docs/reference/api/pandas.read_xml.html

 

먼저 판다스를 불러온다.

 

import pandas as pd

 

그런 다음 items 요소 안의 각 item에 담긴 정보들을 '리스트의 리스트' 형태로 변환해 준다. 중첩된 형태의 리스트 컴프리헨션을 이용한다.

 

listOfItems = [[i.text for i in item] for item in items]

 

listOfItems를 출력해 보면 아래와 같다.

 

[['    34,800',
  '직거래',
  '2021',
  '2022',
  ' 효제동',
  '이지마루종로',
  '4',
  '11',
  '25.55',
  ' ',
  '126-2',
  '11110',
  '5',
  ' ',
  ' '],
 ['    17,700',
 ...
  ' ']]

 

리스트 컴프리헨션에 대해 잘 모른다면 아래 글을 읽어보기 바란다.

 

파이썬에서 코드 한줄로 리스트(딕셔너리, 집합, 제너레이터) 만들기/리스트컴프리헨션, list comprehension

 

파이썬에서 코드 한줄로 리스트(딕셔너리, 집합, 제너레이터) 만들기/리스트컴프리헨션, list compr

서론 파이썬의 기초를 배우고 있는 사람이라면 아래와 같은 코드를 한번쯤 보았을 것이다. 반복문을 이용해 리스트를 만드는 방법으로, 대부분의 튜토리얼에서 이 방법을 먼저 선보이고 있는

codealone.tistory.com

 

그리고 데이터프레임의 칼럼명으로 사용하기 위해서 다음과 같이 첫번째 item의 하부 요소별 태그명을 리스트로 저장한다.

 

columns  = [i.tag for i in items[0]]

 

columns를 출력해 보면 다음과 같다.

 

['거래금액',
 '거래유형',
 '건축년도',
 '년',
 '법정동',
 '아파트',
 '월',
 '일',
 '전용면적',
 '중개사소재지',
 '지번',
 '지역코드',
 '층',
 '해제사유발생일',
 '해제여부']

 

마지막으로 위에서 추출한 listOfItems와 columns를 이용해 데이터프레임을 생성한다.

 

df = pd.DataFrame(listOfItems, columns=columns)

 

df를 출력해 보면 다음과 같다.

 

거래금액  거래유형  건축년도     년    법정동  ...      지번   지역코드   층   해 제사유발생일 해제여부
0       34,800   직거래  2021  2022    효제동  ...   126-2  11110   5
1       17,700   직거래  2017  2022    효제동  ...    65-2  11110   8
2       18,500  중개거래  1995  2022   명륜1가  ...    5-89  11110   4
3       78,000   직거래  1996  2022   명륜2가  ...     236  11110   1
4       70,500  중개거래  1993  2022    창신동  ...     703  11110   8
5       92,000  중개거래  2009  2022    숭인동  ...     766  11110  17
6       10,000   직거래  2013  2022    숭인동  ...  201-11  11110   7
7      230,000  중개거래  2017  2022     평동  ...     233  11110  19  22.04.27    O
8      230,000  중개거래  2017  2022     평동  ...     233  11110  19
9       20,000   직거래  1971  2022    행촌동  ...    41-1  11110   8
10      56,000  중개거래  2017  2022    평창동  ...   179-5  11110   5
11     164,000  중개거래  2008  2022    무악동  ...      60  11110  16
12     112,490  중개거래  2000  2022    무악동  ...      82  11110  13

[13 rows x 15 columns]

 

[참고] 데이터 타입 변경하는 방법

 

df.info()로 데이터프레임 정보를 살펴 보면 모두 object 타입으로 돼 있다.

 

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13 entries, 0 to 12
Data columns (total 15 columns):
 #   Column   Non-Null Count  Dtype
---  ------   --------------  -----
 0   거래금액     13 non-null     object
 1   거래유형     13 non-null     object
 2   건축년도     13 non-null     object
 3   년        13 non-null     object
 4   법정동      13 non-null     object
 5   아파트      13 non-null     object
 6   월        13 non-null     object
 7   일        13 non-null     object
 8   전용면적     13 non-null     object
 9   중개사소재지   13 non-null     object
 10  지번       13 non-null     object
 11  지역코드     13 non-null     object
 12  층        13 non-null     object
 13  해제사유발생일  13 non-null     object
 14  해제여부     13 non-null     object
dtypes: object(15)
memory usage: 1.6+ KB

 

그중 거래금액 칼럼을 int 타입으로 바꾸려면 다음과 같이 하면 된다.

 

df.거래금액.str.strip().str.replace(",","").astype(int)

 

strip()은 각 데이터의 좌측 여백을 제거하는 것이고, replace()는 쉼표를 제거하는 것이며, 마지막으로 astype()을 이용해 int로 변환한다.

반응형

댓글