一、爬取前准备
1.1 环境配置
- 开发语言:Python 3.8+
- 核心库:
pip install requests # 发送HTTP请求
pip install pymongo # 存储数据到MongoDB
pip install fake-useragent # 生成随机User-Agent
pip install lxml # 辅助解析(可选)
- 工具:
-
- 浏览器开发者工具(Chrome/Firefox):抓包分析接口
-
- MongoDB:存储评论数据(也可改用 MySQL)
-
- Postman:接口调试(可选)
1.2 爬取合规说明
- 仅用于学习研究,不得用于商业用途
- 控制爬取频率,避免给京东服务器造成压力
- 爬取数据量不宜过大,遵守网站 robots.txt 协议
二、京东评论接口分析
京东商品评论采用异步加载(AJAX),需通过抓包获取真实请求接口,步骤如下:
2.1 抓包步骤
- 滚动到评论区,刷新页面,打开浏览器开发者工具(F12)→ 切换到「Network」→ 筛选「XHR」
- 找到名称含「comment」的请求(例:https://club.jd.com/comment/productPageComments.action)
- 点击该请求,查看「Headers」(请求头)和「Response」(响应数据)
2.2 核心接口参数解析
请求 URL 格式:
https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100012345678&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&rid=0&fold=1
关键参数说明:
| 参数名 | 含义 | 取值说明 |
| productId | 商品 ID | 从商品详情页 URL 提取 |
| score | 评论评分筛选 | 0 = 全部,1 = 差评,2 = 中评,3 = 好评,5 = 追评 |
| sortType | 排序方式 | 5 = 按时间排序,6 = 按有用度排序 |
| page | 页码 | 从 0 开始递增(0 = 第 1 页) |
| pageSize | 每页评论数 | 最大 10(京东限制) |
| callback | 回调函数名 | 可删除(删除后返回纯 JSON) |
2.3 响应数据格式
删除callback参数后,响应为标准 JSON 格式,核心字段:
{
"comments": [
{
"id": 123456789, // 评论ID
"nickname": "***用户", // 用户名(脱敏)
"score": 5, // 评分(1-5)
"content": "商品质量很好!",// 评论内容
"creationTime": "2024-05-20 14:30:00",// 评论时间
"productColor": "黑色", // 商品颜色
"productSize": "XL", // 商品尺寸
"usefulVoteCount": 23 // 有用数
}
],
"total": 1234, // 总评论数
"pageSize": 10, // 每页数量
"page": 0 // 当前页码
}
三、爬取代码实现(完整实战)
3.1 核心功能模块
- 构建请求头(反爬基础)
- 循环请求多页评论
- 解析 JSON 数据
- 数据存储到 MongoDB
- 异常处理与反爬应对
3.2 完整代码
import requests
import json
import time
from fake_useragent import UserAgent
from pymongo import MongoClient
from requests.exceptions import RequestException
class JDCommentCrawler:
def __init__(self, product_id, max_page=10):
self.product_id = product_id # 商品ID
self.max_page = max_page # 最大爬取页数
self.base_url = "https://club.jd.com/comment/productPageComments.action"
self.ua = UserAgent()
# 连接MongoDB(本地默认端口27017)
self.client = MongoClient("mongodb://localhost:27017/")
self.db = self.client["JD_Comments"] # 数据库名
self.collection = self.db["product_" + str(product_id)] # 集合名(按商品ID区分)
def get_headers(self):
"""生成随机请求头,模拟浏览器"""
return {
"User-Agent": self.ua.random,
"Referer": f"https://item.jd.com/{self.product_id}.html",
"Accept": "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive"
}
def fetch_comment_page(self, page):
"""请求单页评论数据"""
params = {
"productId": self.product_id,
"score": 0, # 0=全部评论
"sortType": 5, # 按时间排序
"page": page,
"pageSize": 10,
"isShadowSku": 0,
"rid": 0,
"fold": 1
}
headers = self.get_headers()
try:
response = requests.get(
url=self.base_url,
params=params,
headers=headers,
timeout=10
)
if response.status_code == 200:
# 解析JSON(京东部分接口返回带回调函数,需处理)
try:
return response.json()
except json.JSONDecodeError:
# 处理带回调函数的响应(如:fetchJSON_comment98({...}))
content = response.text.lstrip("fetchJSON_comment98(").rstrip(")")
return json.loads(content)
else:
print(f"请求失败,状态码:{response.status_code}")
return None
except RequestException as e:
print(f"请求异常:{str(e)}")
return None
def parse_comment(self, comment_data):
"""解析单条评论数据,提取关键信息"""
return {
"comment_id": comment_data.get("id", ""),
"user_name": comment_data.get("nickname", ""),
"score": comment_data.get("score", 0),
"content": comment_data.get("content", "").strip(),
"comment_time": comment_data.get("creationTime", ""),
"product_color": comment_data.get("productColor", ""),
"product_size": comment_data.get("productSize", ""),
"useful_count": comment_data.get("usefulVoteCount", 0),
"reply_count": comment_data.get("replyCount", 0),
"crawl_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}
def save_comment(self, comment):
"""保存评论到MongoDB"""
# 去重:根据comment_id判断是否已存在
if not self.collection.find_one({"comment_id": comment["comment_id"]}):
self.collection.insert_one(comment)
print(f"保存评论:{comment['comment_id']} - {comment['content'][:20]}...")
else:
print(f"评论已存在,跳过:{comment['comment_id']}")
def run(self):
"""启动爬取"""
print(f"开始爬取商品ID:{self.product_id} 的评论,共计划爬取 {self.max_page} 页")
for page in range(self.max_page):
print(f"\n正在爬取第 {page+1} 页...")
# 控制爬取频率(关键反爬措施)
time.sleep(1.5) # 每页间隔1.5秒,可根据情况调整
comment_json = self.fetch_comment_page(page)
if not comment_json:
continue
# 提取评论列表
comments = comment_json.get("comments", [])
if not comments:
print("该页无评论,爬取结束")
break
# 解析并保存每条评论
for comment in comments:
parsed_comment = self.parse_comment(comment)
self.save_comment(parsed_comment)
print("\n爬取完成!")
self.client.close() # 关闭MongoDB连接
if __name__ == "__main__":
# 示例:爬取商品ID为100012345678的前20页评论
product_id = "100012345678" # 替换为目标商品ID
crawler = JDCommentCrawler(product_id=product_id, max_page=20)
crawler.run()
四、反爬措施与问题解决
4.1 核心反爬应对
- 随机 User-Agent:使用fake-useragent库生成不同浏览器的 User-Agent,避免被识别为爬虫
- 控制请求频率:每页请求间隔 1-2 秒(time.sleep(1.5)),避免高频请求触发风控
- 携带 Referer:Referer 设为商品详情页 URL,模拟正常用户浏览行为
- IP 代理池(进阶):若爬取量大,需使用代理 IP 轮换(推荐:阿布云、快代理),示例代码:
# 添加代理配置(在fetch_comment_page方法中)
proxies = {
"http": "http://用户名:密码@代理IP:端口",
"https": "https://用户名:密码@代理IP:端口"
}
response = requests.get(..., proxies=proxies, ...)
4.2 常见问题解决
- 响应 403 Forbidden:
-
- 检查 User-Agent 是否有效,可改用固定高频率使用的 UA(如 Chrome 最新版)
-
- 增加请求间隔(≥2 秒)
-
- 携带 Cookie(从浏览器复制真实 Cookie,添加到请求头)
- JSON 解析失败:
-
- 部分接口返回带回调函数的响应,需剥离回调函数名(代码中已处理)
-
- 检查网络是否稳定,重试请求
- 评论重复爬取:
-
- 数据库层面通过comment_id去重(代码中已实现)
- 爬取到一定页数后无数据:
-
- 京东评论存在「折叠评论」,部分页面可能无数据,需判断comments列表是否为空并退出循环
五、数据存储与后续处理
5.1 MongoDB 数据查看
爬取完成后,可通过 MongoDB Compass 可视化工具查看数据,或使用命令行:
mongo
use JD_Comments
db.product_100012345678.find().pretty() # 查看指定商品的评论
5.2 数据导出(可选)
将 MongoDB 中的数据导出为 CSV/Excel,用于数据分析:
import pandas as pd
# 连接MongoDB并导出
client = MongoClient("mongodb://localhost:27017/")
db = client["JD_Comments"]
collection = db["product_100012345678"]
data = list(collection.find())
df = pd.DataFrame(data)
df.to_csv("jd_comments.csv", index=False, encoding="utf-8-sig")
print("数据已导出为jd_comments.csv")
六、进阶优化方向
- 多线程 / 异步爬取:使用threading或aiohttp提高爬取效率(需控制并发数,避免反爬)
- 分布式爬取:结合 Scrapy+Redis 实现大规模爬取
- 评论图片爬取:解析comment_data["images"]字段,下载评论中的图片
- 情感分析:使用 SnowNLP 或 jieba 对评论内容进行情感倾向分析
- 自动获取商品 ID 列表:从京东分类页爬取多个商品 ID,实现批量爬取
七、注意事项
- 京东接口可能会不定期更新参数或加密方式,若爬取失败需重新抓包分析
- 爬取时需遵守网站规则,避免过度爬取导致 IP 被封(可设置爬取时间间隔≥1 秒)
- 部分商品评论需登录后查看,可通过添加 Cookie(在请求头中加入Cookie字段)解决
- 本教程仅用于学习,请勿将爬取的数据用于商业用途,否则可能面临法律风险
&spm=1001.2101.3001.5002&articleId=155102080&d=1&t=3&u=dfa38134ebe4486ea6e5a15c7866a01c)

被折叠的 条评论
为什么被折叠?



