1. 项目背景与需求分析
大众点评作为国内领先的生活服务平台,积累了海量商户数据。这些数据对于市场分析、竞品调研和商业决策具有重要价值。然而平台的反爬机制日益完善,传统爬虫方案面临诸多挑战:
- 动态渲染内容难以获取
- 频繁请求触发风控
- 验证码拦截
- 数据字段分散需要复杂解析
这个项目要实现的是一款高可用的商家数据采集系统,需要解决以下核心问题:
- 如何绕过前端动态渲染获取完整HTML
- 如何模拟真实用户行为避免被封禁
- 如何设计高效的数据解析流程
- 如何实现分布式调度和容错机制
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与架构设计
2.1 核心工具选型
经过对比测试,最终技术栈确定为:
python复制DrissionPage + Playwright + Asyncio + Redis + MongoDB
选择DrissionPage而非传统Selenium的原因:
- 直接基于Chromium内核,无需驱动
- 支持同步/异步混合模式
- 内置智能等待和元素定位策略
- 内存占用更低(实测比Selenium低40%)
2.2 系统架构设计
采用分层架构设计:
code复制[采集调度层] → [行为模拟层] → [数据解析层] → [存储层]
↑ ↑ ↑
[代理池] [设备指纹库] [规则引擎]
关键组件说明:
- 调度层:基于Redis的分布式任务队列
- 模拟层:DrissionPage封装的浏览器实例池
- 解析层:XPath+CSS选择器双引擎
- 存储层:MongoDB分片集群
重要提示:商业场景使用需遵守平台robots.txt协议,本方案仅用于技术研究
3. 核心模块实现细节
3.1 反反爬策略实现
3.1.1 设备指纹模拟
python复制def generate_fingerprint():
return {
'webgl_vendor': 'Intel Inc.',
'canvas_hash': '8d9f1e5a',
'audio_ctx_hash': '3ac21f4b',
'fonts': ['Arial', 'Microsoft YaHei']
}
3.1.2 流量特征混淆
- 随机化滚动速度:50-300px/s
- 鼠标移动轨迹:贝塞尔曲线模拟
- 请求间隔:正态分布(μ=3s, σ=1.5s)
3.2 数据采集模块
3.2.1 页面导航策略
python复制async def crawl_shop(driver, url):
await driver.goto(url, referer='https://www.dianping.com')
await random_scroll(driver)
await hover_random_element(driver)
return driver.html
3.2.2 关键数据定位
商家主页需要提取的字段及对应选择器:
| 字段 | CSS选择器 | 备用XPath |
|---|---|---|
| 店铺名称 | .shop-name | //h1[@class='shop-name'] |
| 评分 | .star-score | //span[contains(@class,'star')] |
| 人均消费 | .avg-price | //span[text()='人均']/following-sibling::span |
3.3 分布式调度实现
采用Redis Stream实现任务分发:
python复制# 生产者
def produce_task(shop_ids):
for id in shop_ids:
redis.xadd('dp_tasks', {'shop_id': id})
# 消费者
async def consume_task():
while True:
task = redis.xreadgroup('group1', 'consumer1', {'dp_tasks': '>'})
await process(task)
4. 性能优化实践
4.1 浏览器实例池
python复制class BrowserPool:
def __init__(self, size=5):
self.pool = [DrissionPage(proxy=random_proxy())
for _ in range(size)]
async def get(self):
while True:
for browser in self.pool:
if not browser.in_use:
return browser
await asyncio.sleep(0.1)
4.2 智能重试机制
根据异常类型动态调整策略:
| 异常类型 | 处理方式 | 冷却时间 |
|---|---|---|
| 429 Too Many Requests | 切换代理+更换指纹 | 5分钟 |
| 验证码 | 自动打码服务+降低频率 | 30分钟 |
| 连接超时 | 直接重试 | 立即 |
5. 数据存储方案
5.1 MongoDB分片配置
javascript复制sh.addShard("rs0/mongo1:27017")
sh.enableSharding("dianping")
sh.shardCollection("dianping.shops", {"city": 1, "category": 1})
5.2 数据去重策略
采用复合唯一索引:
python复制db.shops.create_index([
("name", TEXT),
("address", TEXT),
("phone", TEXT)
], unique=True)
6. 踩坑经验实录
6.1 典型问题排查
问题现象:连续采集2小时后出现大量验证码
解决方案:
- 引入动态作息模式:每采集30分钟随机休眠5-8分钟
- 增加鼠标移动轨迹随机性
- 混合使用3种不同版本的Chromium内核
6.2 性能瓶颈突破
测试数据:
- 单机日均采集量从1.2万提升到3.8万
- 请求成功率从68%提升到92%
优化手段:
- 使用HTTP/2连接复用
- 预加载城市区域页缓存
- 实现DOM变化增量采集
7. 扩展思考
这套架构稍作改造即可应用于:
- 美团商家数据采集
- 抖音POI信息抓取
- 小红书店铺数据分析
关键调整点:
- 平台特定的反爬策略适配
- 页面结构解析规则调整
- 流量调度参数优化
在实际商业项目中,建议配合以下策略:
- 合法合规的数据使用授权
- 分布式代理IP池建设
- 基于机器学习的请求频率动态调整
