某房产平台爬虫:爬取二手房源数据,分析各城市房价走势

引言

在房地产数据分析、市场趋势研判和购房决策支持中,二手房源数据是不可或缺的基础素材。某房产平台作为国内最大的房产交易平台之一,拥有覆盖全国主要城市的真实挂牌房源数据,房源信息结构化程度高------挂牌价、单价、户型、面积、楼层、朝向、装修、所属区域等字段一应俱全,是研究各城市房价走势的理想数据源。

然而,爬取该平台的数据远非易事。平台部署了严密的多维度反爬体系,核心是识别"非人类操作行为"。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支持分布式扩展。

该平台的二手房源数据是观察中国房地产市场的一扇窗口。通过合理的采集策略和数据分析方法,我们可以将这座数据金矿转化为可执行的洞察------哪些城市房价企稳、哪些区域存在价值洼地、市场成交量何时出现拐点。

最后需要提醒的是:数据采集行为应当遵循平台规则,控制请求频率以避免对目标服务器造成过载。请遵守相关法律法规,仅将爬虫技术用于学习和研究目的。

相关推荐
深蓝电商API1 小时前
Celery 调度实践
爬虫·celery
数据狐(Datafox)6 小时前
京东商品列表API接口解析(附 JSON 样例)
数据库·爬虫·json
深蓝电商API1 天前
爬虫日志系统如何设计?
爬虫
2601_962300471 天前
学习Python 爬虫路线
爬虫·python·学习路线·数据解析·反爬虫
傻啦嘿哟2 天前
某招聘平台爬虫:爬取招聘岗位数据,分析各城市薪资水平
开发语言·爬虫·python
隐擎fox2 天前
深入理解网络传输层安全:TLS 指纹识别(JA3/JA4)原理与 Python 协议层检测实战
爬虫·python·网络协议·安全·网络安全·https
wuyk5552 天前
Python网络爬虫入门到实战 第01章:爬虫到底是什么?原理、流程、合法性、风险全解析(零基础必看)
开发语言·爬虫·python
SEO_juper2 天前
你的服务器正在被 AI 爬虫“白嫖“带宽:2026 用日志把 Googlebot 和 AI 洪流分开算账(附脚本)
运维·人工智能·爬虫·python·chatgpt·seo
m0_547486663 天前
《Python爬虫大数据采集与挖掘》全套PPT课件2026
爬虫·python·powerpoint