☰
Python爬虫实战:Q房网二手房数据采集与反爬策略
2026/10/14 11:15:40 网站建设 项目流程

1. 项目背景与核心价值

最近在帮朋友分析某城市二手房市场时,发现手动收集数据效率太低。作为技术从业者,自然想到用爬虫自动化解决这个问题。Q房网作为国内头部房产平台,其二手房数据具有典型性和参考价值。这个项目就是通过Python技术栈实现对Q房网二手房数据的自动化采集。

从技术角度看,这个爬虫需要解决几个关键问题:如何绕过网站反爬机制、如何高效解析动态加载内容、如何设计合理的存储结构。从业务角度看,采集到的数据可以用于价格趋势分析、房源特征挖掘、区域价值评估等场景。相比人工收集,自动化爬虫能将数据采集效率提升数十倍。

2. 技术方案设计

2.1 整体架构设计

爬虫系统采用经典的三层架构:

  1. 数据采集层:负责页面请求和响应获取
  2. 数据处理层:负责页面解析和数据清洗
  3. 数据存储层:负责结构化数据持久化

具体技术选型如下:

  • 请求库:Requests + aiohttp(异步提升效率)
  • 解析库:BeautifulSoup + PyQuery(互补使用)
  • 反反爬方案:随机UA + 代理IP池 + 请求频率控制
  • 存储方案:MySQL + CSV双备份

2.2 关键问题解决方案

对于动态加载内容,通过分析XHR请求发现,房源列表采用分页接口:

/api/house/list?page=2&size=20

使用Postman测试确认接口返回规范的JSON数据,这比解析DOM更可靠。

对于反爬机制,实测发现Q房网主要采用以下防护措施:

  • Cookie验证(特别是__jsluid_h参数)
  • 请求频率检测(单IP超过10次/分钟会触发验证)
  • 行为特征检测(如鼠标移动轨迹)

我们的应对策略:

  1. 使用selenium模拟真人操作获取初始Cookie
  2. 搭建代理IP池(实测需要至少50个可用IP)
  3. 随机化请求间隔(3-8秒浮动)

3. 核心代码实现

3.1 请求模块封装

import random import asyncio from aiohttp import TCPConnector class RequestHandler: def __init__(self): self.proxy_pool = self._init_proxies() self.user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15' ] async def fetch(self, url, session): proxy = random.choice(self.proxy_pool) headers = { 'User-Agent': random.choice(self.user_agents), 'Referer': 'https://www.qfang.com' } try: async with session.get(url, proxy=proxy, headers=headers) as response: await asyncio.sleep(random.uniform(3, 8)) return await response.text() except Exception as e: print(f"Request failed: {str(e)}") return None

3.2 数据解析模块

房源详情页需要提取20+个字段,包括:

  • 基础信息:标题、总价、单价、面积
  • 位置信息:小区、区域、地铁、坐标
  • 房屋特征:朝向、楼层、装修、年代
  • 交易属性:挂牌时间、带看次数

使用XPath和CSS选择器混合提取:

def parse_detail(html): doc = PyQuery(html) item = {} # 基础信息 item['title'] = doc('.house-title h1').text() item['total_price'] = doc('.price-total').text().replace('万', '') item['unit_price'] = doc('.price-unit').text().replace('元/㎡', '') # 使用更稳健的XPath提取复杂字段 item['build_year'] = html.xpath('//li[contains(text(),"建筑年代")]/span/text()')[0] item['orientation'] = html.xpath('//li[contains(text(),"房屋朝向")]/span/text()')[0] # 处理特殊字段 subway_info = doc('.subway-info').text() item['subway_distance'] = re.search(r'距离(\d+)号线', subway_info).group(1) return item

4. 存储方案优化

4.1 数据库设计

创建包含所有字段的houses表:

CREATE TABLE `houses` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `title` varchar(100) DEFAULT NULL, `total_price` decimal(10,2) DEFAULT NULL, `unit_price` decimal(10,2) DEFAULT NULL, `area` decimal(6,2) DEFAULT NULL, `community` varchar(50) DEFAULT NULL, `district` varchar(20) DEFAULT NULL, `subway` varchar(30) DEFAULT NULL, `build_year` year(4) DEFAULT NULL, `orientation` varchar(10) DEFAULT NULL, `floor` varchar(20) DEFAULT NULL, `layout` varchar(15) DEFAULT NULL, `listing_date` date DEFAULT NULL, `view_count` int(11) DEFAULT NULL, `url` varchar(255) DEFAULT NULL, `crawl_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_district` (`district`), KEY `idx_price` (`unit_price`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

4.2 批量插入优化

使用executemany配合事务提升写入性能:

def batch_insert(conn, items): sql = """INSERT INTO houses(title,total_price,...,url) VALUES(%s,%s,...,%s)""" try: with conn.cursor() as cursor: cursor.executemany(sql, [ (item['title'], item['total_price'], ..., item['url']) for item in items ]) conn.commit() except Exception as e: conn.rollback() print(f"Insert failed: {str(e)}")

5. 反爬对抗实战经验

5.1 Cookie维护策略

通过实测发现Q房网的Cookie有效期约2小时,需要定时刷新。采用以下方案:

  1. 使用selenium获取初始Cookie
  2. 通过requests.Session保持会话
  3. 每90分钟重新获取一次Cookie

关键代码:

def get_cookie(): driver = webdriver.Chrome() driver.get('https://www.qfang.com') time.sleep(5) # 等待登录完成 cookies = driver.get_cookies() driver.quit() return {c['name']: c['value'] for c in cookies} def refresh_cookie(): while True: new_cookie = get_cookie() session.cookies.update(new_cookie) time.sleep(5400) # 90分钟

5.2 请求特征模拟

浏览器指纹检测是难点,需要模拟真实用户行为:

  • 添加合理的请求延迟(3-8秒随机)
  • 模拟页面跳转路径(先列表页再详情页)
  • 随机化鼠标滚动事件
  • 添加合理的Referer链

6. 数据质量保障

6.1 异常数据处理

常见数据问题及处理方案:

  1. 价格异常值:过滤单价<5000或>200000的记录
  2. 面积异常:过滤<10㎡或>500㎡的记录
  3. 缺失字段:对关键字段(如总价)设置非空约束
  4. 格式不一致:统一面积单位(㎡)、价格单位(万)

清洗代码示例:

def clean_data(item): # 统一面积格式 if '㎡' in item['area']: item['area'] = item['area'].replace('㎡', '') # 过滤异常值 try: if float(item['unit_price']) < 5000: return None except: return None return item

6.2 去重方案设计

采用URL+挂牌时间作为唯一标识:

ALTER TABLE houses ADD UNIQUE INDEX `idx_unique` (`url`, `listing_date`);

7. 部署与调度

7.1 分布式架构

使用Redis作为任务队列:

# 列表页任务队列 qfang:start_urls = [ 'https://www.qfang.com/shenzhen/sale?page=1', ... ] # 详情页任务队列 qfang:detail_urls = []

7.2 定时调度

使用APScheduler实现定时采集:

from apscheduler.schedulers.blocking import BlockingScheduler scheduler = BlockingScheduler() @scheduler.scheduled_job('cron', hour=2) # 每天凌晨2点执行 def daily_task(): spider = QfangSpider() spider.crawl() scheduler.start()

8. 数据分析应用示例

采集到的数据可用于多种分析场景:

8.1 价格分布分析

import pandas as pd df = pd.read_sql("SELECT district, unit_price FROM houses", conn) # 按行政区划分析 district_stats = df.groupby('district')['unit_price'].agg(['mean', 'count']) print(district_stats.sort_values('mean', ascending=False))

8.2 房源特征关联分析

# 装修与价格关系 sns.boxplot(x='decoration', y='unit_price', data=df) plt.title('不同装修等级的价格分布') plt.show()

9. 法律合规要点

在开发此类爬虫时需特别注意:

  1. 严格遵守robots.txt协议(实测Q房网允许部分路径爬取)
  2. 控制请求频率,不影响网站正常运营
  3. 不爬取用户隐私信息(如联系方式)
  4. 数据仅用于个人研究,不进行商业牟利
  5. 在headers中声明爬虫身份

10. 性能优化记录

经过多次迭代,关键性能指标对比:

版本请求间隔(s)成功率日均数据量CPU占用
v1.0138%2,00085%
v2.03-8随机72%5,00045%
v3.0代理IP轮换95%15,00060%

最终采用多级缓存策略:

  1. 本地缓存已爬取URL(有效期7天)
  2. Redis缓存列表页HTML(有效期1小时)
  3. 内存缓存详情页请求(LRU算法)

11. 踩坑实录

11.1 动态参数陷阱

某次更新后发现爬虫突然失效,排查发现网站新增了动态参数:

/api/house/list?page=2&_t=1234567890

解决方案是提取响应中的时间戳参数回传。

11.2 字体反爬破解

价格信息显示异常,检查发现使用了自定义字体:

@font-face { font-family: 'qfang-price'; src: url('/fonts/price.woff'); }

通过FontTools解析woff字体文件,建立字符映射关系表。

12. 项目演进方向

  1. 增加房源图片下载功能
  2. 集成自动价格预警系统
  3. 开发可视化分析Dashboard
  4. 支持更多房产平台数据源
  5. 实现自动化特征工程管道

这个项目让我深刻体会到,一个健壮的爬虫系统需要考虑的远不止数据采集本身。从反爬对抗到数据清洗,从性能优化到法律合规,每个环节都需要精心设计。特别是在高强度的反爬环境下,如何平衡效率和稳定性是个持续优化的过程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询