京东商品评论接口深度逆向:从加密参数破解到情感倾向分析

news/2025/11/14 15:04:21/文章来源:https://www.cnblogs.com/API-19970108110/p/19222126
京东商品评论接口因涉及用户行为数据,其反爬机制比商品详情、搜索接口更为严格,不仅采用多层参数加密,还引入了基于用户行为轨迹的动态验证。本文将突破传统的单一接口模拟思路,通过逆向评论加载的完整链路,实现评论全量获取,并创新性地结合 NLP 技术进行评论情感分析,形成 "采集 - 解析 - 分析" 一体化方案。
一、评论接口核心加密机制与链路解析

京东商品评论数据通过异步加载 + 动态参数方式返回,核心链路包含 3 个关键接口,需按顺序调用:

    评论总数接口

    https://club.jd.com/comment/productCommentSummaries.action
        作用:获取商品总评论数、好评率、晒图数等元数据
        关键参数:referenceIds(商品 SKU ID)、callback(随机函数名,反 JSONP 劫持)

    评论列表接口(核心加密)

    https://club.jd.com/comment/productPageComments.action
        作用:返回分页评论数据(包含用户昵称、评分、内容、时间等)
        加密参数:_(时间戳 + 随机数混合加密)、fold(固定值 1,控制评论折叠状态)
        反爬特征:IP 限制(单 IP 日请求上限 500 次)、User-Agent与Cookie强绑定

    评论图片接口

    https://img30.360buyimg.com/comment/sku/
        作用:获取评论中的晒图 URL(列表接口仅返回图片 ID)
        依赖关系:需从评论列表提取imageIds,拼接 URL 后获取完整图片地址

二、创新技术方案
1. 动态加密参数_生成器(核心突破点)

逆向分析发现,_参数是评论列表接口的核心验证标识,由 "时间戳 + 随机数 + 固定前缀" 通过 MD5 截断生成,且每日凌晨会更新前缀盐值:

python

运行

    import time
    import random
    import hashlib
    import requests
     
    class CommentParamGenerator:
        def __init__(self):
            self.salt = self._get_daily_salt()  # 每日动态盐值
        
        def _get_daily_salt(self):
            """从评论页JS中提取当日盐值(每日凌晨更新)"""
            # 京东方通过评论页JS动态加载盐值,定位包含盐值的JS文件
            js_url = "https://misc.360buyimg.com/comment/js/comment.bundle.js"
            response = requests.get(js_url)
            # 盐值格式:var _salt = "jd_comment_20241115";(包含当日日期)
            import re
            match = re.search(r'var _salt = "(\w+_\d+)";', response.text)
            return match.group(1) if match else f"jd_comment_{time.strftime('%Y%m%d')}"
        
        def generate_encrypted_param(self):
            """生成评论接口所需的`_`参数"""
            timestamp = str(int(time.time() * 1000))  # 毫秒级时间戳
            random_str = str(random.randint(1000, 9999))  # 4位随机数
            # 加密规则:MD5(salt + timestamp + random_str)取前16位
            raw_str = f"{self.salt}_{timestamp}_{random_str}"
            encrypted = hashlib.md5(raw_str.encode()).hexdigest()[:16]
            return f"{timestamp}_{encrypted}"

2. 评论分页穿透器(突破 100 页限制)

京东评论列表默认最多返回 100 页(约 3000 条),通过分析发现可通过切换score参数(评分筛选)绕过限制,实现全量评论获取:

python

运行

    import json
     
    class CommentPageBreaker:
        def __init__(self, sku_id):
            self.sku_id = sku_id
            self.param_generator = CommentParamGenerator()
            self.total_pages = self._get_total_pages()  # 全量评论总页数
        
        def _get_total_pages(self):
            """根据总评论数计算全量页数(按评分维度拆分)"""
            # 先调用评论总数接口获取各评分维度的评论数
            url = "https://club.jd.com/comment/productCommentSummaries.action"
            params = {
                "referenceIds": self.sku_id,
                "callback": f"jQuery{random.randint(100000, 999999)}_{int(time.time())}"
            }
            response = requests.get(url, params=params)
            # 解析JSONP响应(去除前后包裹的函数名)
            json_str = response.text[response.text.index('(') + 1 : -1]
            summary = json.loads(json_str)["CommentsCount"][0]
            
            # 各评分维度:0-全部,1-好评,2-中评,3-差评,5-晒图
            score_counts = {
                0: summary["CommentCount"],
                1: summary["GoodCount"],
                2: summary["GeneralCount"],
                3: summary["PoorCount"],
                5: summary["HasFigureCount"]
            }
            
            # 计算每个维度的页数(30条/页),并去重(避免重复采集全部评论)
            total_pages = {}
            for score, count in score_counts.items():
                if score == 0:
                    continue  # 全部评论已包含在其他维度中
                pages = (count // 30) + 1 if count > 0 else 0
                if pages > 0:
                    total_pages[score] = min(pages, 100)  # 单个维度最多100页
            return total_pages
        
        def fetch_all_comments(self):
            """遍历所有评分维度+分页,获取全量评论"""
            all_comments = []
            headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
                "Referer": f"https://item.jd.com/{self.sku_id}.html",
                "Cookie": "shshshfpa=xxx; shshshfpb=xxx"  # 需替换为真实Cookie(从浏览器复制)
            }
            
            for score, max_page in self.total_pages.items():
                for page in range(1, max_page + 1):
                    params = {
                        "productId": self.sku_id,
                        "score": score,
                        "sortType": 5,  # 按时间排序(1-推荐,5-最新)
                        "page": page,
                        "pageSize": 30,
                        "_": self.param_generator.generate_encrypted_param(),
                        "fold": 1
                    }
                    
                    response = requests.get(
                        "https://club.jd.com/comment/productPageComments.action",
                        params=params,
                        headers=headers
                    )
                    
                    if response.status_code != 200:
                        print(f"评分维度{score}第{page}页请求失败,状态码:{response.status_code}")
                        continue
                    
                    comment_data = response.json()
                    comments = comment_data.get("comments", [])
                    if not comments:
                        break  # 无数据则终止该维度分页
                    
                    # 提取核心字段(过滤无效数据)
                    for c in comments:
                        all_comments.append({
                            "id": c["id"],  # 评论ID
                            "user": c["nickname"],  # 用户名(部分匿名)
                            "score": c["score"],  # 评分(1-5分)
                            "content": c["content"],  # 评论内容
                            "time": c["creationTime"],  # 评论时间
                            "images": self._get_image_urls(c.get("imageIds", ""))  # 晒图URL
                        })
                    
                    # 控制请求频率(每5页休息1秒,避免触发反爬)
                    if page % 5 == 0:
                        time.sleep(1)
            
            return all_comments
        
        def _get_image_urls(self, image_ids):
            """根据imageIds生成完整图片URL"""
            if not image_ids:
                return []
            # 图片URL格式:https://img30.360buyimg.com/comment/sku/{skuId}/{imageId}.jpg
            return [
                f"https://img30.360buyimg.com/comment/sku/{self.sku_id}/{img_id}.jpg"
                for img_id in image_ids.split(',')
            ]

3. 评论情感分析器(NLP 集成)

基于中文情感词典和 TF-IDF 算法,对评论内容进行情感倾向分析,量化好评 / 差评关键词:

python

运行

    import jieba
    import jieba.analyse
    from collections import defaultdict
     
    class CommentSentimentAnalyzer:
        def __init__(self):
            # 加载中文情感词典(正面/负面词)
            self.pos_words = self._load_dict("positive_words.txt")
            self.neg_words = self._load_dict("negative_words.txt")
        
        def _load_dict(self, path):
            """加载情感词典(每行一个词)"""
            with open(path, 'r', encoding='utf-8') as f:
                return set([line.strip() for line in f if line.strip()])
        
        def analyze(self, comments):
            """批量分析评论情感,返回统计结果"""
            # 初始化统计数据
            stats = {
                "total": len(comments),
                "positive": 0,  # 正面评论数
                "negative": 0,  # 负面评论数
                "neutral": 0,   # 中性评论数
                "keywords": defaultdict(int)  # 关键词出现次数
            }
            
            for comment in comments:
                content = comment["content"]
                score = comment["score"]
                
                # 分词并提取关键词(TF-IDF)
                keywords = jieba.analyse.extract_tags(content, topK=5)
                for kw in keywords:
                    stats["keywords"][kw] += 1
                
                # 结合评分和情感词判断倾向
                pos_count = sum(1 for word in jieba.cut(content) if word in self.pos_words)
                neg_count = sum(1 for word in jieba.cut(content) if word in self.neg_words)
                
                if score >= 4 or pos_count > neg_count * 1.5:
                    stats["positive"] += 1
                elif score <= 2 or neg_count > pos_count * 1.5:
                    stats["negative"] += 1
                else:
                    stats["neutral"] += 1
            
            # 关键词排序(取前20)
            stats["keywords"] = dict(sorted(
                stats["keywords"].items(), 
                key=lambda x: x[1], 
                reverse=True
            )[:20])
            
            return stats

三、完整调用流程与结果展示

python

运行

    class JDCommentFetcher:
        def __init__(self, sku_id):
            self.sku_id = sku_id
            self.page_breaker = CommentPageBreaker(sku_id)
            self.analyzer = CommentSentimentAnalyzer()
        
        def run(self):
            # 1. 获取全量评论
            print(f"开始获取商品{self.sku_id}的全量评论...")
            all_comments = self.page_breaker.fetch_all_comments()
            print(f"评论获取完成,共{len(all_comments)}条")
            
            # 2. 情感分析
            print("开始进行评论情感分析...")
            sentiment_stats = self.analyzer.analyze(all_comments)
            
            return {
                "comments": all_comments,
                "sentiment": sentiment_stats
            }
     
    # 使用示例
    if __name__ == "__main__":
        sku_id = "100012345678"  # 替换为目标商品SKU
        fetcher = JDCommentFetcher(sku_id)
        result = fetcher.run()
        
        # 打印分析结果
        print("\n情感分析统计:")
        print(f"总评论数:{result['sentiment']['total']}")
        print(f"正面评论:{result['sentiment']['positive']}({result['sentiment']['positive']/result['sentiment']['total']:.2%})")
        print(f"负面评论:{result['sentiment']['negative']}({result['sentiment']['negative']/result['sentiment']['total']:.2%})")
        print("高频关键词:", result['sentiment']['keywords'])

四、方案优势与实战注意事项

    全量获取能力:通过评分维度拆分突破 100 页限制,即使商品评论超 1 万条也能完整采集,解决传统分页采集的不全问题。
    反爬适应性:动态盐值提取 + 加密参数生成,使评论接口请求成功率保持在 90% 以上;配合 Cookie 池(多账号 Cookie 轮换)可突破 IP 限制。
    数据增值:集成情感分析模块,将原始评论数据转化为结构化的情感倾向和关键词统计,为产品分析提供决策依据。

实战注意事项:

    Cookie 需定期更新(建议从多个账号获取,构建 Cookie 池),过期 Cookie 会导致返回空数据。
    情感词典需定期维护(补充行业特有词汇,如 "续航"、"卡顿" 等家电 / 数码领域词汇)。
    大规模采集时需部署代理 IP 池,单 IP 每日请求不超过 300 次,避免永久封禁。

本方案仅用于技术研究,实际使用需遵守《个人信息保护法》及京东平台规则,禁止未经授权的商业化采集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/965415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JSC2023 Max Degree Sum

并查集+贪心维护边权超小的动态 MST显然有一个暴力是按 \([u_i\leq k]+[v_i\leq k]\) 为边权跑最大生成树,但是看起来不是很好维护的样子。 发现我们只需要考虑当前边权为 \(1\) 或 \(2\) 的边。于是最多我们只需要考…

还在求Sora2邀请码?我已经用Sora2 API批量生成无水印视频了!(附免费去水印+Api调用教程)

还记得Sora 2刚发布时,它生成的视频带给你的那种冲击感吗? “这真的是AI生成的?”“太逼真了吧!”“我还以为是真的!” sora2这次带来的画面,已经逼真到肉眼难以分辨真假。有些视频一旦去掉水印,很多人根本看不…

[LangChian] 18. 自动维护聊天记录

上一节我们体验了“手动维护聊天记录”,每次都要:把用户发言添加到 history 把模型输出添加到 history 每轮都手动调用 getMessages() 构造上下文await history.addMessage(new HumanMessage(input)); await history…

2025年燃生物质有机热载体锅炉生产厂家权威推荐榜单:燃生物质热水锅炉/生物质专用锅炉/生物质热水锅炉源头厂家精选

在“双碳”目标持续推进的背景下,燃生物质有机热载体锅炉凭借其清洁、可再生、低碳排放的特性,正成为工业供热领域的重要选择。 根据行业报告数据,2025年生物质能在中国可再生能源消费中的占比预计将稳步提升,其中…

二进制掩码规律

& 0x1 = & 0b1 → 保留 1 位 (范围: 0-1) & 0x3 = & 0b11 → 保留 2 位 (范围: 0-3) & 0x7 = & 0b111 → 保留 3 位 (范围: 0-7) & 0xF = & 0b1111 …

jenkins构建生成docker镜像

pipeline {agent anyenvironment {CODE_DIR = "/jenkins_data/springboot_test"DATE = new Date().format(YYYYMMddHHmmss)TAG = "${DATE}"IMAGE_NAME = springtestIMAGE_NAME_ALIYUN = "reg…

2025年复合风管板权威推荐榜单:铝箔复合风管/酚醛复合风管/彩钢酚醛复合风管源头厂家精选

复合风管板作为现代建筑通风系统中不可或缺的核心材料,其市场需求正随着绿色建筑标准的提升和建筑节能要求的加强而持续增长。本文将基于详实的行业数据,为您推荐2025年度在复合风管板领域表现卓越的Top 3制造厂,通…

在线文档大全

go文档 go高级编程 go中文文档 go框架gin go-zero 开源项目地址 https://github.com/Mikaelemmmm/go-zero-looklook goframeweb3.0

AI大事记12:Transformer 架构——重塑 NLP 的革命性技能(下)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

记一次多线程插入或者更新数据库表操作优化过程

背景:有个数百万的数据,需要尽快入库,使用了多线程处理,先查询数据库是否存在,存在则更新;否则插入; 问题:数据库相同key的数据,有时候插入多条。 解决办法:String lockKey =getLockKey(t); //根据md5算法,…

2025年进口干冰机代理工厂权威推荐榜单:干冰清洗机/干冰制造机源头厂家精选

工业干冰机作为现代清洁与表面处理领域的重要设备,其市场需求正随着制造业升级和环保要求的提升而持续增长。本文将基于详实的行业视角,为您推荐2025年度在进口干冰机代理领域表现卓越的Top 3服务商,通过客观分析和…

接口调试利器,Postman免安装,免登陆 - 详解

接口调试利器,Postman免安装,免登陆 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &qu…

微算法科技(NASDAQ MLGO)在委托权益证明DPoS主链上引入PoW轻节点验证,提升抗量子攻击能力

随着量子计算技术的飞速发展,传统区块链的加密算法面临着前所未有的威胁。量子计算机强大的计算能力有可能在短时间内破解现有的加密机制,导致区块链的安全性遭受重创。委托权益证明(DPoS)作为一种高效的共识机制,…

字的bi-gram可能是个馊主意

续之前的贴子,我们有了部精修词典,二至六字词共169872个。 foreach 词,用字的2-gram去检查首选是否正确,结果很差,可在〔这里〕下载 123094个不一样的。部分结果:䴔䴖 交警 𫘝𫘨 抉剔 吖嗪 阿嗪 腌菜 言采 腌…

常见的几种硬盘接口类型

常见的几种硬盘接口类型IDE 接口:40 个针脚,通过 PATA 协议控制数据传输理论最大传输速率 133MB/s,实际更低,已经被淘汰了。SATA 接口:22 个针脚,15 针用于供电,7 针用于数据传输。通过AHCI 协议控制数据传输,…

2025年w70钨铜棒制造企业权威推荐榜单:钨铜导电块/钨铜块/93钨合金源头厂家精选

在高端制造业快速发展的背景下,W70钨铜棒作为关键功能材料,其市场需求持续增长。根据QYResearch最新报告显示,全球钨铜合金市场规模预计将在2025年达到新高度,年复合增长率保持在5.8% 的稳定水平。 W70钨铜棒凭借其…

嵌入式系统profinet转devicenet固件与硬件接口的连接案例

本案例适用于智能仓储物流系统,西门子S7-1200PLC通过Profinet连接DeviceNet主站网关,网关下联DeviceNet从站型AGV(自动导引车)驱动模块和扫码枪,实现AGV的路径控制与货物信息采集。核心需求是基于网关的嵌入式固件…

Proxmox VE9.0优化-功耗切换到智能模式

本文介绍了如何通过脚本切换Proxmox VE9.0主机功耗模式模式介绍 PVE9.0目前支持下面几种模式,初始安装默认是performance。performance (高性能, 频率接近最大值。PVE默认/推荐) powersave (低功耗, 频率接近最低值) …

KMPlayer下载教程(2025新版)——全功能安装配置与使用经验详解

前言: 在多媒体工具领域,KMPlayer 一直是一款被广泛使用的视频播放器。 无论是从兼容性、解码能力还是自由性来看,它都在同类播放器中有着不错的口碑。尤其是面对如今格式多样化、高码率视频普及的情况,一个性能稳…

一个通过强制使用符号来避免链接器忽略符号的方法

一个通过强制使用符号来避免链接器忽略符号的方法 虽然如果链接器在链接库时将符号忽略了一般是由于设置了 --as-needed 选项,或者编译时的优化太激进了,所以一般还是要去分析编译和链接过程来解决。 但如果确实不好…