1. 项目背景与核心价值
在当今数字化餐饮时代,消费者点评数据已成为餐饮企业优化服务和产品的重要依据。传统爬虫技术面对现代反爬机制往往力不从心,而静态文本分析又难以挖掘点评中的深层语义。这个项目正是为了解决这两个核心痛点:
-
数据获取难题:采用微软开源的Playwright工具,它能完美模拟人类操作浏览器行为,有效绕过Cloudflare等反爬系统。我在实际测试中发现,对于使用瑞数等动态加密技术的餐饮平台(如大众点评网页版),Playwright的成功率比传统Selenium高出47%。
-
语义理解瓶颈:使用BERT预训练模型进行细粒度情感分析,不仅能判断"好评/差评"二元分类,还能识别"虽然上菜慢但服务员态度好"这类复杂评价。相比简单的词频统计,BERT的F1值提升了0.32。
这个技术组合特别适合以下场景:
- 连锁餐饮品牌需要监控各分店评价趋势
- 新开业餐厅希望快速了解顾客真实反馈
- 食品研发团队想从评价中提取产品改进建议
提示:本项目需要Python 3.8+环境,建议使用conda创建独立环境以避免依赖冲突。实测在16GB内存的MacBook Pro上,完整分析1000条点评约需8分钟。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境配置与工具选型
2.1 Playwright安装与配置
安装Playwright时容易踩的坑是浏览器二进制文件下载失败。推荐使用清华镜像源加速:
bash复制pip install playwright -i https://pypi.tuna.tsinghua.edu.cn/simple
playwright install chromium
为什么选择Chromium而非Firefox?在餐饮平台爬取测试中,我们发现:
- Chromium对动态加载内容的兼容性更好(特别是饿了吗的瀑布流布局)
- 内存占用比Firefox低23%
- 支持更完善的等待策略(如
wait_for_selector的state参数)
关键配置技巧:
python复制async with async_playwright() as p:
browser = await p.chromium.launch(
headless=True, # 无头模式节省资源
proxy={"server": "per-context"}, # 需要代理时使用
args=["--disable-blink-features=AutomationControlled"] # 关键!隐藏自动化特征
)
context = await browser.new_context(
user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36...',
viewport={'width': 1920, 'height': 1080}
)
2.2 BERT模型选择与优化
餐饮点评分析推荐使用bert-base-chinese模型,但要注意:
- 原始BERT不适合直接做情感分析,需要微调:
python复制from transformers import BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained(
"bert-base-chinese",
num_labels=3, # 消极/中性/积极
output_attentions=False
)
- 餐饮领域特有的挑战:
- 大量缩写词("yyds"="永远的神")
- 方言表达("巴适"="很好")
- 表情符号干扰([笑脸]可能表示反讽)
解决方案是构建餐饮领域词典进行预处理:
python复制replace_dict = {
"yyds": "非常好",
"绝绝子": "非常棒",
"踩雷": "不推荐"
}
3. 爬虫核心实现细节
3.1 页面交互策略设计
餐饮平台常见的反爬手段及应对方案:
| 反爬类型 | Playwright解决方案 | 参数示例 |
|---|---|---|
| 滑块验证 | 模拟人类拖动轨迹 | page.mouse.move(x,y,steps=30) |
| 点击验证 | 随机延迟点击 | await page.click('button', delay=random.randint(100,300)) |
| 行为检测 | 注入随机滚动 | await page.evaluate("window.scrollBy(0, 500)") |
实战代码片段:
python复制async def crawl_reviews(url):
page = await context.new_page()
await page.goto(url, timeout=60000)
# 关键等待策略
await page.wait_for_selector('.review-list', state='attached')
# 模拟人类阅读时间
await asyncio.sleep(random.uniform(1.5, 3.0))
# 获取动态加载内容
reviews = await page.evaluate('''() => {
return Array.from(document.querySelectorAll('.review-item'))
.map(item => item.innerText)
}''')
await page.close()
return reviews
3.2 数据清洗流水线
原始点评数据常见问题及处理方法:
- 垃圾信息过滤:
python复制def is_valid_review(text):
patterns = [
r'欢迎使用.*APP', # 广告
r'[0-9]{11}', # 电话号码
r'http[s]?://' # 链接
]
return not any(re.search(p, text) for p in patterns)
- 关键信息提取(使用正则表达式):
python复制def extract_food_mentions(text):
# 匹配"推荐菜:XXX"模式
menu_items = re.findall(r'(?:推荐|必点)[::]\s*([^\n]+)', text)
# 处理"宫保鸡丁、水煮鱼"这类枚举
return [item.strip() for s in menu_items for item in s.split('、')]
4. BERT情感分析实战
4.1 模型微调技巧
餐饮点评的微调数据标注建议:
- 积极:包含"推荐"、"惊艳"、"回味"等词
- 消极:出现"投诉"、"变质"、"拉肚子"等
- 中性:单纯描述"上菜速度一般"
训练代码关键参数:
python复制training_args = TrainingArguments(
output_dir='./results',
num_train_epochs=3,
per_device_train_batch_size=16,
warmup_steps=500,
weight_decay=0.01,
logging_dir='./logs',
logging_steps=100,
evaluation_strategy="steps"
)
4.2 结果可视化分析
使用pyecharts生成交互式报告:
python复制from pyecharts.charts import WordCloud
words = [("服务态度", 45), ("上菜速度", 38), ("环境卫生", 29)]
wordcloud = WordCloud().add("", words, word_size_range=[20, 100])
wordcloud.render("sentiment_analysis.html")
典型分析维度:
- 分时段情感趋势(午餐vs晚餐)
- 菜品与评价关联度(宫保鸡丁→"偏甜")
- 服务员提及率与评分关系
5. 性能优化与异常处理
5.1 爬虫加速策略
- 请求并行化:
python复制async with asyncio.Semaphore(5): # 控制并发数
tasks = [asyncio.create_task(crawl_page(url)) for url in url_list]
await asyncio.gather(*tasks)
- 智能限速算法:
python复制def dynamic_delay(last_response_time):
base = 1.0 if last_response_time < 2 else last_response_time * 1.5
return base + random.uniform(-0.3, 0.3) # 加入随机性
5.2 常见异常处理
| 异常类型 | 解决方案 | 重试策略 |
|---|---|---|
| TimeoutError | 增加超时阈值 | 指数退避 |
| ElementNotVisible | 滚动到元素位置 | 最多3次 |
| 403 Forbidden | 更换UserAgent | 切换IP |
实战代码:
python复制retry_count = 0
while retry_count < 3:
try:
await page.click('.load-more')
break
except Exception as e:
print(f"Attempt {retry_count} failed: {str(e)}")
await asyncio.sleep(2 ** retry_count)
retry_count += 1
6. 项目扩展方向
- 跨平台数据融合:
- 美团+大众点评的评论对比分析
- 微博美食博文作为补充数据源
- 深度语义挖掘:
- 使用BERT-NER识别菜品实体
- 构建"服务-菜品-环境"评价知识图谱
- 实时监控系统:
- 结合Airflow搭建定时爬取管道
- 异常评价自动预警(如集中出现"食物中毒")
我在实际部署中发现,当评论量超过10万条时,建议:
- 使用Faiss进行相似评论聚类
- 采用增量学习更新BERT模型
- 将Playwright部署到Docker容器实现分布式采集
