Python爬虫实战㉙|综合实战4,房产数据采集与区域价值评估
·
author: 专注Python实战,分享爬虫与数据分析干货
title: Python爬虫实战㉙|综合实战4,房产数据采集与区域价值评估
update: 2026-04-26
tags: Python,爬虫实战,房产,数据分析,区域评估,价格预测,热力图,可视化
作者:专注Python实战,分享爬虫与数据分析干货
更新时间:2026年4月
适合人群:已学完全部基础、想做完整项目的开发者
前言:买房/租房前,先分析数据
在哪买房性价比最高?哪个区域涨幅最大?周边配套怎样?
爬虫采集房源 → 多维度评分 → 区域价值排行,用数据说话。
一、项目目标
1. 爬取房源数据(价格、面积、位置、配套等)
2. 数据清洗与特征工程
3. 区域价值评分模型
4. 可视化:价格热力图、区域排行、配套分析
5. 生成区域价值评估报告
二、数据爬取
2.1 房源爬虫
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
import re
class HouseCrawler:
"""房源数据爬虫"""
def __init__(self):
self.session = requests.Session()
self.data = []
def crawl_district(self, city_code, district, max_pages=5):
"""爬取某区域房源"""
for page in range(1, max_pages + 1):
url = f"https://example-house.com/{city_code}/{district}/pg{page}/"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"
}
try:
resp = self.session.get(url, headers=headers, timeout=15)
resp.raise_for_status()
resp.encoding = "utf-8"
soup = BeautifulSoup(resp.text, "html.parser")
items = soup.select(".house-item")
for item in items:
house = {
"标题": self._safe_text(item.select_one(".title")),
"小区": self._safe_text(item.select_one(".community")),
"区域": district,
"总价_万": self._parse_price(self._safe_text(item.select_one(".total-price"))),
"单价_元每平": self._parse_unit_price(self._safe_text(item.select_one(".unit-price"))),
"面积_平": self._parse_area(self._safe_text(item.select_one(".area"))),
"户型": self._safe_text(item.select_one(".layout")),
"朝向": self._safe_text(item.select_one(".orientation")),
"楼层": self._safe_text(item.select_one(".floor")),
"装修": self._safe_text(item.select_one(".decoration")),
"建筑年代": self._parse_year(self._safe_text(item.select_one(".build-year"))),
"标签": self._safe_text(item.select_one(".tags")),
}
self.data.append(house)
except Exception as e:
print(f" 爬取失败({district} p{page}): {e}")
time.sleep(random.uniform(2, 5))
def _safe_text(self, element):
return element.get_text(strip=True) if element else ""
def _parse_price(self, text):
match = re.search(r"([\d.]+)", text)
return float(match.group(1)) if match else None
def _parse_unit_price(self, text):
match = re.search(r"([\d,]+)", text)
if match:
return int(match.group(1).replace(",", ""))
return None
def _parse_area(self, text):
match = re.search(r"([\d.]+)平", text)
return float(match.group(1)) if match else None
def _parse_year(self, text):
match = re.search(r"(\d{4})", text)
return int(match.group(1)) if match else None
def to_dataframe(self):
df = pd.DataFrame(self.data)
df = df.drop_duplicates(subset=["标题", "小区"]).reset_index(drop=True)
return df
三、数据清洗与特征工程
import pandas as pd
import numpy as np
def clean_house_data(df):
"""房源数据清洗"""
# 1. 去除缺失关键字的行
df = df.dropna(subset=["总价_万", "面积_平", "区域"]).copy()
# 2. 异常值处理
# 面积 < 10 或 > 500 的剔除
df = df[(df["面积_平"] >= 10) & (df["面积_平"] <= 500)]
# 总价 < 10万 或 > 5000万 的剔除
df = df[(df["总价_万"] >= 10) & (df["总价_万"] <= 5000)]
# 单价异常
df = df[(df["单价_元每平"] >= 1000) & (df["单价_元每平"] <= 200000)]
# 3. 计算衍生特征
df["单价_元每平"] = df["单价_元每平"].fillna(df["总价_万"] * 10000 / df["面积_平"])
# 户型提取(几室几厅)
df["室"] = df["户型"].str.extract(r"(\d+)室").astype(float)
df["厅"] = df["户型"].str.extract(r"(\d+)厅").astype(float)
# 房龄
current_year = 2026
df["房龄"] = current_year - df["建筑年代"]
df["房龄"] = df["房龄"].clip(0, 50)
# 单价分档
df["价格档"] = pd.cut(df["单价_元每平"],
bins=[0, 20000, 40000, 60000, 100000, 200000],
labels=["2万以下", "2-4万", "4-6万", "6-10万", "10万以上"])
df = df.reset_index(drop=True)
return df
四、区域价值评分
class DistrictScorer:
"""区域价值评分模型"""
def __init__(self, df):
self.df = df
def score_all(self):
"""综合评分"""
district_stats = self.df.groupby("区域").agg(
均价=("单价_元每平", "mean"),
中位价=("单价_元每平", "median"),
房源数=("标题", "count"),
平均面积=("面积_平", "mean"),
平均房龄=("房龄", "mean"),
总价均值=("总价_万", "mean"),
).reset_index()
# 标准化评分(0-100)
for col in ["均价", "房源数"]:
district_stats[f"{col}_分"] = (
(district_stats[col] - district_stats[col].min())
/ (district_stats[col].max() - district_stats[col].min())
* 100
).round(1)
# 综合评分 = 价格权重*0.6 + 活跃度*0.4
district_stats["综合评分"] = (
district_stats["均价_分"] * 0.6 +
district_stats["房源数_分"] * 0.4
).round(1)
district_stats = district_stats.sort_values("综合评分", ascending=False)
return district_stats
五、可视化
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
def plot_district_ranking(scores):
"""区域价值排行"""
top = scores.head(15)
fig, ax = plt.subplots(figsize=(10, 7))
bars = ax.barh(top["区域"][::-1], top["综合评分"][::-1],
color=plt.cm.RdYlGn(np.linspace(0.3, 0.9, len(top))))
for bar, val in zip(bars, top["综合评分"][::-1]):
ax.text(bar.get_width() + 1, bar.get_y() + bar.get_height()/2,
f"{val:.1f}", va="center", fontsize=11)
ax.set_title("区域综合价值评分排行", fontsize=16, fontweight="bold")
ax.set_xlabel("综合评分", fontsize=12)
plt.tight_layout()
plt.savefig("district_ranking.png", dpi=150, bbox_inches="tight")
plt.show()
def plot_price_distribution(df):
"""价格分布对比"""
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
# 单价分布
top_districts = df["区域"].value_counts().head(6).index
for district in top_districts:
subset = df[df["区域"] == district]["单价_元每平"]
axes[0].hist(subset, bins=30, alpha=0.5, label=district)
axes[0].set_title("各区域单价分布")
axes[0].legend()
# 箱线图
top_df = df[df["区域"].isin(top_districts)]
sns.boxplot(data=top_df, x="区域", y="单价_元每平", ax=axes[1])
axes[1].set_title("各区域单价箱线图")
axes[1].set_xticklabels(axes[1].get_xticklabels(), rotation=30)
plt.tight_layout()
plt.savefig("price_distribution.png", dpi=150, bbox_inches="tight")
plt.show()
def plot_area_vs_price(df):
"""面积-价格散点图"""
plt.figure(figsize=(10, 6))
for district in df["区域"].value_counts().head(5).index:
subset = df[df["区域"] == district]
plt.scatter(subset["面积_平"], subset["总价_万"],
alpha=0.4, s=20, label=district)
plt.xlabel("面积(㎡)", fontsize=12)
plt.ylabel("总价(万)", fontsize=12)
plt.title("面积 vs 总价(按区域着色)", fontsize=16, fontweight="bold")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("area_vs_price.png", dpi=150, bbox_inches="tight")
plt.show()
六、生成评估报告
def generate_report(df, scores):
"""区域价值评估报告"""
report = f"""
╔══════════════════════════════════════╗
║ 房产区域价值评估报告 ║
╚══════════════════════════════════════╝
📊 市场概况
─────────────────────
房源总量: {len(df)}
涉及区域: {df['区域'].nunique()}
整体均价: ¥{df['单价_元每平'].mean():,.0f}/㎡
中位价: ¥{df['单价_元每平'].median():,.0f}/㎡
价格区间: ¥{df['单价_元每平'].min():,.0f} - ¥{df['单价_元每平'].max():,.0f}/㎡
🏆 区域价值TOP5
─────────────────────
"""
for i, row in scores.head(5).iterrows():
report += (
f" {row['区域']}: 评分{row['综合评分']:.1f} "
f"(均价¥{row['均价']:,.0f}/㎡, {int(row['房源数'])}套)\n"
)
report += """
📈 建议
─────────────────────
- 关注评分高且房源活跃的区域
- 对比同区域不同户型的性价比
- 注意房龄对价格的影响
"""
return report
print(generate_report(df, scores))
七、知识卡
| 模块 | 说明 |
|---|---|
| HouseCrawler | 房源数据爬虫 |
| clean_house_data() | 数据清洗+特征工程 |
| DistrictScorer | 区域价值评分 |
| plot_district_ranking | 区域排行图 |
| plot_price_distribution | 价格分布图 |
| pd.cut() | 价格分档 |
八、课后作业
必做题:
- 完成房源数据爬虫
- 实现数据清洗和特征工程
- 制作区域价值评分
选做题:
- 用线性回归预测房价
- 生成HTML评估报告
有问题欢迎评论区留言,大家一起讨论!
标签:Python | 爬虫实战 | 房产 | 数据分析 | 区域评估 | 可视化 | 评分模型
更多推荐
所有评论(0)