Skip to main content

Python client for Korean public real estate APIs

Project description

korea-real-estate

한국 공공 부동산 데이터 Python 클라이언트

Python library and CLI for querying Korean government real estate data: land sales, building permits, price trend indices, appraised values, zoning, and address resolution.

CI Lint PyPI Python License: MIT


Contents


Installation

pip install korea-real-estate

Python 3.11+ required.


Getting API Keys

Each data source requires a separate key from the Korean government data portal.

  1. Create an account at www.data.go.kr
  2. Search for each API and click 활용신청 (Apply for use)
  3. Copy your 서비스키 from 마이페이지 → 오픈API 활용현황
Env Var API Portal Link
SALES_HISTORY_API_KEY 토지 매매 실거래가 15126466
COMMERCIAL_SALES_API_KEY 상업용 부동산 매매 실거래가 15058017
BUILDING_PERMITS_API_KEY 건축인허가 정보 15044525
ZONING_API_KEY 토지이용계획 15113034
APPRAISED_VALUE_API_KEY 개별공시지가 (NSDI) 15057159
STANDARD_LAND_PRICE_API_KEY 표준지공시지가 15056649
BUILDING_REGISTRY_API_KEY 건축물대장 15044521
BUILDING_MAP_API_KEY 건물 공간정보 15058453
PRICE_TRENDS_API_KEY 한국부동산원 통계 (REB) reb.or.kr
ADDRESS_RESOLVER_API_KEY 주소 검색 (Juso) juso.go.kr

Keys from data.go.kr are URL-encoded. Use them as-is — do not re-encode.


Configuration

cp .env.example .env

.env:

# Historical transactions
SALES_HISTORY_API_KEY=your_key_here
COMMERCIAL_SALES_API_KEY=your_key_here
BUILDING_PERMITS_API_KEY=your_key_here

# Land parcel
ZONING_API_KEY=your_key_here
APPRAISED_VALUE_API_KEY=your_key_here
STANDARD_LAND_PRICE_API_KEY=your_key_here

# Building
BUILDING_REGISTRY_API_KEY=your_key_here
BUILDING_MAP_API_KEY=your_key_here

# Market trends (REB)
PRICE_TRENDS_API_KEY=your_key_here

# Address resolution (Juso)
ADDRESS_RESOLVER_API_KEY=your_key_here

# Defaults
DEFAULT_REGION_CODE=42820
REQUEST_TIMEOUT_SECONDS=30
MAX_RETRIES=3

Never commit .env — it is git-ignored.


Quick Start

from korea_realestate import KoreaRealEstateClient

client = KoreaRealEstateClient()

# Land sales last 6 months
df = client.events.get_land_sales(region_code="42820", start_year_month="202410", end_year_month="202503")

# Official appraised land value
df = client.land.get_appraised_value(region_code="42820", year=2024)

# Building registry
df = client.building.get_registry(region_code="42820")

# Market price trend
df = client.market.get_price_trends(region_code="42820", index_type="land", start_year_month="202401", end_year_month="202412")

# Resolve address
result = client.address.resolve("강원도 고성군 대진리 123")

Client Reference

KoreaRealEstateClient (master)

Single entry point. Instantiates and wires all domain clients with shared HTTP connections.

from korea_realestate import KoreaRealEstateClient

client = KoreaRealEstateClient()

client.events    # EventsClient
client.land      # LandClient
client.building  # BuildingClient
client.market    # MarketClient
client.address   # AddressClient

For testing, inject mock HTTP clients:

from unittest.mock import MagicMock
from korea_realestate.http import PublicDataClient, RebClient, JusoClient

client = KoreaRealEstateClient(
    public_data_client=MagicMock(spec=PublicDataClient),
    reb_client=MagicMock(spec=RebClient),
    juso_client=MagicMock(spec=JusoClient),
)

EventsClient — historical transactions

# Land sales
df = client.events.get_land_sales(
    region_code="42820",
    start_year_month="202401",
    end_year_month="202412",
    land_category="임",   # optional: 임 | 전 | 답 | 대 | …
    limit=50,             # most recent N rows
)
# columns: deal_date, region, dong, parcel, land_category, area_sqm,
#          price_10k_won, price_per_sqm, zoning, buyer_type, cancelled

# Commercial / factory / warehouse sales
df = client.events.get_commercial_sales(
    region_code="42820",
    start_year_month="202401",
    end_year_month="202412",
    property_type="상업용",  # optional
    limit=20,
)
# columns: deal_date, region, dong, building_use, land_area_sqm,
#          building_area_sqm, floors, build_year, price_10k_won

# Building permits
df = client.events.get_permit_history(
    region_code="42820",
    start_date="20240101",
    end_date="20241231",
    permit_type="신축",   # optional: 신축 | 증축 | 대수선 | 철거
    limit=10,
)
# columns: address, permit_type, main_use, site_area_sqm, building_area_sqm,
#          floor_area_ratio, coverage_ratio, permit_date, start_date, completion_date

LandClient — parcel data

# Zoning classification
df = client.land.get_zoning(region_code="42820", dong="대진리")
# columns: region, dong, parcel, land_category, zoning_class, area_sqm

# Official appraised land value (개별공시지가)
df = client.land.get_appraised_value(region_code="42820", year=2024)
# columns: region, dong, parcel, area_sqm, value_per_sqm, total_value, reference_year

# Standard land price (표준지공시지가)
df = client.land.get_standard_price(region_code="42820", year=2024)
# columns: region, dong, parcel, land_category, area_sqm, price_per_sqm,
#          reference_year, zoning, terrain, road_access

# Full parcel profile (all sources combined)
profile = client.land.get_full_profile(
    region_code="42820",
    history_limit=12,       # months of sales history
    nearby_radius_m=500,    # optional: include nearby parcels snapshot
)
# profile["parcel"]["zoning"]          → DataFrame
# profile["parcel"]["appraised_value"] → DataFrame
# profile["parcel"]["standard_price"]  → DataFrame
# profile["history"]["sales"]          → DataFrame
# profile["nearby"]                    → list | None

BuildingClient — building registry

# Building registry (건축물대장)
df = client.building.get_registry(
    region_code="42820",
    parcel_main="100",   # optional
    parcel_sub="5",      # optional
    ledger_type="표제부",  # 표제부 | 총괄표제부 | 층별개요 | 지역지구구역
)
# columns: address, building_name, main_use, structure,
#          floors_above, total_area_sqm, …

# Building map layer (GeoJSON)
geojson = client.building.get_map_layer(region_code="42820")
# geojson["type"] == "FeatureCollection"

# Permit history (delegates to EventsClient)
df = client.building.get_permit_history(
    region_code="42820",
    start_date="20240101",
    end_date="20241231",
)

# Full building profile
profile = client.building.get_full_profile(
    region_code="42820",
    history_limit=12,
    nearby_radius_m=None,
)
# profile["building"]["registry"]   → DataFrame
# profile["building"]["map_layer"]  → GeoJSON dict
# profile["history"]["permits"]     → DataFrame
# profile["nearby"]                 → list | None

MarketClient — price trends

# Land or housing price index (한국부동산원)
df = client.market.get_price_trends(
    region_code="42820",
    index_type="land",          # "land" or "housing"
    start_year_month="202401",
    end_year_month="202412",
    limit=12,
)
# columns: period, region, index_value, change_pct_mom, change_pct_yoy

# Commercial property comparables (delegates to EventsClient)
df = client.market.get_commercial_comps(
    region_code="42820",
    start_year_month="202401",
    end_year_month="202412",
)

# Full market profile
profile = client.market.get_full_profile(region_code="42820", history_limit=12)
# profile["trends"]["land"]              → DataFrame
# profile["trends"]["housing"]           → DataFrame
# profile["history"]["commercial_sales"] → DataFrame

AddressClient — address resolution

# Resolve one address
result = client.address.resolve("강원도 고성군 대진리 123")
# result: {road_addr, jibun_addr, zip, region_code, x, y, …}

# Batch resolve
results = client.address.resolve_many(["주소1", "주소2"])

# Get 5-digit 시군구 region code from address string
code = client.address.to_region_code("고성군 대진리")  # → "42820"

Error Handling

from korea_realestate.exceptions import (
    APIKeyError,          # missing, invalid, or expired key
    RateLimitError,       # daily call limit exceeded
    RegionNotFoundError,  # no data returned for region/period
    APIResponseError,     # unexpected HTTP or XML error
)

try:
    df = client.events.get_land_sales(region_code="42820", start_year_month="202401", end_year_month="202412")
except APIKeyError as e:
    print("Check your API key:", e)
except RateLimitError:
    print("Daily limit exceeded — try again tomorrow")
except RegionNotFoundError:
    print("No data for this region/period")
except APIResponseError as e:
    print("Unexpected API error:", e)

CLI Reference

Keys are read from .env automatically.

# Land sales
korea-realestate sales --region 42820 --from 202401 --to 202412 --land-category  --output sales.csv

# Commercial / factory / warehouse sales
korea-realestate commercial-sales --region 42820 --from 202401 --to 202412

# Building permits
korea-realestate permits --region 42820 --from 20240101 --to 20241231 --type 신축

# Zoning lookup
korea-realestate zoning --region 42820 --dong 대진리

# Official appraised land value
korea-realestate appraised-value --region 42820 --year 2024

# Price trend index
korea-realestate price-trends --region 42820 --type land --from 202401 --to 202412

# Building registry
korea-realestate building-registry --region 42820 --parcel 100-5

# Resolve address
korea-realestate resolve-address "강원도 고성군 대진리 123"

All commands accept --output <file.csv> to save results.


Running Tests

pip install "korea-real-estate[dev]"
pytest

Tests use respx to mock HTTP — no real API keys needed.


Region Codes

5-digit 시군구 codes (법정동코드 앞 5자리).

Region Code Region Code
고성군 (강원) 42820 속초시 42210
양양군 42830 인제군 42810
춘천시 42110 원주시 42130
강릉시 42150 동해시 42170
강남구 11230 서초구 11220
송파구 11240 용산구 11030
수원시영통구 41117 성남시분당구 41135
제주시 50110 서귀포시 50130
세종시 36110 해운대구 21090

Lookup helper:

from korea_realestate.utils import get_code

code = get_code("고성군")  # → "42820"
code = get_code("고성")    # → "42820" (fuzzy match)

API Reference Links

API Portal
Land Sales data.go.kr/15126466
Commercial Sales data.go.kr/15058017
Building Permits data.go.kr/15044525
Zoning data.go.kr/15113034
Appraised Value data.go.kr/15057159
Standard Land Price data.go.kr/15056649
Building Registry data.go.kr/15044521
Building Map data.go.kr/15058453
Price Trends (REB) reb.or.kr
Address (Juso) juso.go.kr

License

MIT — see LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

korea_real_estate-0.1.0.tar.gz (33.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

korea_real_estate-0.1.0-py3-none-any.whl (35.0 kB view details)

Uploaded Python 3

File details

Details for the file korea_real_estate-0.1.0.tar.gz.

File metadata

  • Download URL: korea_real_estate-0.1.0.tar.gz
  • Upload date:
  • Size: 33.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.9

File hashes

Hashes for korea_real_estate-0.1.0.tar.gz
Algorithm Hash digest
SHA256 de09dca1e1dc60458508e95834a98c9467b590914c18dfe3ba7e6b5edadf5f90
MD5 7adf8ba246defd9cb87ca84d580dffa0
BLAKE2b-256 af94a56bce0bd3584b6bac05165c981e53ec5c5329e197becb910fa629f940b0

See more details on using hashes here.

File details

Details for the file korea_real_estate-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for korea_real_estate-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1564d7566ca5201d011fb37e64054c4d7c35625698434d1ab3c1ebd88ac5cc2a
MD5 6abb47cd9cac4c4a238ff724b59cb458
BLAKE2b-256 cc8cec47506c9ead16d8da36173428ad11a99c4851c7c9bb25bf3f9da21f834c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page