引言
在房地产数据分析、市场趋势研判和购房决策支持中,二手房源数据是不可或缺的基础素材。某房产平台作为国内最大的房产交易平台之一,拥有覆盖全国主要城市的真实挂牌房源数据,房源信息结构化程度高------挂牌价、单价、户型、面积、楼层、朝向、装修、所属区域等字段一应俱全,是研究各城市房价走势的理想数据源。
然而,爬取该平台的数据远非易事。平台部署了严密的多维度反爬体系,核心是识别"非人类操作行为"。IP封禁、请求头校验、动态渲染、滑块验证四道防线层层递进,更隐蔽的是"数据污染"风险------部分低价代理IP已被平台标记,即便请求成功,返回的也可能是价格虚高、信息错乱的虚假数据。本文将系统介绍如何突破这些障碍,爬取二手房源数据并分析房价走势。
免责声明:本文仅限技术学习与交流,请勿将爬虫技术用于商业用途或对目标网站造成过大压力。2022年北京知识产权法院曾判决一起涉及房源数据抓取的不正当竞争案,被告被判赔偿500万元。请务必遵守平台规则和法律法规。

一、某房产平台反爬体系全景解析
在动手写代码之前,必须先搞清楚平台的反爬"防线"如何构建。
1.1 第一道防线:IP封禁与请求头校验
这是最直接、最有效的防御手段。平台会对同一IP短时间内频繁访问直接拉黑。同时,请求头中的User-Agent、Referer等字段如果缺失或不合法,请求会被直接拒绝。
实测表明,该平台对单IP的请求频率极为敏感------同一个IP地址短时间内频繁访问,轻则被限制访问,重则直接封禁IP。
1.2 第二道防线:动态渲染与JS混淆
这是目前最主流的手段。页面上的关键数据------房价、户型、面积------往往不是直接写在HTML里,而是通过JavaScript动态加载或计算生成的。直接用requests请求到的HTML源码中,这些数据要么是乱码,要么根本不存在。此外,用于生成请求参数的JavaScript代码经过混淆,增加了逆向难度。
1.3 第三道防线:行为检测与验证码
平台会检测访问行为是否像真人。过于规律的请求频率、缺少鼠标移动或点击事件、使用固定的User-Agent等,都可能触发验证码(滑块、点选等)或直接封锁会话。某房产平台更注重行为分析,会检测鼠标移动、点击模式等用户行为特征。
1.4 第四道防线:"数据污染"------最隐蔽的陷阱
这是最容易被忽视的一道防线。一些低价或免费的机房IP,自身已被平台标记为"爬虫IP"。即便请求频率控制得很好,平台也不会直接封你,而是返回虚假数据------价格虚高、房源信息错乱,让采集结果彻底报废。
1.5 反爬体系速览
| 反爬手段 | 具体表现 | 应对难度 |
|---|---|---|
| IP封禁 | 同一IP短时间多次访问,直接拉黑 | ⭐⭐ |
| 请求头验证 | 检查User-Agent、Referer等字段 | ⭐⭐⭐ |
| 动态加载数据 | 房源信息通过JS异步渲染 | ⭐⭐⭐⭐ |
| 人机验证 | 滑块验证码、点击验证码 | ⭐⭐⭐⭐⭐ |
| 数据污染 | 向可疑IP返回虚假房源信息 | 隐蔽性极强 |
二、技术选型:Playwright + Scrapy-Redis + 隧道代理
面对如此严密的防御体系,单靠requests + BeautifulSoup的"轻量方案"注定失败。我们需要一套工程化的解决方案。
2.1 为什么选择Playwright而非纯HTTP请求?
该平台的核心数据都是JS动态渲染的,纯HTTP请求拿不到完整内容。Playwright可以驱动真实Chrome浏览器,完整执行JavaScript,加载登录态和Cookie。在反爬严格的场景下,真实浏览器的通过率远高于纯HTTP请求。
2.2 为什么选择Scrapy-Redis做分布式?
Scrapy-Redis将Scrapy的调度器替换为Redis,支持多台机器共享同一个请求队列,天然支持分布式扩展。对于"爬取多城市、多区域、多页面的二手房数据"这一任务,分布式架构可以成倍提升采集效率。
2.3 为什么必须搭配隧道代理?
即使完美配置了浏览器和请求头,当采集规模扩大到多城市、多区域时,IP封禁依然不可避免。该平台的封锁策略是"按IP封禁"。
传统方案是自建代理IP池,但存在两个致命问题:一是免费代理可用率极低,二是低价机房IP已被平台标记,会返回污染数据 。隧道代理是更可靠的方案。你只需配置一个固定入口,后台自动切换出口IP,无需手动维护IP池。
站大爷隧道代理在该平台采集场景中的核心优势:
-
高匿性:让平台看不出你在用代理,避免触发数据污染
-
自动切换:每次请求自动更换出口IP,控制每个IP的访问频率在普通用户范围内
-
覆盖广泛:支持按城市定向,方便采集不同城市的房价数据
-
三种鉴权模式:白名单、用户名密码/白名单、用户名密码+白名单
三、爬虫实战:从接口到结构化数据
3.1 环境准备
pip install playwright scrapy scrapy-redis pandas
playwright install chromium
3.2 数据字段设计
该平台二手房列表页包含以下核心字段:
| 字段 | 说明 | 分析价值 |
|---|---|---|
| 房源标题 | 小区名+户型描述 | 识别房源 |
| 户型 | 室/厅/卫 | 户型分析 |
| 建筑面积 | 平方米 | 面积分布 |
| 朝向 | 南/北/东/西 | 偏好分析 |
| 装修情况 | 精装/简装/毛坯 | 品质分析 |
| 挂牌价格 | 总价(万) | 核心指标 |
| 单价 | 元/平米 | 核心指标 |
| 所属区域 | 区/板块 | 地域分析 |
3.3 核心爬虫实现
以下是一个基于Playwright + 隧道代理的采集实现:
from playwright.sync_api import sync_playwright
import time
import random
import pandas as pd
class HouseScraper:
def __init__(self, use_proxy=True):
self.use_proxy = use_proxy
# 站大爷隧道代理配置
if use_proxy:
self.proxy_config = {
"server": "http://用户名:密码@tps.zdaye.com:8080"
}
else:
self.proxy_config = None
self.user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0",
]
def scrape_city(self, city_url, max_pages=10):
"""采集指定城市的二手房数据"""
results = []
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False, # 有头模式更接近真实用户
proxy=self.proxy_config
)
context = browser.new_context(
user_agent=random.choice(self.user_agents),
viewport={"width": 1440, "height": 900}
)
# 注入反检测脚本
context.add_init_script("""
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
""")
page = context.new_page()
for page_num in range(1, max_pages + 1):
url = f"{city_url}/pg{page_num}/"
print(f"正在采集第{page_num}页...")
page.goto(url, wait_until="networkidle")
time.sleep(random.uniform(2, 4))
# 提取房源列表
items = page.query_selector_all(".sellListContent li")
for item in items:
try:
title = item.query_selector(".title a").inner_text()
total_price = item.query_selector(".totalPrice span").inner_text()
unit_price = item.query_selector(".unitPrice span").inner_text()
house_info = item.query_selector(".houseInfo").inner_text()
position = item.query_selector(".positionInfo").inner_text()
results.append({
"title": title.strip(),
"total_price": float(total_price.replace("万", "")),
"unit_price": int(unit_price.replace("元/平米", "").replace(",", "")),
"house_info": house_info.strip(),
"position": position.strip(),
"page": page_num
})
except Exception as e:
continue
print(f"第{page_num}页获取 {len(items)} 条")
# 随机延迟,规避频率检测
time.sleep(random.uniform(2, 5))
browser.close()
return results
def save_to_csv(self, data, filename="houses.csv"):
df = pd.DataFrame(data)
df.to_csv(filename, index=False, encoding="utf-8-sig")
print(f"数据已保存到 {filename},共 {len(data)} 条")
# 使用示例
if __name__ == "__main__":
scraper = HouseScraper(use_proxy=True)
# 采集北京二手房数据
data = scraper.scrape_city("https://bj.lianjia.com/ershoufang", max_pages=5)
scraper.save_to_csv(data, "beijing_houses.csv")
3.4 隧道代理在Playwright中的集成
在Playwright中集成站大爷隧道代理只需在启动浏览器时配置proxy参数。如果需要精细控制IP更换周期,可以通过period参数自定义:
self.proxy_config = {
"server": "http://用户名-period-300:密码@tps.zdaye.com:8080"
}
在Scrapy中,可以通过自定义Downloader Middleware实现代理轮换,将代理地址配置到settings.py中,Scrapy会在每个请求中自动使用隧道代理。
四、各城市房价走势分析
4.1 数据清洗
采集到的原始数据需要清洗:将总价(万)和单价(元/平米)转换为浮点数,从"houseInfo"字段中拆分户型、面积、朝向、装修等信息。
4.2 城市房价对比分析
import pandas as pd
import matplotlib.pyplot as plt
# 加载多城市数据
cities = ["beijing", "shanghai", "guangzhou", "shenzhen"]
all_data = []
for city in cities:
df = pd.read_csv(f"{city}_houses.csv")
df["city"] = city
all_data.append(df)
combined = pd.concat(all_data, ignore_index=True)
# 各城市平均单价对比
city_price = combined.groupby("city")["unit_price"].mean().sort_values(ascending=False)
print("各城市二手房平均单价(元/平米):")
print(city_price)
# 可视化
plt.figure(figsize=(10, 6))
city_price.plot(kind="bar", color=["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"])
plt.title("各城市二手房平均单价对比")
plt.ylabel("单价(元/平米)")
plt.xticks(rotation=0)
plt.tight_layout()
plt.savefig("city_price_comparison.png")
4.3 2025年房价走势的关键发现
根据平台公开数据,2025年百城二手房挂牌均价延续调整态势,各线城市全面普跌。二线城市(-9.74%)跌幅最深,厦门(-16.9%)、合肥(-15.58%)等城市价格调整剧烈。
进入2025年底,一线城市出现企稳信号。北京链家数据显示,政策调整后1个月,北京链家交易量较政策出台前增长33%。上海链家二手房成交量环比上涨15%,成交价暂时止住下跌趋势,出现"止跌"信号。上海链家研究院负责人表示,上海全市价格仍在调整周期,整体处于深度筑底过程中的高性价比房源出清阶段。
4.4 区域价格分化分析
同一城市内部,不同区域的价格分化同样显著。通过爬取各区域的房源数据,可以生成区域价格热力图,识别城市内部的"价值洼地"和"价格高地"。
五、常见问题与避坑指南
5.1 IP被封怎么办?
使用站大爷隧道代理自动切换IP。注意避免使用已被平台标记的低价机房IP,否则会被返回污染数据。
5.2 遇到滑块验证码怎么办?
使用Playwright的有头模式,配合隧道代理切换IP,降低验证码触发概率。首次运行时建议人工完成一次验证,后续复用Cookie和会话。
5.3 数据全是虚假的怎么办?
这是"数据污染"的表现。立即更换代理服务商,选择高匿住宅代理。低价或免费代理的IP大多已被平台标记。
5.4 法律与合规提醒
该平台的robots.txt规定了哪些页面可以被爬取。请遵守平台规则,控制请求频率,仅将数据用于学习和研究目的。
六、总结
本文从某房产平台的反爬体系入手,系统介绍了爬取二手房源数据、分析各城市房价走势的完整方案。
| 挑战 | 解决方案 |
|---|---|
| IP封禁 | 站大爷隧道代理,自动切换IP |
| 动态渲染 | Playwright驱动真实浏览器 |
| 行为检测 | 有头模式 + 随机延迟 + UA轮换 |
| 数据污染 | 高匿住宅代理,避免机房IP |
| 房价分析 | 数据清洗 + 城市对比 + 趋势可视化 |
技术选型速览 :推荐"Playwright + 站大爷隧道代理 + Scrapy-Redis"的组合方案。Playwright解决动态渲染,隧道代理解决IP封禁和数据污染,Scrapy-Redis支持分布式扩展。
该平台的二手房源数据是观察中国房地产市场的一扇窗口。通过合理的采集策略和数据分析方法,我们可以将这座数据金矿转化为可执行的洞察------哪些城市房价企稳、哪些区域存在价值洼地、市场成交量何时出现拐点。
最后需要提醒的是:数据采集行为应当遵循平台规则,控制请求频率以避免对目标服务器造成过载。请遵守相关法律法规,仅将爬虫技术用于学习和研究目的。