Categories: '교육'

부동산 매매가 데이터 통계 정보 만들기 1편

오늘은 부동산 매매가 데이터 통계 정보를 만들어 보겠습니다. 간단하게 매매가 정보를 가지고 와서 유의미한 정보를 추출해서 보여주려고 합니다. 파이썬 코드로 쉽게 웹앱을 만들 수 있는 streamlit 을 사용해보도록 하겠습니다.

부동산 매매가 데이터 통계 정보 만들기 1편

먼저 예전에 사용했던 코드를 불러 오겠습니다. 기존 포스팅에서 사용했던 코드이니 기억하실 분도 있으실 겁니다. 만약 이 코드를 보고 이해가 안된다고 생각하시는 분들은 아래 포스팅을 한번 참고해보세요.

2024.09.14 – [부동산/자동화 프로젝트] – 파이썬 부동산 매매가 조회 프로그램 만들기 4편 (전국 데이터)

class DistrictConverter:
    def __init__(self):
        self.districts = self.__read_district_file()

    def __read_district_file(self):
        # 드라이브 내의 JSON 파일 경로를 설정합니다.
        json_file_path = '/content/drive/MyDrive/district.json'

        # 파일을 열어서 내용을 읽고 JSON으로 변환합니다.
        with open(json_file_path, 'r') as f:
            return json.loads(f.read())

    def get_si_do_code(self, si_do_name):
        for district in self.districts:
            if si_do_name == district["si_do_name"]:
                return district["si_do_code"]

    def get_sigungu(self, si_do_code):
        for district in self.districts:
            if si_do_code == district["si_do_code"]:
                return district["sigungu"]

def get_user_input(prompt, default_value=None):
    try:
        user_input = input(prompt)
        return user_input if user_input.strip() else default_value
    except EOFError:
        return default_value

# 사용자로부터 시/도와 기간을 입력 받음
si_do_name = get_user_input("시/도를 입력하세요 (예: 서울특별시) 또는 '전국' 입력: ", "전국")
start_year_month = get_user_input("조회 시작 년월 (YYYYMM 형식, 예: 202301): ", None)
end_year_month = get_user_input("조회 종료 년월 (YYYYMM 형식, 예: 202312): ", None)

# 현재 날짜를 기준으로 기간을 설정
now = datetime.now()
current_year_month = now.strftime("%Y%m")

# 기간을 설정합니다.
if not start_year_month:
    start_year_month = f"{now.year}01"
if not end_year_month:
    end_year_month = current_year_month

# DistrictConverter 인스턴스 생성
converter = DistrictConverter()

# 서울특별시와 모든 시/군/구 데이터를 수집할 DataFrame 초기화
all_data = pd.DataFrame()

# 전체 시/도 조사
if si_do_name == "전국":
    for district in converter.districts:
        si_do_code = district["si_do_code"]
        sigungu_list = district["sigungu"]
        for sigungu in sigungu_list:
            sigungu_code = sigungu["sigungu_code"]
            sigungu_name = sigungu["sigungu_name"]

            print(f"Processing data for {sigungu_name} ({sigungu_code})")

            # 부동산 데이터를 가져옴
            df = api.get_data(
                property_type="아파트",
                trade_type="매매",
                sigungu_code=sigungu_code,
                start_year_month=start_year_month,
                end_year_month=end_year_month
            )

            # 시/군/구 이름 및 시/도 이름을 새로운 컬럼으로 추가
            df["sigungu_name"] = sigungu_name
            df["si_do_name"] = district["si_do_name"]

            # 가져온 데이터를 all_data에 추가
            all_data = pd.concat([all_data, df], ignore_index=True)
else:
    si_do_code = converter.get_si_do_code(si_do_name)
    sigungu_list = converter.get_sigungu(si_do_code)

    for sigungu in sigungu_list:
        sigungu_code = sigungu["sigungu_code"]
        sigungu_name = sigungu["sigungu_name"]

        print(f"Processing data for {sigungu_name} ({sigungu_code})")

        # 부동산 데이터를 가져옴
        df = api.get_data(
            property_type="아파트",
            trade_type="매매",
            sigungu_code=sigungu_code,
            start_year_month=start_year_month,
            end_year_month=end_year_month
        )

        # 시/군/구 이름 및 시/도 이름을 새로운 컬럼으로 추가
        df["sigungu_name"] = sigungu_name
        df["si_do_name"] = si_do_name

        # 가져온 데이터를 all_data에 추가
        all_data = pd.concat([all_data, df], ignore_index=True)

# 데이터 열 이름을 한국어로 변환
columns_to_select = {
    "si_do_name": "시도",
    "sigungu_name": "시군구",
    "umdNm": "법정동",
    "roadNm": "도로명",
    "bonbun": "지번",
    "aptNm": "아파트",
    "buildYear": "건축년도",
    "excluUseAr": "전용면적",
    "floor": "층",
    "dealYear": "거래년도",
    "dealMonth": "거래월",
    "dealDay": "거래일",
    "dealAmount": "거래금액",
    "aptSeq": "일련번호",
    "dealingGbn": "거래유형",
    "estateAgentSggNm": "중개사소재지",
    "cdealType": "해제여부",
    "cdealDay": "해제사유발생일"
}

# 필요한 열만 남기고 한국어 열 이름으로 변경
selected_data = all_data.rename(columns=columns_to_select)[list(columns_to_select.values())]

# 구글 시트 API 인증
scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
creds = ServiceAccountCredentials.from_json_keyfile_name('/content/drive/MyDrive/client_secret_143915664608-hejcq3u26rkd7gd645tt7ef44cpfqbp2.apps.googleusercontent.com.json', scope)
client = gspread.authorize(creds)

# 구글 시트에 데이터 저장
def save_to_google_sheet(df, sheet_name):
    # 새로운 구글 시트 생성
    sh = client.create(sheet_name)
    worksheet = sh.get_worksheet(0)

    # 데이터프레임을 구글 시트에 추가
    worksheet.update([df.columns.values.tolist()] + df.values.tolist())

# 시트 이름 생성 및 데이터 저장
sheet_name = f'{si_do_name if si_do_name != "전국" else "전체"}_{start_year_month}_{end_year_month}_매매'
save_to_google_sheet(selected_data, sheet_name)

자, 이제 이 코드를 스트림릿에 맞게 코드를 아래와 같이 변경해줍니다. 이 데이터를 스트림릿 클라우드에 업로드하기 전에, 구글 드라이브에 저장하는 코드는 삭제하고 결과 값을 표로 나타내주는 코드를 추가하고, 데이터를 엑셀 또는 csv로 다운 받을 수 있는 옵션창을 하나 추가해보도록 하겠습니다. 그리고 개인 service key 는 보안상 아래과 같이 코드를 수정한 후 앱 설정에서 값을 설정합니다.

Streamlit 코드에 맞게 변경하기

이제 이 코드를 스트림릿에 맞게 코드를 아래와 같이 변경해줍니다.

import streamlit as st
import pandas as pd
import PublicDataReader as pdr
from datetime import datetime
import json

# Streamlit secrets에서 API 키 및 파일 경로 가져오기
service_key = st.secrets["general"]["SERVICE_KEY"]
json_file_path = "district.json"

# PublicDataReader API 서비스 키 사용
api = pdr.TransactionPrice(service_key)

# DistrictConverter 클래스 정의
class DistrictConverter:
    def __init__(self):
        self.districts = self.__read_district_file()

    def __read_district_file(self):
        with open(json_file_path, 'r') as f:
            return json.loads(f.read())

    def get_si_do_code(self, si_do_name):
        for district in self.districts:
            if si_do_name == district["si_do_name"]:
                return district["si_do_code"]

    def get_sigungu(self, si_do_code):
        for district in self.districts:
            if si_do_code == district["si_do_code"]:
                return district["sigungu"]

# 사용자 입력 받기
st.title("부동산 데이터 조회")
si_do_name = st.text_input("시/도를 입력하세요 (예: 서울특별시) 또는 '전국' 입력", "전국")
start_year_month = st.text_input("조회 시작 년월 (YYYYMM 형식, 예: 202301)", "")
end_year_month = st.text_input("조회 종료 년월 (YYYYMM 형식, 예: 202312)", "")

# 현재 날짜를 기준으로 기간 설정
now = datetime.now()
if not start_year_month:
    start_year_month = f"{now.year}01"
if not end_year_month:
    end_year_month = now.strftime("%Y%m")

# 데이터를 조회하는 버튼을 추가하여, 사용자 입력 후에만 데이터 처리를 시작합니다.
if st.button("데이터 조회"):
    if si_do_name and start_year_month and end_year_month:
        # DistrictConverter 인스턴스 생성
        converter = DistrictConverter()

        # 데이터 수집 및 처리
        all_data = pd.DataFrame()

        if si_do_name == "전국":
            for district in converter.districts:
                si_do_code = district["si_do_code"]
                sigungu_list = district["sigungu"]
                for sigungu in sigungu_list:
                    sigungu_code = sigungu["sigungu_code"]
                    sigungu_name = sigungu["sigungu_name"]

                    st.write(f"Processing data for {sigungu_name} ({sigungu_code})")

                    df = api.get_data(
                        property_type="아파트",
                        trade_type="매매",
                        sigungu_code=sigungu_code,
                        start_year_month=start_year_month,
                        end_year_month=end_year_month
                    )

                    df["sigungu_name"] = sigungu_name
                    df["si_do_name"] = district["si_do_name"]

                    all_data = pd.concat([all_data, df], ignore_index=True)
        else:
            si_do_code = converter.get_si_do_code(si_do_name)
            sigungu_list = converter.get_sigungu(si_do_code)

            for sigungu in sigungu_list:
                sigungu_code = sigungu["sigungu_code"]
                sigungu_name = sigungu["sigungu_name"]

                st.write(f"Processing data for {sigungu_name} ({sigungu_code})")

                df = api.get_data(
                    property_type="아파트",
                    trade_type="매매",
                    sigungu_code=sigungu_code,
                    start_year_month=start_year_month,
                    end_year_month=end_year_month
                )

                df["sigungu_name"] = sigungu_name
                df["si_do_name"] = si_do_name

                all_data = pd.concat([all_data, df], ignore_index=True)

        # 컬럼 이름 변환
        columns_to_select = {
            "si_do_name": "시도",
            "sigungu_name": "시군구",
            "umdNm": "법정동",
            "roadNm": "도로명",
            "bonbun": "지번",
            "aptNm": "아파트",
            "buildYear": "건축년도",
            "excluUseAr": "전용면적",
            "floor": "층",
            "dealYear": "거래년도",
            "dealMonth": "거래월",
            "dealDay": "거래일",
            "dealAmount": "거래금액",
            "aptSeq": "일련번호",
            "dealingGbn": "거래유형",
            "estateAgentSggNm": "중개사소재지",
            "cdealType": "해제여부",
            "cdealDay": "해제사유발생일"
        }

        selected_data = all_data.rename(columns=columns_to_select)[list(columns_to_select.values())]

        # 데이터 표로 표시
        st.write("### 조회 결과")
        st.dataframe(selected_data)

        # 데이터 다운로드 옵션 추가
        st.write("### 데이터 다운로드")
        excel_filename = f"{si_do_name}_{start_year_month}_{end_year_month}_매매.xlsx"
        csv_filename = f"{si_do_name}_{start_year_month}_{end_year_month}_매매.csv"

        # 엑셀 다운로드
        st.download_button(
            label="엑셀로 다운로드",
            data=selected_data.to_excel(index=False, engine='xlsxwriter'),
            file_name=excel_filename,
            mime='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )

        # CSV 다운로드
        st.download_button(
            label="CSV로 다운로드",
            data=selected_data.to_csv(index=False),
            file_name=csv_filename,
            mime='text/csv'
        )
    else:
        st.error("모든 필드를 채워주세요.")

Streamlit 코드 옵션 설정 및 key service 부여하기

이제 이 코드를 스트림릿 클라우드 옵션에 key service를 아래와 같이 설정 합니다.

[general]
SERVICE_KEY = "your_actual_service_key_here"
DISTRICT_JSON_PATH = "/path/to/your/district.json"

자 실행하면 잘 됩니다만, 에러 출력을 하나 만나게 됩니다.

File “/home/adminuser/venv/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/exec_code.py”, line 88, in exec_func_with_error_handling result = func() ^^^^^^
File “/home/adminuser/venv/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/script_runner.py”, line 590, in code_to_exec exec(code, module.__dict__)
File “/mount/src/price_stastic/streamlit_app.py”, line 136, in <module> data=selected_data.to_excel(index=False, engine=’xlsxwriter’), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/home/adminuser/venv/lib/python3.12/site-packages/pandas/util/_decorators.py”, line 333, in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^

우선 엑셀 데이터를 메모리에 저장한 후 이를 download_button으로 제공해야 하도록 수정하겠습니다.

import streamlit as st
import pandas as pd
import PublicDataReader as pdr
from datetime import datetime
import json
from io import BytesIO

# Streamlit secrets에서 API 키 및 파일 경로 가져오기
service_key = st.secrets["general"]["SERVICE_KEY"]
json_file_path = "district.json"

# PublicDataReader API 서비스 키 사용
api = pdr.TransactionPrice(service_key)

# DistrictConverter 클래스 정의
class DistrictConverter:
    def __init__(self):
        self.districts = self.__read_district_file()

    def __read_district_file(self):
        with open(json_file_path, 'r') as f:
            return json.loads(f.read())

    def get_si_do_code(self, si_do_name):
        for district in self.districts:
            if si_do_name == district["si_do_name"]:
                return district["si_do_code"]

    def get_sigungu(self, si_do_code):
        for district in self.districts:
            if si_do_code == district["si_do_code"]:
                return district["sigungu"]

# 사용자 입력 받기
st.title("부동산 데이터 조회")
si_do_name = st.text_input("시/도를 입력하세요 (예: 서울특별시) 또는 '전국' 입력", "전국")
start_year_month = st.text_input("조회 시작 년월 (YYYYMM 형식, 예: 202301)", "")
end_year_month = st.text_input("조회 종료 년월 (YYYYMM 형식, 예: 202312)", "")

# 현재 날짜를 기준으로 기간 설정
now = datetime.now()
if not start_year_month:
    start_year_month = f"{now.year}01"
if not end_year_month:
    end_year_month = now.strftime("%Y%m")

# 데이터를 조회하는 버튼을 추가하여, 사용자 입력 후에만 데이터 처리를 시작합니다.
if st.button("데이터 조회"):
    if si_do_name and start_year_month and end_year_month:
        # DistrictConverter 인스턴스 생성
        converter = DistrictConverter()

        # 데이터 수집 및 처리
        all_data = pd.DataFrame()

        if si_do_name == "전국":
            for district in converter.districts:
                si_do_code = district["si_do_code"]
                sigungu_list = district["sigungu"]
                for sigungu in sigungu_list:
                    sigungu_code = sigungu["sigungu_code"]
                    sigungu_name = sigungu["sigungu_name"]

                    st.write(f"Processing data for {sigungu_name} ({sigungu_code})")

                    df = api.get_data(
                        property_type="아파트",
                        trade_type="매매",
                        sigungu_code=sigungu_code,
                        start_year_month=start_year_month,
                        end_year_month=end_year_month
                    )

                    df["sigungu_name"] = sigungu_name
                    df["si_do_name"] = district["si_do_name"]

                    all_data = pd.concat([all_data, df], ignore_index=True)
        else:
            si_do_code = converter.get_si_do_code(si_do_name)
            sigungu_list = converter.get_sigungu(si_do_code)

            for sigungu in sigungu_list:
                sigungu_code = sigungu["sigungu_code"]
                sigungu_name = sigungu["sigungu_name"]

                st.write(f"Processing data for {sigungu_name} ({sigungu_code})")

                df = api.get_data(
                    property_type="아파트",
                    trade_type="매매",
                    sigungu_code=sigungu_code,
                    start_year_month=start_year_month,
                    end_year_month=end_year_month
                )

                df["sigungu_name"] = sigungu_name
                df["si_do_name"] = si_do_name

                all_data = pd.concat([all_data, df], ignore_index=True)

        # 컬럼 이름 변환
        columns_to_select = {
            "si_do_name": "시도",
            "sigungu_name": "시군구",
            "umdNm": "법정동",
            "roadNm": "도로명",
            "bonbun": "지번",
            "aptNm": "아파트",
            "buildYear": "건축년도",
            "excluUseAr": "전용면적",
            "floor": "층",
            "dealYear": "거래년도",
            "dealMonth": "거래월",
            "dealDay": "거래일",
            "dealAmount": "거래금액",
            "aptSeq": "일련번호",
            "dealingGbn": "거래유형",
            "estateAgentSggNm": "중개사소재지",
            "cdealType": "해제여부",
            "cdealDay": "해제사유발생일"
        }

        selected_data = all_data.rename(columns=columns_to_select)[list(columns_to_select.values())]

        # 데이터 표로 표시
        st.write("### 조회 결과")
        st.dataframe(selected_data)

        # 데이터 다운로드 옵션 추가
        st.write("### 데이터 다운로드")
        excel_filename = f"{si_do_name}_{start_year_month}_{end_year_month}_매매.xlsx"
        csv_filename = f"{si_do_name}_{start_year_month}_{end_year_month}_매매.csv"

        # 엑셀 다운로드 (BytesIO로 메모리에 저장)
        output = BytesIO()
        with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
            selected_data.to_excel(writer, index=False)
        output.seek(0)

        st.download_button(
            label="엑셀로 다운로드",
            data=output,
            file_name=excel_filename,
            mime='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )

        # CSV 다운로드
        st.download_button(
            label="CSV로 다운로드",
            data=selected_data.to_csv(index=False),
            file_name=csv_filename,
            mime='text/csv'
        )
    else:
        st.error("모든 필드를 채워주세요.")

네 이제 정상 작동을 하지요? 이 코드로 추출한 정보를 streamlit 에서 좀 더 세밀한 분석을 해보고, 시각화된 자료로 출력이 될 수 있도록 해보겠습니다. 2편 기대해주세요~

#부동산, 데이터, 부동산데이터, 부동산통계, 파이썬크롤링,파이썬부동산,부동산매매,부동산흐름,부동산매매가

urjent

Share
Published by
urjent

Recent Posts

대전가볼만한곳 추천 베스트 6 자연과 야경 그리고 가족 나들이 코스

대전가볼만한곳을 찾는다면 단순히 번화가나 흔한 유원지를 벗어나 지역 고유의 역사적 숨결과 화려한 야경을 동시에 만끽하는…

20분 ago

티빙 개인정보 유출 보상 신청 방법, 2만원 혜택 탈퇴 회원 재가입 가능

티빙 개인정보 유출 사태로 피해를 입은 회원은 자동 지급이 아니라 오는 9월 30일까지 직접 홈페이지나…

1시간 ago

청도날씨 가을 가볼만한곳 운문사 꽃무릇 개화 시기 옷차림 완벽 정리

청도날씨는 유난히 청명하고 선선한 가을바람이 불어오면서 야외 활동을 즐기기에 가장 완벽한 시기에 접어들었습니다. 경북 청도…

1시간 ago

2026년 10월축제 총정리 가을 여행 일정과 지역별 명소 추천

2026년 10월축제는 전국 각지에서 다채로운 문화 예술 행사와 함께 화려한 가을의 시작을 알리고 있습니다. 선선한…

3시간 ago

홍준표 프로필 나이 대구시장 사퇴 한동훈 아들 국회의원 총정리

정치권에서 직설적인 화법과 강력한 추진력으로 늘 화제의 중심에 서 있는 홍준표 전 대구시장은 검사 시절부터…

3시간 ago

2026년 9월축제 총정리 서울 및 전국 가볼만한 가을 행사 명소 안내

2026년 9월축제는 선선한 가을바람과 함께 서울 전역과 전국 각지에서 다채롭게 펼쳐지며 일상의 활력을 불어넣어 주고…

4시간 ago