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.2.0.tar.gz (18.4 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.2.0-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: korea_real_estate-0.2.0.tar.gz
  • Upload date:
  • Size: 18.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for korea_real_estate-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9a315f469a0aabb9104d8b83361332fdf13cf84aa1c975fb0df87f936d3bf14a
MD5 655f83c2801514328f8a7c575b90d59b
BLAKE2b-256 2676d4ae7cc0944d106a6fe95a17ab6ea3f6976dd0d7412b4c1e80844177e0df

See more details on using hashes here.

Provenance

The following attestation bundles were made for korea_real_estate-0.2.0.tar.gz:

Publisher: publish.yml on tlee0818/korea-real-estate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for korea_real_estate-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1f3d240f419374057927860e7e1034f3c08232f92bde7ef20455ed245da2da2a
MD5 2f20beef75ce00e4404793afbae7c675
BLAKE2b-256 04f0475efea1db45919116f3bb6c30cc09de4e0ffc49bc2a83d274724bfbfa11

See more details on using hashes here.

Provenance

The following attestation bundles were made for korea_real_estate-0.2.0-py3-none-any.whl:

Publisher: publish.yml on tlee0818/korea-real-estate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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