×

api开发 电商平台 数据挖掘

逆向分析与 API 调用:另一种获取京东实时商品数据的技术方案探讨

admin admin 发表于2025-09-08 17:19:14 浏览18 评论0

抢沙发发表评论

在电商数据分析、价格监控和竞品分析等场景中,获取实时商品数据具有重要价值。京东作为国内领先的电商平台,其商品数据接口并未完全对外开放,这给开发者带来了一定挑战。本文将探讨一种通过逆向分析结合 API 调用的技术方案,实现京东实时商品数据的获取,并提供相应的代码实现。

一、技术方案概述

本方案主要包含以下几个关键步骤:


  1. 网页逆向分析:通过浏览器开发者工具分析京东商品页面的网络请求,找到获取商品数据的 API 接口

  2. 请求参数解析:研究 API 接口的请求参数,特别是那些动态生成的参数

  3. API 调用模拟:使用程序模拟浏览器发送请求,获取商品数据

  4. 数据解析与处理:对返回的 JSON 数据进行解析,提取所需信息


这种方案相比传统的网页爬虫具有更高的效率和稳定性,因为它直接与数据源接口交互,而非解析整个 HTML 页面。

二、逆向分析过程

1. 找到目标 API

打开京东商品详情页,例如:https://item.jd.com/100008348542.html,打开浏览器开发者工具(F12),切换到 Network 标签,刷新页面,观察所有网络请求。


经过筛选分析,可以发现京东商品详情数据主要来自以下 API:


  • 基本商品信息

  • 商品价格信息

2. 分析请求参数

以价格 API 为例,其请求格式通常为:


plaintext

https://p.3.cn/prices/mgets?skuIds=J_100008348542



其中skuIds参数是商品的唯一标识符,格式为J_加上商品 ID。这个参数比较简单,容易构造。


对于商品详情 API,参数相对复杂一些,但核心参数也是商品 ID,其他参数多为辅助验证或缓存控制用。

三、代码实现

下面提供一个 Python 实现,通过上述分析的 API 获取京东商品的基本信息和价格:

import requests
import json
import time
import random
from user_agent import generate_user_agent  # 需要安装: pip install user_agent

class JDProductFetcher:
    def __init__(self):
        # 初始化请求头,模拟浏览器行为
        self.headers = {
            "Accept": "*/*",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Connection": "keep-alive",
            "Host": "p.3.cn",
            "Referer": "https://item.jd.com/",
            "Sec-Fetch-Dest": "script",
            "Sec-Fetch-Mode": "no-cors",
            "Sec-Fetch-Site": "cross-site",
            "User-Agent": generate_user_agent()
        }
        
        # 商品详情API的请求头(主机不同)
        self.detail_headers = self.headers.copy()
        self.detail_headers["Host"] = "item-soa.jd.com"
    
    def get_price(self, product_id):
        """获取商品价格"""
        try:
            # 构造价格API的URL
            url = f"https://p.3.cn/prices/mgets?skuIds=J_{product_id}"
            
            # 随机延迟,避免请求过于频繁
            time.sleep(random.uniform(1, 3))
            
            # 发送请求
            response = requests.get(url, headers=self.headers)
            
            # 检查响应状态
            if response.status_code != 200:
                print(f"获取价格失败,状态码: {response.status_code}")
                return None
            
            # 解析JSON数据
            price_data = json.loads(response.text)
            
            if price_data and len(price_data) > 0:
                return {
                    "product_id": product_id,
                    "price": price_data[0].get("p"),
                    "original_price": price_data[0].get("m"),
                    "update_time": time.strftime("%Y-%m-%d %H:%M:%S")
                }
            else:
                print("未获取到价格数据")
                return None
                
        except Exception as e:
            print(f"获取价格时发生错误: {str(e)}")
            return None
    
    def get_product_detail(self, product_id):
        """获取商品详细信息"""
        try:
            # 构造商品详情API的URL
            url = f"https://item-soa.jd.com/getItemDetail?skuId={product_id}"
            
            # 随机延迟
            time.sleep(random.uniform(1, 3))
            
            # 发送请求
            response = requests.get(url, headers=self.detail_headers)
            
            # 检查响应状态
            if response.status_code != 200:
                print(f"获取商品详情失败,状态码: {response.status_code}")
                return None
            
            # 解析JSON数据
            detail_data = json.loads(response.text)
            
            # 提取需要的信息
            if detail_data.get("code") == 200 and "data" in detail_data:
                data = detail_data["data"]
                return {
                    "product_id": product_id,
                    "name": data.get("itemName"),
                    "brand": data.get("brandName"),
                    "shop_name": data.get("shopName"),
                    "category": data.get("category", {}).get("categoryName"),
                    "description": data.get("wDiscription"),
                    "stock": data.get("stockState")  # 1表示有货,0表示无货
                }
            else:
                print("未获取到商品详情数据")
                return None
                
        except Exception as e:
            print(f"获取商品详情时发生错误: {str(e)}")
            return None
    
    def get_product_full_info(self, product_id):
        """获取商品完整信息(价格+详情)"""
        price_info = self.get_price(product_id)
        if not price_info:
            return None
            
        detail_info = self.get_product_detail(product_id)
        if not detail_info:
            return None
            
        # 合并信息
        full_info = {**price_info,** detail_info}
        return full_info

if __name__ == "__main__":
    # 示例用法
    fetcher = JDProductFetcher()
    
    # 测试商品ID(可以替换为其他京东商品ID)
    product_ids = ["100008348542", "100012166285", "100023216438"]
    
    for pid in product_ids:
        print(f"\n获取商品 {pid} 的信息...")
        product_info = fetcher.get_product_full_info(pid)
        
        if product_info:
            print("商品完整信息:")
            print(json.dumps(product_info, ensure_ascii=False, indent=2))
        else:
            print(f"获取商品 {pid} 信息失败")

四、代码解析

上述代码实现了一个京东商品数据获取工具,主要包含以下几个部分:


  1. 请求头设置:模拟浏览器的请求头信息,包括 User-Agent 的随机生成,以降低被识别为爬虫的概率。

  2. 价格获取方法:通过分析得到的价格 API,根据商品 ID 获取商品的当前价格和原价。

  3. 商品详情获取方法:调用商品详情 API,获取商品名称、品牌、店铺名称、分类等信息。

  4. 完整信息整合:将价格信息和详情信息合并,提供完整的商品数据。

  5. 反反爬措施

    • 随机 User-Agent 生成

    • 随机请求间隔

    • 合理的请求头设置

五、注意事项与风险

  1. 合法性问题:使用此方案获取数据时,请确保符合京东的用户协议和 robots.txt 规则,以及相关法律法规,不得用于商业用途或恶意爬取。

  2. 接口变化:电商平台的 API 接口和参数可能会不定期变化,当代码无法正常工作时,需要重新进行逆向分析。

  3. 反爬机制:频繁的请求可能会导致 IP 被临时封禁,建议进一步优化反反爬策略,如使用代理 IP 池、更智能的请求间隔控制等。

  4. 数据使用限制:获取的数据应仅用于个人学习研究,不得侵犯平台和商家的合法权益。

六、总结与扩展

本文介绍的通过逆向分析发现 API 接口并进行调用的方法,是获取电商平台数据的有效途径。相比传统的网页解析,这种方法更高效、数据结构更清晰。


未来可以从以下几个方面进行扩展:


  1. 实现更完善的错误处理和重试机制

  2. 加入代理 IP 池,提高稳定性

  3. 开发数据存储模块,将获取的数据持久化

  4. 实现定时任务,定期获取商品数据,进行价格趋势分析


需要强调的是,任何数据获取行为都应在合法合规的前提下进行,尊重平台规则和数据所有权,共同维护健康的网络环境。


少长咸集

群贤毕至

访客