1. 项目概述:电商数据抓取的实用价值
上周帮朋友分析竞品店铺时,我再次感受到商品评价数据的价值。无论是做市场调研、竞品分析还是用户需求挖掘,真实的消费者评价都是最直接的决策依据。这个爬虫项目就是为了快速获取电商平台的商品评价数据而设计的,特别适合需要批量分析评价内容但不想手动收集的运营人员和数据分析师。
整套工具采用Python编写,核心功能包括自动登录、翻页抓取、评价解析和数据存储。经过三个月的迭代优化,目前已经稳定运行在多个主流电商平台,单日可采集上万条结构化评价数据。最让我满意的是它的"开箱即用"特性——解压后只需配置少量参数就能直接运行,不需要复杂的部署过程。
注意:爬虫使用需遵守各平台robots协议,建议控制请求频率(建议间隔2秒以上),本项目仅供学习交流使用
2. 技术方案设计思路
2.1 为什么选择Requests+BeautifulSoup组合
早期版本尝试过Scrapy框架,虽然并发性能优秀,但面对电商平台的反爬机制时灵活性不足。最终选择Requests+BeautifulSoup的方案主要基于三点考虑:
- 学习成本低:对Python初学者更友好,调试直观
- 控制粒度细:可以精确模拟用户操作流程
- 扩展性强:方便集成Selenium应对动态渲染页面
实际测试中,这套方案在中小规模数据采集场景(单商品5000条评价内)表现稳定。以下是核心组件版本要求:
python复制requests >= 2.25.1
beautifulsoup4 >= 4.9.3
lxml >= 4.6.2 # 比html.parser速度更快
2.2 反爬应对策略设计
电商平台常见的反爬手段和我们的应对方案:
| 反爬类型 | 应对方案 | 实现示例 |
|---|---|---|
| User-Agent检测 | 轮换常见浏览器UA | headers['User-Agent']池 |
| IP频率限制 | 代理IP池+请求间隔控制 | 免费IP源:https://www.kuaidaili.com/free |
| 登录验证 | 维持会话cookie | session = requests.Session() |
| 动态参数加密 | 逆向解析JavaScript生成逻辑 | 使用PyExecJS执行关键JS代码 |
3. 核心代码实现解析
3.1 登录会话保持机制
大多数电商平台需要登录才能查看完整评价,我们通过会话对象保持登录状态:
python复制def login(username, password):
session = requests.Session()
login_url = "https://example.com/login"
# 先获取登录页面的token
resp = session.get(login_url)
token = re.search(r'name="_token" value="(.*?)"', resp.text).group(1)
# 构造登录表单
form_data = {
"username": username,
"password": password,
"_token": token
}
# 提交登录请求
session.post(login_url, data=form_data)
return session # 返回已登录的会话对象
实操心得:某些平台会检测鼠标移动轨迹,此时需要改用Selenium模拟真实操作
3.2 评价数据解析逻辑
不同平台的评价页面结构差异很大,我们通过CSS选择器灵活定位关键元素:
python复制def parse_reviews(html):
soup = BeautifulSoup(html, 'lxml')
reviews = []
for item in soup.select('.review-item'):
try:
review = {
'user': item.select_one('.user-name').text.strip(),
'rating': float(item.select_one('.rating').attrs['data-score']),
'date': item.select_one('.review-date').text,
'content': item.select_one('.content').text.strip(),
'images': [img['src'] for img in item.select('.review-img')]
}
reviews.append(review)
except Exception as e:
print(f"解析失败:{e}")
return reviews
3.3 自动翻页与增量采集
通过递归实现自动翻页,并记录已采集的评价ID避免重复:
python复制def crawl_reviews(session, product_id, page=1, max_page=10, collected_ids=set()):
if page > max_page:
return []
url = f"https://example.com/product/{product_id}/reviews?page={page}"
resp = session.get(url)
reviews = parse_reviews(resp.text)
new_reviews = [r for r in reviews if r['review_id'] not in collected_ids]
for r in new_reviews:
collected_ids.add(r['review_id'])
# 递归抓取下一页
next_reviews = crawl_reviews(session, product_id, page+1, max_page, collected_ids)
return new_reviews + next_reviews
4. 数据存储方案优化
4.1 结构化存储设计
根据分析需求,我们设计了三层存储结构:
- 原始HTML:作为数据溯源依据
- 解析后的JSON:便于程序直接使用
- 数据库表:支持复杂查询分析
推荐使用SQLite作为轻量级存储方案:
python复制import sqlite3
def init_db():
conn = sqlite3.connect('reviews.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS reviews
(id TEXT PRIMARY KEY,
product_id TEXT,
user TEXT,
rating REAL,
date TEXT,
content TEXT)''')
conn.commit()
return conn
4.2 增量更新策略
通过记录最后采集时间实现增量更新:
sql复制ALTER TABLE reviews ADD COLUMN crawl_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
-- 查询时需要最新数据
SELECT * FROM reviews
WHERE product_id = ?
ORDER BY crawl_time DESC
LIMIT 100;
5. 实战问题排查指南
5.1 常见错误代码处理
| 错误代码 | 可能原因 | 解决方案 |
|---|---|---|
| 403 | IP被封禁 | 更换代理IP,增加延迟 |
| 404 | 商品下架或URL结构变更 | 验证商品状态,更新URL模板 |
| 500 | 服务器内部错误 | 等待1-2小时后重试 |
| 302 | 需要重新登录 | 检查会话cookie有效性 |
5.2 数据缺失排查流程
当发现采集的评价数量异常少时:
- 检查是否触发了反爬机制(返回验证码页面)
- 确认登录状态是否仍然有效
- 验证CSS选择器是否匹配最新页面结构
- 查看是否有异步加载内容(需要滚动触发)
调试时可以保存问题页面到本地:
python复制with open('debug_page.html', 'w', encoding='utf-8') as f:
f.write(resp.text)
6. 数据清洗与分析技巧
6.1 评价文本预处理
原始评价数据需要经过以下处理:
python复制import jieba # 中文分词
def clean_text(text):
# 去除特殊字符
text = re.sub(r'[^\w\s]', '', text)
# 去除停用词
stopwords = set(line.strip() for line in open('stopwords.txt'))
words = [w for w in jieba.cut(text) if w not in stopwords]
return ' '.join(words)
6.2 情感分析实战
使用SnowNLP进行简单的情感倾向分析:
python复制from snownlp import SnowNLP
def analyze_sentiment(text):
s = SnowNLP(text)
return s.sentiments # 0~1之间的情感分值
将结果可视化:
python复制import matplotlib.pyplot as plt
def plot_sentiment(reviews):
scores = [r['sentiment'] for r in reviews]
plt.hist(scores, bins=10)
plt.title('Sentiment Distribution')
plt.show()
7. 项目部署与调度
7.1 定时任务配置
使用APScheduler实现定时采集:
python复制from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
@sched.scheduled_job('interval', hours=6)
def scheduled_job():
crawl_product('123456') # 商品ID
sched.start()
7.2 日志记录规范
建议采用结构化日志:
python复制import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger('review_crawler')
handler = RotatingFileHandler('crawler.log', maxBytes=10*1024*1024, backupCount=5)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# 使用示例
try:
crawl_reviews(...)
except Exception as e:
logger.error(f"抓取失败: {str(e)}", exc_info=True)
8. 法律合规与道德考量
8.1 数据使用边界
虽然技术可行,但需要注意:
- 不得采集用户个人信息(如联系方式)
- 不得用于垃圾营销等用途
- 遵守平台规定的采集频率
- 公开报告需匿名化处理数据
8.2 反爬策略的合理应对
建议采取"友好爬虫"策略:
- 设置合理的请求间隔(建议≥2秒)
- 遵守robots.txt规定
- 在User-Agent中标识爬虫身份
- 遇到验证码时人工处理而非暴力破解
这套爬虫框架经过多次迭代已经相对成熟,但电商平台的页面结构变化频繁,建议每月检查一次核心解析逻辑。对于需要大规模采集的场景,可以考虑引入分布式爬虫架构,但要注意控制总体请求频率。