공공데이터를 활용한 아파트 도로명 주소 등 추출해보기
공공데이터를 openapi로 제공하는 data.go.kr에서 아파트 관련 정보를 얻기 위해 api 사용 연습을 해보았는데, 구글에서 관련 자료들을 참고하여 시도하니 큰 어려움은 없었으나 1일당 제공하는 데이터의 양이 적은 것도 있어서, 표준 데이터(공동주택 기본 정보)를 활용했고, 그에 대한 샘플 자료를 대상으로 한 api 호출 내용을 정리해보았다.
아파트(공동주택) 기본 정보 api 호출 연습 등에 대한 정리
1. 본 작업을 하게 된 동기
얼마 전에 창호 샷시 교체 사업을 하는 회사에 다니는 지인의 부탁으로 아파트 dm을 보낼 주소(도로명 주소 기반 아파트 주소)를 구해달라는 부탁을 받았다.
인근 아파트에 리플릿이나 전단지 배포를 위해 사람을 고용하여 동, 호수마다 전단지를 한 장씩 배포하는 것은 해당 업종에는 안 맞고, 홈페이지, 블로그 등에 대한 sns 홍보와 온라인 홍보도 하고는 있었지만, 우편번호를 포함한 도로명 주소가 있으면 제품이나 솔루션 홍보를 전단지 형태로 만들어서 우편(dm)으로 한 번 진행하고 싶다는 것이었다.
이러한 요구사항을 해결해주긴 했으나 추출한 아파트 주소 자료를 다른 무엇과 합칠 경우, 보다 더 유용한 자료가 나올 것이라 판단되어 공공데이터로 눈을 돌렸다.
2. 해보려고 하는 작업
온라인 홍보가 광고 홍보 수단의 최고라는 것은 의심의 여지가 없지만, 지인 회사처럼 우편번호, 도로명 주소 기반으로 dm을 보내서 제품(창호, 샤시)을 홍보하려는 업체가 있다면,
또한, 오래된 아파트를 대상으로 창호 샷시가 아닌 다른 업종의 제품 홍보나 아파트 분양 등의 부동산 분양 정보, 자동차 리플릿을 일정 지역의 아파트를 대상으로 dm을 보내는 업체가 있다면, 데이터를 가공해서 제공할 수도 있을 것으로 보였다.
3. 공공데이터 open API 활용해보기(샘플 데이터 활용)
- 먼저, 공공데이터 포털에 가입을 해야 한다.
- 그리고, open api를 사용할 인증키를 신청하고 발급을 받으면, 필요한 데이터를 검색하여 활용 신청을 한 후 api 연동 등의 작업을 하면 된다.
- 메인 화면에서 "아파트"라고 검색하니 여러 데이터가 나왔다. 흥미로운 것은 아파트 매매 실거래가 데이터도 제공되고 있다는 점...
- 표준 데이터셋 탭을 눌러 "전국 공동주택 표준 데이터"를 클릭해서 보니, 다음과 같은 유용한 자료가 제공되었다. (실제 필요한 것은 일부지만....)
단지 코드를 이용해 단지명, 법정동 주소, 분양 형태, 난방방식, 건축물대장상 연면적, 동수, 세대수, 시공사, 시행사, 관리사무소 연락처, 관리사무소 팩스, 홈페이지 주소, 단지 분류, 도로명주소, 호수, 관리방식, 복도 유형, 사용승인일, 관리비 부과면적, 전용면적별 세대 현황, 단지 전용면적합, 법정동 코드를 조회할 수 있는 공동주택 기본 정보제공 서비스
- 활용 승인 절차 개발단계 : 허용 / 운영단계 : 허용
- 신청 가능 트래픽 10,000 / 운영 계정은 활용사례 등록 시 신청하면 트래픽 증가 가능
- 요청 주소 http://apis.data.go.kr/1613000/AptBasisInfoService1/getAphusBassInfo
- 서비스 URL http://apis.data.go.kr/1613000/AptBasisInfoService1
다행인 것은, 운영 계정은 트래픽 증가가 가능하다고 한다.
샘플 코드
import requests
url = 'http://apis.data.go.kr/1613000/AptBasisInfoService1/getAphusBassInfo'
params ={'serviceKey' : '서비스키', 'kaptCode' : 'A10027875' }
response = requests.get(url, params=params)
print(response.content)
미리 보기 페이지의 url을 통해 샘플 코드를 실행해보았다.
import requests
import xmltodict
import pandas as pd
url = 'http://apis.data.go.kr/1613000/AptBasisInfoService1/getAphusBassInfo?serviceKey=lKEUr0Sjw%2F9nxJMmHhghe3wti2PWT2BOxB4Isq9QzY6f9o2qitdgd4r6L1yHJaNdVWk4uduR2Hp11kUV1JMmPw%3D%3D&kaptCode=A10027875'
response = requests.get(url)
print(response.content)
[출력 결과]를 보면, 아스키코드로 보이는 문자열이 나온다.
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><response><header><resultCode>00</resultCode><resultMsg>NORMAL SERVICE.</resultMsg></header><body><item><bjdCode>2638010100</bjdCode><codeAptNm>\xec\x95\x84\xed\x8c\x8c\xed\x8a\xb8</codeAptNm><codeHallNm>\xed\x98\xbc\xed\x95\xa9\xec\x8b\x9d</codeHallNm><codeHeatNm>\xea\xb0\x9c\xeb\xb3\x84\xeb\x82\x9c\xeb\xb0\xa9</codeHeatNm><codeMgrNm>\xec\x9e\x90\xec\xb9\x98\xea\xb4\x80\xeb\xa6\xac</codeMgrNm><codeSaleNm>\xeb\xb6\x84\xec\x96\x91</codeSaleNm><doroJuso>\xeb\xb6\x80\xec\x82\xb0\xea\xb4\x91\xec\x97\xad\xec\x8b\x9c \xec\x82\xac\xed\x95\x98\xea\xb5\xac \xeb\x82\x99\xeb\x8f\x99\xeb\x8c\x80\xeb\xa1\x9c 180</doroJuso><hoCnt>182</hoCnt><kaptAcompany>(\xec\xa3\xbc)\xea\xb2\xbd\xec\x84\xb1\xeb\xa6\xac\xec\xb8\xa0</kaptAcompany><kaptAddr>\xeb\xb6\x80\xec\x82\xb0\xea\xb4\x91\xec\x97\xad\xec\x8b\x9c \xec\x82\xac\xed\x95\x98\xea\xb5\xac \xea\xb4\xb4\xec\xa0\x95\xeb\x8f\x99 258 \xea\xb4\xb4\xec\xa0\x95 \xea\xb2\xbd\xec\x84\xb1\xec\x8a\xa4\xeb\xa7\x88\xed\x8a\xb8W\xec\x95\x84\xed\x8c\x8c\xed\x8a\xb8</kaptAddr><kaptBcompany>(\xec\xa3\xbc)\xea\xb2\xbd\xec\x84\xb1\xeb\xa6\xac\xec\xb8\xa0</kaptBcompany><kaptCode>A10027875</kaptCode><kaptDongCnt>3</kaptDongCnt><kaptFax>0512949364</kaptFax><kaptMarea>15040.1634</kaptMarea><kaptMparea_135>0</kaptMparea_135><kaptMparea_136>0</kaptMparea_136><kaptMparea_60>182</kaptMparea_60><kaptMparea_85>0</kaptMparea_85><kaptName>\xea\xb4\xb4\xec\xa0\x95 \xea\xb2\xbd\xec\x84\xb1\xec\x8a\xa4\xeb\xa7\x88\xed\x8a\xb8W\xec\x95\x84\xed\x8c\x8c\xed\x8a\xb8</kaptName><kaptTarea>15040.1634</kaptTarea><kaptTel>0512949363</kaptTel><kaptUrl> </kaptUrl><kaptUsedate>20150806</kaptUsedate><kaptdaCn
xml_data = response.content.decode('utf-8')
print(xml_data)
parse_data = xmltodict.parse(xml_data)
print(parse_data) # OrderedDict([('response', OrderedDict([('header',...
[출력 결과]를 보면, decode 시 xml 데이터가 나오고, xmltodict 모듈로 파싱을 하니 제대로 된 아파트 관련 정보가 보인다.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><response><header><resultCode>00</resultCode><resultMsg>NORMAL SERVICE.</resultMsg></header><body><item><bjdCode>2638010100</bjdCode><codeAptNm>아파트</codeAptNm><codeHallNm>혼합식</codeHallNm><codeHeatNm>개별난방</codeHeatNm><codeMgrNm>자치관리
</codeMgrNm><codeSaleNm>분양</codeSaleNm><doroJuso>부산광역시 사하구 낙동대
로 180</doroJuso><hoCnt>182</hoCnt><kaptAcompany>(주)경성리츠</kaptAcompany><kaptAddr>부산광역시 사하구 괴정동 258 괴정 경성스마트W아파트</kaptAddr><kaptBcompany>(주)경성리츠</kaptBcompany><kaptCode>A10027875</kaptCode><kaptDongCnt>3</kaptDongCnt><kaptFax>0512949364</kaptFax><kaptMarea>15040.1634</kaptMarea><kaptMparea_135>0</kaptMparea_135><kaptMparea_136>0</kaptMparea_136><kaptMparea_60>182</kaptMparea_60><kaptMparea_85>0</kaptMparea_85><kaptName>괴정 경성스마트W아파트</kaptName><kaptTarea>15040.1634</kaptTarea><kaptTel>0512949363</kaptTel><kaptUrl> </kaptUrl><kaptUsedate>20150806</kaptUsedate><kaptdaCnt>182</kaptdaCnt><privArea>9014.0338</privArea></item></body></response>
OrderedDict([('response', OrderedDict([('header', OrderedDict([('resultCode', '00'), ('resultMsg', 'NORMAL SERVICE.')])), ('body', OrderedDict([('item', OrderedDict([('bjdCode', '2638010100'), ('codeAptNm', '아파트'), ('codeHallNm', '혼합식'), ('codeHeatNm', '개별난방'), ('codeMgrNm', '자치관리'), ('codeSaleNm', '분양'), ('doroJuso', '부산광역시 사하구 낙동대로 180'), ('hoCnt', '182'), ('kaptAcompany', '(주)경성리츠'), ('kaptAddr', '부산광역시 사
하구 괴정동 258 괴정 경성스마트W아파트'), ('kaptBcompany', '(주)경성리츠'), ('kaptCode', 'A10027875'), ('kaptDongCnt', '3'), ('kaptFax', '0512949364'), ('kaptMarea', '15040.1634'), ('kaptMparea_135', '0'), ('kaptMparea_136',
'0'), ('kaptMparea_60', '182'), ('kaptMparea_85', '0'), ('kaptName', '괴정
경성스마트W아파트'), ('kaptTarea', '15040.1634'), ('kaptTel', '0512949363'), ('kaptUrl', None), ('kaptUsedate', '20150806'), ('kaptdaCnt', '182'), ('privArea', '9014.0338')]))]))]))])
for 문으로 결과를 추출해보니,
아파트 정보가 있는 것을 볼 수 있다. (주석 부분은 공공데이터 포털의 상세 설명 내용임)
for key, val in parse_data['response']['body']['item'].items():
print(key, val)
'''
bjdCode 2638010100 ## 법정동 코드
codeAptNm 아파트 ## 단지 분류
codeHallNm 혼합식 ## 복도 유형
codeHeatNm 개별난방 ## 난방 방식
codeMgrNm 자치관리 ## 관리 방식
codeSaleNm 분양 ## 분양 형태
doroJuso 부산광역시 사하구 낙동대로 180 ## 도로명 주소
hoCnt 182 ## 호수
kaptAcompany (주)경성리츠 ## 시행사
kaptAddr 부산광역시 사하구 괴정동 258 괴정 경성스마트W아파트 ## 법정동주소
kaptBcompany (주)경성리츠 ## 시공사
kaptCode A10027875 ## 단지 코드
kaptDongCnt 3 ## 동수
kaptFax 0512949364 ## 관리사무소 팩스
kaptMarea 15040.1634 ## 관리비 부과면적(㎡)
kaptMparea_135 0 ## 전용면적별 세대현황(85㎡ ~ 135㎡ 이하)
kaptMparea_136 0 ## 전용면적별 세대현황(135㎡ 초과)
kaptMparea_60 182 ## 전용면적별 세대현황(60㎡ 이하)
kaptMparea_85 0 ## 전용면적별 세대현황(60㎡ ~ 85㎡ 이하)
kaptName 괴정 경성스마트W아파트 ## 단지명
kaptTarea 15040.1634 ## 건축물대장상 연면적(㎡)
kaptTel 0512949363 ## 관리사무소 연락처
kaptUrl None ## 홈페이지 주소
kaptUsedate 20150806 # 사용 승인일
kaptdaCnt 182 # 세대수
privArea 9014.0338 ## 단지 전용면적합(㎡)
'''
판다스로 엑셀 저장해 보기
df = pd.DataFrame(parse_data['response']['body']['item'], index=[0])
print(df.head())
df.to_excel('apt_std_sample.xlsx', encoding='utf-8-sig')
실 데이터 접근은
url = 'http://apis.data.go.kr/1613000/AptBasisInfoService1/getAphusBassInfo'
service_key = '본인의 인증키'
params ={'serviceKey' : service_key, 'kaptCode' : 'A10027871' }
response = requests.get(url, params=params)
print(response.content)
- 미리 보기 페이지 소스코드의 앞부분 중 이 부분만을 변경하여 실행하면 되는데, 각 아파트 단지를 맵핑할 수 있는 단지 코드(kaptCode)가 있어야 한다.
☞ 아파트 단지 코드 오픈 API : https://goodthings4me.tistory.com/597