"このアパート、今買ってもいいですか?"
この質問に答えるためには、結局データが必要です。実際の取引価格の推移、周辺の相場、賃貸価格率、取引量の変化など、感覚ではなく数字で判断する必要があります。不動産投資家、プロプテックスタートアップ、不動産仲介業者、学術研究者は皆、同じ悩みを抱えています: "どうやってこのデータを自動的に集めることができるか?"
この記事では、不動産の実際の取引価格データを収集するための3つの方法を紹介します:
- 公共API — 国土交通部の実際の取引価格公開API(無料、最も安全)
- 直接クローリング — ネイバー不動産などのウェブサイトをクロール(技術的に難しい)
- 専門サービス — クローリングサービスを活用した自動収集(最も便利)
それぞれの方法の利点、欠点、実際のPythonコード、トラブルシューティング、法的注意事項までをまとめます。
目次
- 不動産データはどこにあるか?
- 方法 1: 国土交通部公共APIの活用
- 方法 2: ネイバー不動産クローリング
- 方法 3: 専門クローリングサービスの活用
- 収集したデータの活用 — 分析と可視化
- トラブルシューティング — よく発生する問題と解決法
- 法的注意事項
- よくある質問 (FAQ)
不動産データはどこにあるか?
韓国の不動産取引データは複数の出所から提供されます。目的に応じて適切な出所が異なります。
1. 国土交通部実際の取引価格公開システム
URL: rt.molit.go.kr
国土交通部が運営する公式の実際の取引価格データです。不動産取引が報告されると、このシステムに公開されます。
提供データ:
- アパート、連棟/多世帯、一戸建て/多戸建ての売買・賃貸
- オフィステルの売買・賃貸
- 土地、分譲/入居権、商業/業務用取引
- 取引日、取引金額、面積、階数、建築年など
公共データポータルAPI:
公共データポータル(data.go.kr)で国土交通部実際の取引価格APIを無料で利用できます。APIキーを取得すればプログラミングでデータを自動収集できます。
利点: 公式データ、無料、法的リスクなし
欠点: 実際の取引価格のみ提供(相場・物件情報なし)、更新に遅れあり
2. ネイバー不動産
URL: land.naver.com
実際の取引価格データだけでなく、物件情報、相場、学区、周辺インフラなど最も豊富な追加情報を提供します。
提供データ:
- 実際の取引価格(国土交通部データベースを基に)
- 現在の物件情報(価格、物件タイプ)
- 相場情報(KB価格、ネイバー独自の推定価格)
- ビル情報(戸数、駐車、管理費など)
- 学区および周辺施設情報
利点: データが豊富、ユーザーフレンドリー
欠点: クローリングの難易度が高い、利用規約制限あり
3. ジクバン / ダバン
URL: zigbang.com / dabangapp.com
ワンルーム、ツールームなど小規模住宅を中心とした物件情報に強みがあります。特に賃貸市場データが豊富です。
利点: 小規模住宅/賃貸データが豊富
欠点: アパート売買データはネイバー不動産より少ない
4. 韓国不動産院(旧 韓国評価院)
URL: reb.or.kr
不動産価格動向、賃貸/売買価格指数などの統計データを提供します。R-ONE不動産統計情報システムを通じてさまざまな統計にアクセスできます。
利点: 公式統計、価格指数提供
欠点: 個別取引データではなく集計統計
方法 1: 国土交通部公共APIの活用
最も正統で安定した方法です。公共データなので法的リスクはありません。
ステップ 1: APIキーの取得
- 公共データポータルに登録
- "国土交通部アパート売買実際取引資料"を検索
- "利用申請"をクリック → 利用目的を入力
- APIキーを取得(通常、即日〜1日かかる)
ヒント: APIキーはエンコードされたキー(Encoding)とデコードされたキー(Decoding)の2つが発行されます。Pythonではデコードされたキーを使用すると便利です。エンコードされたキーを使用すると、requestsライブラリが二重エンコードしてエラーが発生する可能性があります。
主要APIリスト
| API名 | 説明 | サービスコード |
|---|---|---|
| アパート売買実際取引資料 | アパート売買実際取引価格 | getRTMSDataSvcAptTrade |
| アパート前月賃貸資料 | アパート前月賃貸取引価格 | getRTMSDataSvcAptRent |
| 連棟多世帯売買実際取引資料 | マンション・連棟売買価格 | getRTMSDataSvcRHTrade |
| オフィステル売買実際取引資料 | オフィステル売買価格 | getRTMSDataSvcOffiTrade |
| 一戸建て/多戸建て売買実際取引資料 | 一戸建て住宅売買価格 | getRTMSDataSvcSHTrade |
| 土地売買実際取引資料 | 土地取引価格 | getRTMSDataSvcLandTrade |
Pythonコード — アパート売買実際取引価格の取得
import requests
import xml.etree.ElementTree as ET
import pandas as pd
# API 설정 — 디코딩된 키를 사용하세요
SERVICE_KEY = "발급받은_디코딩_API_키"
BASE_URL = "http://openapi.molit.go.kr/OpenAPI_ToolInstall/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade"
def get_apt_trade(lawd_cd: str, deal_ymd: str) -> pd.DataFrame:
"""
아파트 매매 실거래가를 조회합니다.
Args:
lawd_cd: 법정동 앞 5자리 코드 (예: "11680" = 서울 강남구)
deal_ymd: 계약년월 (예: "202601")
Returns:
거래 데이터가 담긴 DataFrame
"""
params = {
"serviceKey": SERVICE_KEY,
"LAWD_CD": lawd_cd,
"DEAL_YMD": deal_ymd,
"numOfRows": "9999",
"pageNo": "1"
}
response = requests.get(BASE_URL, params=params, timeout=30)
response.raise_for_status()
root = ET.fromstring(response.text)
# 에러 체크
result_code = root.find(".//resultCode")
if result_code is not None and result_code.text != "00":
result_msg = root.find(".//resultMsg")
raise Exception(f"API 오류: {result_msg.text if result_msg is not None else 'Unknown'}")
items = root.findall(".//item")
if not items:
return pd.DataFrame()
data = []
for item in items:
row = {}
for child in item:
text = child.text.strip() if child.text else ""
row[child.tag] = text
data.append(row)
return pd.DataFrame(data)
# 사용 예시: 서울 강남구(11680) 2026년 1월 거래 조회
df = get_apt_trade("11680", "202601")
print(f"조회된 거래 수: {len(df)}")
if not df.empty:
# 거래금액 정수 변환 (쉼표와 공백 제거)
df["거래금액_만원"] = df["거래금액"].str.replace(",", "").str.strip().astype(int)
print(df[["거래금액_만원", "아파트", "전용면적", "층"]].head(10))
ソウル全体の区別ごとの年間データの収集
import time
# 서울시 구별 법정동 앞 5자리 코드
SEOUL_CODES = {
"강남구": "11680", "서초구": "11650", "송파구": "11710",
"강동구": "11740", "마포구": "11440", "용산구": "11170",
"성동구": "11200", "광진구": "11215", "중구": "11140",
"종로구": "11110", "영등포구": "11560", "동작구": "11590",
"관악구": "11620", "강서구": "11500", "양천구": "11470",
"구로구": "11530", "금천구": "11545", "노원구": "11350",
"도봉구": "11320", "강북구": "11305", "성북구": "11290",
"동대문구": "11230", "중랑구": "11260", "은평구": "11380",
"서대문구": "11410"
}
def collect_seoul_yearly(year: int) -> pd.DataFrame:
"""서울시 전체 구의 1년치 아파트 매매 데이터를 수집합니다."""
all_data = []
months = [f"{year}{m:02d}" for m in range(1, 13)]
total = len(SEOUL_CODES) * len(months)
count = 0
for gu_name, code in SEOUL_CODES.items():
for month in months:
count += 1
try:
df = get_apt_trade(code, month)
if not df.empty:
df["구"] = gu_name
all_data.append(df)
print(f"[{count}/{total}] {gu_name} {month}: {len(df)}건")
except Exception as e:
print(f"[{count}/{total}] {gu_name} {month}: {e}")
time.sleep(0.3) # API 호출 간격
if all_data:
result = pd.concat(all_data, ignore_index=True)
return result
return pd.DataFrame()
# 2025년 전체 데이터 수집
result = collect_seoul_yearly(2025)
result.to_csv("서울_아파트_실거래가_2025.csv", index=False, encoding="utf-8-sig")
print(f"\n총 {len(result)}건 수집 완료!")
公共APIの制限
公共APIは安定していますが、制約があります:
| 制約 | 説明 |
|---|---|
| データ範囲 | 実際の取引価格と基本情報のみ提供。相場、物件情報などの追加情報なし |
| 更新遅延 | リアルタイムではなく、報告後数日〜数週間後に反映 |
| 呼び出し制限 | 1日のAPI呼び出し回数制限(通常1,000回/日、申請で拡大可能) |
| データ形式 | 基本的にXML形式の応答(一部APIはJSONもサポート) |
| 地域コード | 法定区域コードを別途管理する必要がある |
| API URL変更 | 公共データポータルAPIのURLが断続的に変更される |
方法 2: ネイバー不動産クローリング
公共APIよりも豊富なデータが必要な場合に考慮できます。相場、物件、ビル情報など、公共APIでは提供されないデータを収集できます。
ネイバー不動産の内部API
ネイバー不動産はフロントエンドから内部APIを呼び出してデータをレンダリングしています。ブラウザの開発者ツール(F12 → ネットワークタブ)でこのAPI呼び出しを確認できます。
主要エンドポイント(変更される可能性があります):
# 단지 기본 정보
GET https://fin.land.naver.com/complexes/{complexNo}
# 단지 매물 목록
GET https://fin.land.naver.com/complexes/{complexNo}/articles
# 단지 실거래가
GET https://fin.land.naver.com/complexes/{complexNo}/real-estates/trades
# 지역별 단지 목록
GET https://fin.land.naver.com/front-api/v1/complex/marker
Pythonコード例 — ネイバー不動産のビル情報
import requests
import json
import time
def get_naver_complex(complex_no: str) -> dict | None:
"""
네이버 부동산에서 아파트 단지 정보를 조회합니다.
주의: 네이버 내부 API는 수시로 변경될 수 있습니다.
이 코드가 동작하지 않으면 브라우저 개발자 도구에서
최신 API 엔드포인트를 확인하세요.
"""
url = f"https://fin.land.naver.com/complexes/{complex_no}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
"Referer": "https://land.naver.com/",
"Accept": "application/json"
}
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
return response.json()
else:
print(f"HTTP {response.status_code}: {complex_no}")
return None
except requests.exceptions.JSONDecodeError:
# HTML이 반환된 경우 (API 변경 가능성)
print(f"JSON 파싱 실패 — API 엔드포인트가 변경되었을 수 있습니다")
return None
except requests.exceptions.RequestException as e:
print(f"요청 실패: {e}")
return None
クローリング時に直面する現実的な問題
ネイバー不動産のクローリングは理論的には簡単ですが、実際には継続的なメンテナンスが必要です:
- APIエンドポイントの変更: ネイバーは内部APIのURLを頻繁に変更します。昨日動作したコードが今日壊れる可能性があります。
- 認証トークン: 一部のデータにはセッショントークンや別個の認証が必要で、トークンの更新ロジックを実装する必要があります。
- IPブロック: 短時間に多くのリクエストを送信するとIPがブロックされます。プロキシローテーションが必要な場合があります。
- JavaScriptレンダリング: 一部のページはサーバーサイドレンダリングではなくクライアントレンダリングを使用しているため、SeleniumやPlaywrightなどのブラウザ自動化ツールが必要です。
- 利用規約: ネイバーの利用規約では自動化手段によるデータ収集を禁止しています。クローリングの法的問題については別の記事を参照してください。
方法 3: 専門クローリングサービスの活用
公共APIの制限を超えつつ、直接クローリングのメンテナンス負担を避けるには、専門クローリングサービスが現実的な選択肢です。
3つの方法の比較
| 項目 | 公共API | 直接クローリング | 専門サービス |
|---|---|---|---|
| 初期構築 | 数日 | 数週間〜数ヶ月 | 即時 |
| データ範囲 | 実際の取引価格のみ | 相場+物件+追加情報 | 相場+物件+追加情報 |
| メンテナンス | ほぼなし | 多い(API変更への対応) | サービスで管理 |
| 法的リスク | なし | あり | サービスで管理 |
| コスト | 無料 | 開発/運用人件費 | サービス利用料 |
| IPブロックリスク | なし | 高い | なし |
| データ品質 | 高い(公式データ) | 変動的 | 高い |
| 拡張性 | 制限的 | 直接実装が必要 | 高い |
ハッシュスクレイパーで不動産データ収集
ハッシュスクレイパーは不動産関連データ収集に豊富な経験を持っています:
- ネイバー不動産データ: 地域/タイプ別の物件リスト、価格、面積、階数、ビル情報を自動収集
- 実際の取引価格統合収集: 複雑な公共API呼び出しを簡単なインターフェースで提供
- 相場変動モニタリング: 定期的に相場変動を追跡して通知を提供
- Excel/API連携: 収集したデータをExcelでダウンロードしたり、REST APIで既存システムに連携
自前のクローラを構築するとAPI変更への対応、IPブロック処理、データクリーニングに絶えず時間を費やす必要がありますが、専門




