1. 项目背景与核心价值
商业地理大数据采集在零售、餐饮、地产等行业具有极高价值。以美团大众点评为代表的本地生活平台,包含了商户位置、评分、评论、品类等关键数据,这些信息对于商圈分析、竞品调研、选址决策等场景至关重要。然而传统爬虫在面对现代反爬机制(如动态渲染、行为验证)时往往力不从心,而单机爬取又难以满足海量数据的采集需求。
这正是我们开发这套分布式异步爬虫系统的初衷。系统采用Playwright作为浏览器自动化工具,完美应对动态内容加载;基于Asyncio实现高并发请求;通过Redis分布式任务队列协调多节点工作。实测显示,单节点每日可稳定采集10万+条结构化数据,且能绕过绝大多数反爬策略。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 核心组件选型
Playwright的优势:
- 支持Chromium/Firefox/WebKit全内核
- 自动等待元素加载机制
- 内置反检测规避功能
- 相比Selenium减少30%内存占用
Asyncio事件循环:
python复制async def crawl_task(url):
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto(url)
# 页面操作代码...
分布式协调方案:
- Redis作为消息队列存储待抓取URL
- Celery作为任务调度器
- 一致性哈希算法分配节点负载
2.2 系统工作流程
- 主节点从Redis获取种子URL
- 通过Celery分发到Worker节点
- 各节点启动Playwright实例
- 执行页面交互与数据提取
- 清洗后存入MongoDB
- 反馈新发现的URL到队列
3. 关键实现细节
3.1 反反爬策略实践
瑞数验证码绕过方案:
python复制await page.route(
"**/*",
lambda route: route.continue_()
if not route.request.url.endswith(".css")
else route.abort()
)
IP代理管理技巧:
- 使用隧道代理服务
- 每个请求随机切换出口IP
- 自动检测IP可用性
3.2 数据提取优化
XPath定位最佳实践:
python复制# 不推荐
//div[@class="review"]/p[1]
# 推荐
//div[contains(@class,"review")]//p[starts-with(@class,"content")]
动态等待策略:
python复制await page.wait_for_selector(
"div.shop-info",
state="attached",
timeout=10000
)
4. 性能调优实录
4.1 并发控制参数
| 参数项 | 单机推荐值 | 说明 |
|---|---|---|
| 浏览器实例数 | 5-8 | 取决于CPU核心数 |
| 请求超时 | 30s | 包含页面加载时间 |
| 重试次数 | 3 | 避免无限重试 |
4.2 内存泄漏排查
常见问题场景:
- 未关闭BrowserContext
- 事件监听器未移除
- 大对象未及时释放
解决方案:
python复制async with async_playwright() as p:
browser = await p.chromium.launch()
context = await browser.new_context()
try:
# 业务代码
finally:
await context.close()
await browser.close()
5. 数据分析应用
采集后的数据可通过:
- 地理编码转换(WGS84/GCJ02)
- 评论情感分析(SnowNLP)
- 热力图可视化(Pyecharts)
示例分析代码:
python复制def analyze_shop_distribution(data):
from pyecharts.charts import Geo
geo = Geo()
geo.add_schema(maptype="北京")
geo.add("商户分布", data)
return geo.render()
6. 踩坑经验分享
Cookie处理陷阱:
- 不要全局共享cookie
- 每个店铺页面使用独立context
- 定期清除localStorage
验证码应对策略:
- 识别出现验证码的特征(如跳转特定URL)
- 自动暂停任务并报警
- 人工干预后继续任务
分布式锁的正确用法:
python复制with redis.lock("task_lock", timeout=60):
if not check_duplicate(url):
add_to_queue(url)
这套系统经过半年生产环境验证,在数据完整性、系统稳定性方面表现优异。特别提醒:商业数据采集需遵守平台Robots协议,建议控制请求频率在合理范围内。
