搞定京东反爬!Python 爬取商品评论全攻略(含多页爬取 + 数据去重)

一、爬取前准备

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 抓包步骤
  1. 打开京东商品详情页(例:https://item.jd.com/100012345678.html
  1. 滚动到评论区,刷新页面,打开浏览器开发者工具(F12)→ 切换到「Network」→ 筛选「XHR」
  1. 找到名称含「comment」的请求(例:https://club.jd.com/comment/productPageComments.action
  1. 点击该请求,查看「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 核心功能模块
  1. 构建请求头(反爬基础)
  1. 循环请求多页评论
  1. 解析 JSON 数据
  1. 数据存储到 MongoDB
  1. 异常处理与反爬应对
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 核心反爬应对
  1. 随机 User-Agent:使用fake-useragent库生成不同浏览器的 User-Agent,避免被识别为爬虫
  1. 控制请求频率:每页请求间隔 1-2 秒(time.sleep(1.5)),避免高频请求触发风控
  1. 携带 Referer:Referer 设为商品详情页 URL,模拟正常用户浏览行为
  1. IP 代理池(进阶):若爬取量大,需使用代理 IP 轮换(推荐:阿布云、快代理),示例代码:
 

# 添加代理配置(在fetch_comment_page方法中)

proxies = {

"http": "http://用户名:密码@代理IP:端口",

"https": "https://用户名:密码@代理IP:端口"

}

response = requests.get(..., proxies=proxies, ...)

4.2 常见问题解决
  1. 响应 403 Forbidden
    • 检查 User-Agent 是否有效,可改用固定高频率使用的 UA(如 Chrome 最新版)
    • 增加请求间隔(≥2 秒)
    • 携带 Cookie(从浏览器复制真实 Cookie,添加到请求头)
  1. JSON 解析失败
    • 部分接口返回带回调函数的响应,需剥离回调函数名(代码中已处理)
    • 检查网络是否稳定,重试请求
  1. 评论重复爬取
    • 数据库层面通过comment_id去重(代码中已实现)
  1. 爬取到一定页数后无数据
    • 京东评论存在「折叠评论」,部分页面可能无数据,需判断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")

六、进阶优化方向

  1. 多线程 / 异步爬取:使用threading或aiohttp提高爬取效率(需控制并发数,避免反爬)
  1. 分布式爬取:结合 Scrapy+Redis 实现大规模爬取
  1. 评论图片爬取:解析comment_data["images"]字段,下载评论中的图片
  1. 情感分析:使用 SnowNLP 或 jieba 对评论内容进行情感倾向分析
  1. 自动获取商品 ID 列表:从京东分类页爬取多个商品 ID,实现批量爬取

七、注意事项

  1. 京东接口可能会不定期更新参数或加密方式,若爬取失败需重新抓包分析
  1. 爬取时需遵守网站规则,避免过度爬取导致 IP 被封(可设置爬取时间间隔≥1 秒)
  1. 部分商品评论需登录后查看,可通过添加 Cookie(在请求头中加入Cookie字段)解决
  1. 本教程仅用于学习,请勿将爬取的数据用于商业用途,否则可能面临法律风险
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值