1. 项目概述
最近在做一个很有意思的数据分析小项目——爬取京东商品评论数据并进行可视化分析。这个需求源于我朋友开的电商公司,他们想了解消费者对竞品的真实评价,但手动翻看几千条评论实在太费时。于是我决定用Python写个自动化工具,把评论数据抓下来做系统分析。
这个项目主要涉及三个技术环节:数据爬取、数据清洗和可视化呈现。整个过程走下来,发现其中有不少值得分享的技巧和踩过的坑。特别是京东的反爬机制越来越完善,需要一些特殊处理才能稳定获取数据。下面我就把整个实现过程拆解开来,包括代码实现和避坑经验。
2. 技术选型与准备
2.1 工具链选择
核心工具我选择了Python生态中的几个经典库:
- Requests + BeautifulSoup:用于网页抓取和解析
- Pandas:数据处理和分析
- Matplotlib + Seaborn:数据可视化
- Jieba + WordCloud:中文分词和词云生成
选择这套组合主要考虑几点:
- 轻量级,不需要复杂的环境配置
- 社区支持好,遇到问题容易找到解决方案
- 功能覆盖全面,从爬取到分析都能搞定
注意:京东页面有动态加载内容,纯静态解析可能不够。可以考虑加入Selenium做动态渲染,但会增加复杂度。根据我的测试,核心评论数据其实都在初始HTML中,所以本项目暂未使用。
2.2 环境配置
建议使用Python 3.8+版本,主要库安装命令:
bash复制pip install requests beautifulsoup4 pandas matplotlib seaborn jieba wordcloud
如果要做更复杂的文本分析,可以加装:
bash复制pip install scikit-learn nltk
3. 数据爬取实现
3.1 分析京东评论接口
京东的评论数据主要通过API接口获取,而不是直接解析HTML。通过浏览器开发者工具可以找到真实的请求地址,通常是这样的格式:
code复制https://club.jd.com/comment/productPageComments.action?productId=商品ID&score=0&sortType=5&page=页码&pageSize=10
关键参数说明:
- productId:商品编号,可以从商品URL中提取
- score:评价类型(0全部,1好评,2中评,3差评)
- sortType:排序方式(5按时间,6按有用数)
- pageSize:每页条数(最大可设100)
3.2 爬虫代码实现
基础爬取代码如下:
python复制import requests
import pandas as pd
from time import sleep
import random
def get_jd_comments(product_id, max_pages=10):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...',
'Referer': f'https://item.jd.com/{product_id}.html'
}
all_comments = []
for page in range(0, max_pages):
url = f'https://club.jd.com/comment/productPageComments.action?productId={product_id}&score=0&sortType=5&page={page}&pageSize=10'
try:
resp = requests.get(url, headers=headers)
data = resp.json()
comments = data['comments']
for comment in comments:
all_comments.append({
'content': comment['content'],
'creationTime': comment['creationTime'],
'score': comment['score'],
'usefulVoteCount': comment['usefulVoteCount']
})
# 随机延迟防止被封
sleep(random.uniform(1, 3))
except Exception as e:
print(f'第{page}页出错:', e)
return pd.DataFrame(all_comments)
3.3 反爬应对策略
京东的反爬机制比较严格,需要特别注意:
- 必须设置合理的User-Agent和Referer
- 请求频率不能太高,建议每页间隔1-3秒
- IP容易被封,可以考虑使用代理池(本项目未使用)
- 可以随机化请求间隔,增加爬取行为的"人性化"
实测技巧:京东对未登录用户的爬取限制较少,但获取的数据量有限。如果需要大量数据,建议模拟登录获取cookie。
4. 数据清洗与分析
4.1 数据预处理
原始数据通常存在以下问题需要处理:
- 评论内容包含HTML标签、特殊符号
- 时间格式不统一
- 存在重复评论
- 评分为字符串类型需要转换
清洗代码示例:
python复制import re
from datetime import datetime
def clean_data(df):
# 去除HTML标签
df['content'] = df['content'].apply(lambda x: re.sub(r'<[^>]+>', '', x))
# 转换时间格式
df['creationTime'] = pd.to_datetime(df['creationTime'])
# 去除重复评论
df = df.drop_duplicates(subset=['content'])
# 转换评分类型
df['score'] = df['score'].astype(int)
return df
4.2 基础统计分析
可以计算以下基础指标:
- 好评/中评/差评占比
- 评论时间分布
- 评论长度分析
- 有用数分布
示例代码:
python复制def basic_analysis(df):
# 评分分布
score_dist = df['score'].value_counts(normalize=True)
# 评论长度
df['content_length'] = df['content'].apply(len)
length_stats = df['content_length'].describe()
# 时间分布
df['hour'] = df['creationTime'].dt.hour
hour_dist = df['hour'].value_counts().sort_index()
return {
'score_dist': score_dist,
'length_stats': length_stats,
'hour_dist': hour_dist
}
5. 可视化呈现
5.1 评分分布可视化
使用Matplotlib绘制评分分布饼图:
python复制import matplotlib.pyplot as plt
def plot_score_distribution(score_dist):
labels = ['1星', '2星', '3星', '4星', '5星']
sizes = score_dist.sort_index().values
fig, ax = plt.subplots(figsize=(8, 6))
ax.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
ax.axis('equal')
ax.set_title('评分分布')
plt.show()
5.2 评论时间趋势
使用Seaborn绘制评论时间分布:
python复制import seaborn as sns
def plot_comment_trend(hour_dist):
plt.figure(figsize=(12, 6))
sns.lineplot(x=hour_dist.index, y=hour_dist.values)
plt.title('24小时评论分布')
plt.xlabel('小时')
plt.ylabel('评论数')
plt.xticks(range(0, 24))
plt.grid()
plt.show()
5.3 词云生成
分析评论关键词:
python复制from wordcloud import WordCloud
import jieba
def generate_wordcloud(texts):
# 中文分词
words = ' '.join(jieba.cut(''.join(texts)))
# 生成词云
wc = WordCloud(
font_path='simhei.ttf',
background_color='white',
max_words=100,
width=800,
height=600
).generate(words)
plt.figure(figsize=(10, 8))
plt.imshow(wc, interpolation='bilinear')
plt.axis('off')
plt.show()
6. 高级分析技巧
6.1 情感分析
可以使用SnowNLP进行简单的情感分析:
python复制from snownlp import SnowNLP
def sentiment_analysis(df):
df['sentiment'] = df['content'].apply(lambda x: SnowNLP(x).sentiments)
# 情感分布
plt.figure(figsize=(10, 6))
sns.histplot(df['sentiment'], bins=20, kde=True)
plt.title('评论情感分布')
plt.xlabel('情感值')
plt.ylabel('频数')
plt.show()
return df
6.2 主题建模
使用LDA进行主题提取:
python复制from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
def topic_modeling(df, n_topics=3):
# 中文分词
df['tokenized'] = df['content'].apply(lambda x: ' '.join(jieba.cut(x)))
# 构建词袋模型
vectorizer = CountVectorizer(max_df=0.95, min_df=2)
X = vectorizer.fit_transform(df['tokenized'])
# LDA模型
lda = LatentDirichletAllocation(n_components=n_topics, random_state=42)
lda.fit(X)
# 输出主题词
feature_names = vectorizer.get_feature_names_out()
for topic_idx, topic in enumerate(lda.components_):
print(f"Topic #{topic_idx}:")
print(" ".join([feature_names[i] for i in topic.argsort()[:-10 - 1:-1]]))
7. 项目优化方向
7.1 爬虫优化
- 使用Scrapy框架重构爬虫,提高效率和稳定性
- 实现分布式爬取,加快数据收集速度
- 加入自动重试机制,处理网络异常
7.2 分析深化
- 加入更多商品维度的对比分析
- 实现评论与销量的关联分析
- 构建自动化报告生成系统
7.3 可视化增强
- 使用Pyecharts实现交互式可视化
- 构建Dash/Streamlit Web应用
- 开发自动化数据监控看板
8. 常见问题与解决方案
8.1 爬取被封怎么办?
- 降低请求频率,增加随机延迟
- 轮换User-Agent和代理IP
- 使用浏览器自动化工具模拟真人操作
- 考虑使用京东开放平台API(如果有资质)
8.2 数据量太大怎么处理?
- 使用Pandas的chunksize参数分块处理
- 考虑使用Dask或PySpark处理大数据集
- 将数据存入数据库(如MongoDB)再分析
8.3 可视化效果不佳?
- 调整Matplotlib的样式参数
- 使用Seaborn的预设主题
- 尝试Plotly等交互式可视化库
- 优化图表标题和标签的字体大小
9. 完整项目结构建议
一个规范的京东评论分析项目可以这样组织:
code复制jd_comment_analysis/
├── spiders/ # 爬虫代码
│ ├── jd_spider.py
│ └── utils.py
├── analysis/ # 分析代码
│ ├── data_clean.py
│ ├── basic_analysis.py
│ └── advanced_analysis.py
├── visualization/ # 可视化代码
│ ├── plots.py
│ └── dashboard.py
├── data/ # 数据文件
│ ├── raw/
│ └── processed/
├── config.py # 配置文件
└── main.py # 主程序
10. 个人实战经验分享
在实际操作中,我总结了几个特别有用的技巧:
- 时间处理:京东评论时间有多种格式("2023-01-01"、"1个月前"等),需要统一处理。我写了个转换函数:
python复制def parse_jd_time(time_str):
if '前' in time_str: # 处理"1个月前"这种格式
# 转换逻辑...
else:
return pd.to_datetime(time_str)
-
反爬技巧:除了常规的headers设置,我发现京东对Cookie中的
__jda和__jdc参数特别敏感。通过浏览器登录后复制这些参数,可以显著提高爬取成功率。 -
数据缓存:在开发分析过程中,建议将原始数据保存为JSON或CSV,避免每次调试都重新爬取。我通常这样做:
python复制if os.path.exists('comments.json'):
df = pd.read_json('comments.json')
else:
df = get_jd_comments(product_id)
df.to_json('comments.json')
- 可视化调优:Matplotlib的默认样式比较简陋,我习惯在开头设置全局样式:
python复制plt.style.use('seaborn')
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文显示问题
plt.rcParams['axes.unicode_minus'] = False
这个项目虽然不算复杂,但涵盖了从数据获取到分析可视化的完整流程。最大的收获是学会了如何针对具体网站设计反反爬策略,以及如何从海量评论中提取有价值的信息。对于电商从业者来说,这种分析可以帮助他们快速了解消费者对产品的真实反馈,发现潜在的产品改进点。