"这个公寓,现在可以买吗?"
要回答这个问题,最终需要数据。需要以数字而不是直觉来判断实际交易价格趋势、周边市场价格、租金比率、交易量变化。房地产投资者、房地产科技初创公司、房地产经纪机构、学术研究人员都面临同样的问题:“如何自动收集这些数据?”
本文将介绍三种收集房地产实际交易价格数据的方法:
- 公共API — 国土交通部公开的实际交易价格API(免费,最安全)
- 直接爬取 — 爬取网站如Naver房地产等(技术难度高)
- 专业服务 — 利用爬虫服务进行自动收集(最便捷)
将总结每种方法的优缺点、实际Python代码、故障排除以及法律注意事项。
目录
- 房地产数据存放在哪里?
- 方法1:利用国土交通部公共API
- 方法2:爬取Naver房地产
- 方法3:利用专业爬虫服务
- 收集的数据如何应用 — 分析和可视化
- 故障排除 — 常见问题及解决方法
- 法律注意事项
- 常见问题(FAQ)
房地产数据存放在哪里?
韩国的房地产交易数据来自多个来源。根据目的,适合的来源也不同。
1. 国土交通部实际交易价格公开系统
网址: rt.molit.go.kr
这是国土交通部运营的官方实际交易价格数据。房地产交易报告后将公开在该系统中。
提供的数据:
- 公寓、联排/独栋、多户住宅的买卖·租赁
- 办公室出售·出租
- 土地、分销/入住权、商业/办公用途交易
- 交易日期、交易金额、面积、楼层、建筑年份等
公共数据门户API:
在公共数据门户(data.go.kr)上可以免费使用国土交通部实际交易价格API。只需获取API密钥,就可以通过编程自动收集数据。
优点: 官方数据、免费、没有法律风险
缺点: 只提供实际交易价格(没有市场价格·房源信息),更新有延迟
2. Naver房地产
网址: land.naver.com
除了实际交易价格数据外,还提供房源信息、市场价格、学区、周边基础设施等最丰富的附加信息。
提供的数据:
- 实际交易价格(基于国土交通部数据)
- 当前房源信息(挂牌价、房源类型)
- 市场价格信息(KB市场价、Naver自家估价)
- 小区信息(户数、停车、管理费等)
- 学区及周边设施信息
优点: 数据丰富、用户友好
缺点: 爬取难度高、受使用条款限制
3. Zigbang / Dabang
网址: zigbang.com / dabangapp.com
擅长小型住宅(如单间、双间)的房源信息。尤其是租赁市场数据丰富。
优点: 小型住宅/租赁数据丰富
缺点: 公寓买卖数据比Naver房地产少
4. 韩国房地产院(原韩国评估院)
网址: reb.or.kr
提供房地产价格趋势、租赁/买卖价格指数等统计数据。通过R-ONE房地产统计信息系统可以访问各种统计数据。
优点: 官方统计数据、提供价格指数
缺点: 不是个别交易数据,而是汇总统计
方法1:利用国土交通部公共API
这是最正统且稳定的方法。由于是公共数据,因此没有法律风险。
步骤1:获取API密钥
- 在公共数据门户上注册
- 搜索“国土交通部公寓买卖实际交易数据”
- 点击“申请使用” → 输入用途
- 获取API密钥(通常需要1天内)
提示: API密钥分为编码密钥(Encoding)和解码密钥(Decoding)两种。在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稳定,但有一些限制:
| 限制 | 描述 |
|---|---|
| 数据范围 | 仅提供实际交易价格和基本信息。没有市场价格、房源等附加信息 |
| 更新延迟 | 不是实时的,而是报告后数日至数周才反映 |
| 调用限制 | 有每日API调用次数限制(通常为1,000次/日,可申请扩大) |
| 数据格式 | 默认为XML格式响应(部分API支持JSON) |
| 地区代码 | 需要单独管理法定区代码 |
| API URL更改 | 公共数据门户API URL会不时更改 |
方法2:爬取Naver房地产
当需要更丰富的数据时,可以考虑Naver房地产的爬取。可以收集公共API不提供的市场价格、房源信息等数据。
Naver房地产的内部API
Naver房地产通过前端调用内部API来渲染数据。您可以在浏览器开发者工具(F12 → Network标签)中查看这些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示例代码 — Naver房地产小区信息
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
爬取时面临的现实问题
Naver房地产的爬取在理论上很简单,但实际上需要持续维护:
- API端点更改: Naver经常更改内部API URL。昨天可以正常运行的代码,今天可能就无法正常工作。
- 认证令牌: 一些数据需要会话令牌或额外认证,需要实现令牌更新逻辑。
- IP封锁: 如果在短时间内发送大量请求,IP可能会被封锁。可能需要代理轮换。
- JavaScript渲染: 一些页面使用客户端渲染而不是服务器端渲染,需要使用Selenium或Playwright等浏览器自动化工具。
- 使用条款: Naver的使用条款禁止使用自动化手段进行数据收集。有关爬取法律问题的详细信息,请参考单独的文章。
方法3:利用专业爬虫服务
克服了公共API的限制,同时避免了直接爬取的维护负担,使用专业爬虫服务是现实选择。
三种方法对比
| 项目 | 公共API | 直接爬取 | 专业服务 |
|---|---|---|---|
| 初始建设 | 数日 | 数周~数月 | 即刻 |
| 数据范围 | 仅提供实际交易价格 | 市场价格+房源+附加信息 | 市场价格+房源+附加信息 |
| 维护 | 几乎没有 | 多(应对API更改) | 由服务方管理 |
| 法律风险 | 无 | 有 | 由服务方管理 |
| 成本 | 免费 | 开发/运营人员成本 | 服务费用 |
| IP封锁风险 | 无 | 高 | 无 |
| 数据质量 | 高(官方数据) | 可变 | 高 |
| 可扩展性 | 有限 | 需要自行实现 | 高 |
使用HashScraper收集房地产数据
HashScraper在收集房地产相关数据方面拥有丰富的经验:
- Naver房地产数据: 自动收集区域/类型的房源列表、挂牌价、面积、楼层、小区信息
- 整合实际交易价格: 通过简单接口提供复杂的公共API调用
- 监控市场价格变动: 定期跟踪市场价格变动并提供通知
- Excel/API集成: 将收集的数据下载到Excel或通过REST API集成到现有系统中
如果自行构建爬虫程序,需要不断应对API更改、IP封锁处理、数据清洗,而使用专业服务则可以将注意力集中在数据分析上。
想了解更多有关房地产数据收集?通过联系我们进行咨询。
收集的数据如何应用 — 分析和可视化
一旦收集了数据,现在该通过分析提取价值了。
基本分析: 按区域价格趋势
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
# 한글 폰트 설정
matplotlib.rcParams['font.family'] = 'AppleGothic' # macOS
# matplotlib.rcParams['font.family'] = 'Malgun Gothic' # Windows
matplotlib.rcParams['axes.unicode_minus'] = False
# 데이터 로드 및 전처리
df = pd.read_csv("서울_아파트_실거래가_2025.csv")
df["거래금액_만원"] = (
df["거래금액"].astype(str).str.replace(",", "").str.strip().astype(int)
)
df["거래월"] = df["년"].astype(str) + "-" + df["월"].astype(str).str.zfill(2)
# 구별 월평균 매매가
monthly = df.groupby(["구", "거래월"])["거래금액_만원"].mean().reset_index()
# 강남 3구 비교 그래프
fig, ax = plt.subplots(figsize=(12, 6))
for gu in ["강남구", "서초구", "송파구"]:
data = monthly[monthly["구"] == gu].sort_values("거래월")
ax.plot(data["거래월"], data["거래금액_만원"] / 10000, marker="o", label=gu)
ax.set_title("강남 3구 아파트 평균 매매가 추이 (2025)", fontsize=14)
ax.set_xlabel("거래월")
ax.set_ylabel("평균 매매가 (억 원)")
ax.legend()
ax.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig("강남3구_매매가_추이.png", dpi=150)
plt.show()
高级分析: 计算租售比
租售比(租金/买卖价格 × 100)是房地产投资中的关键指标。租售比越高,差价投资吸引力越高,越低则可能表示买卖市场过热。
def analyze_jeonse_rate(trade_file: str, rent_file: str, gu: str) -> pd.DataFrame:
"""
특정 구의 아파트별 전세가율을 계산합니다.
전세가율 = 전세 보증금 / 매매가 × 100
"""
trade = pd.read_csv(trade_file)
rent = pd.read_csv(rent_file)
# 해당 구 필터링
trade = trade[trade["구"] == gu].copy()
rent = rent[rent["구"] == gu].copy()
# 금액 정수 변환
trade["매매가"] = trade["거래금액"].astype(str).str.replace(",", "").str.strip().astype(int)
rent["보증금"] = rent["보증금액"].astype(str).str.replace(",", "").str.strip().astype(int)
# 전세만 필터링 (월세 제외: 월세금액이 0인 경우)
rent = rent[rent["월세금액"].astype(str).str.strip().replace("", "0").astype(int) == 0]
# 아파트별 평균가
avg_trade = trade.groupby("아파트")["매매가"].mean()
avg_rent = rent.groupby("아파트")["보증금"].mean()
# 전세가율 계산
common = avg_trade.index.intersection(avg_rent.index)
rates = pd.DataFrame({
"아파트": common,
"평균매매가_만원": avg_trade[common].values,
"평균전세가_만원": avg_rent[common].values,
})
rates["전세가율"] = (rates["평균전세가_만원"] / rates["평균매매가_만원"] * 100).round(1)
rates = rates.sort_values("전세가율", ascending=False)
return rates
# 강남구 전세가율 분석
rates = analyze_jeonse_rate(
"서울_아파트_매매_2025.csv",
"서울_아파트_전세_2025.csv",
"강남구"
)
print(rates.head(20))
数据应用案例
| 用户 | 应用目的 | 所需数据 |
|---|---|---|
| 个人投资者 | 判断购买时机,选择投资区域 | 实际交易价格趋势,租售比,交易量 |
| 房地产科技初创公司 | 价格预测模型,自动估价 | 大量实际交易价格,市场价格,小区信息 |
| 房地产经纪机构 | 房源比较,客户咨询资料 | 当前房源,实际交易价格,市场价格 |
| 学术研究 | 住房价格决定因素分析 | 实际交易价格+人口/经济数据 |
| 金融机构 | 抵押评估,风险管理 | 市场价格,实际交易价格,价格指数 |
故障排除 — 常见问题及解决方法
与公共API相关
问题1: 出现"SERVICE_KEY_IS_NOT_REGISTERED_ERROR"错误
→ 使用编码密钥,同时requests进行了双重编码。请使用解码密钥。
问题2: 出现"LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR"错误
→ 超过了每日调用限制。您可以在公共数据门户上申请增加流量或等到第二天再尝试。
问题3: 返回的数据为0
→ 请检查地区代码(LAWD_CD)是否正确。只使用法定区代码的前5位。此外,该月份可能没有交易。
问题4: API URL已更改
→ 请查看公共数据门户上该API的详细页面。URL结构可能会定期更改。查看API详细页面上的"请求地址(Endpoint)"是最准确的。
与Naver房地产爬取相关
问题1: 收到403 Forbidden响应
→ 用户代理标头缺失或IP被封锁。请设置适当的标头,并延长请求间隔。
问题2: JSON解析失败(返回HTML)
→ API端点可能已更改。请在浏览器开发者工具中查看最新URL。
问题3: 数据仅部分返回
→ 可能需要分页的API。请检查页面和大小参数。
法律注意事项
在收集房地产数据时,务必考虑法律问题。
公共API — 安全
通过国土交通部公共API收集的实际交易价格数据是公共数据。根据《公共数据的提供和利用激活法》(公共数据法),任何人都可以自由使用以营利或非营利目的。但是必须遵




