代码高效采集京东商品信息:API 接口接入与实时数据获取

98 阅读7分钟

在电商数据分析、竞品监控和价格策略制定等场景中,高效采集京东商品信息是一项关键需求。相比传统的网页爬虫方式,通过官方 API 接口获取数据具有稳定性高、合规性强、数据结构规范等显著优势。本文将详细介绍如何高效接入京东商品 API 接口,实现商品信息的实时获取,并提供可直接使用的代码实现。

京东 API 概述 点击注册使用链接 京东提供了一套完整的 API 服务体系,其中商品相关接口是开发者最常使用的服务之一。通过这些接口,开发者可以合法获取商品基本信息、价格、库存、评价等多维度数据。

核心优势包括:

数据获取合规,避免法律风险和 IP 封禁 接口稳定,不受页面布局变更影响 数据结构标准化,解析成本低 支持高并发调用(在配额范围内) 提供完整的错误码体系,便于问题排查 接入前的准备工作 开发者账号注册:访问并完成开发者账号注册 应用创建:获取 ApiKey 和 ApiSecret 接口权限申请:根据需求申请相应的商品接口权限 了解接口文档:熟悉目标接口的参数要求、返回数据结构和调用限制 高效采集的技术实现 高效采集京东商品信息需要考虑几个关键因素:签名算法的正确实现、请求频率控制、批量处理机制和错误重试策略。下面是完整的代码实现:

import requests import time import hashlib import json import logging from concurrent.futures import ThreadPoolExecutor, as_completed from ratelimit import limits, sleep_and_retry

配置日志

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(name)

class JDProductCollector: def init(self, app_key, app_secret, max_workers=5, rate_limit=10): """ 初始化京东商品采集器

    Args:
        app_key: 应用的AppKey
        app_secret: 应用的AppSecret
        max_workers: 并发工作线程数
        rate_limit: 每分钟最大请求数
    """
    self.app_key = app_key
    self.app_secret = app_secret
    self.api_url = "https://api.jd.com/routerjson"
    self.version = "2.0"
    self.format = "json"
    self.max_workers = max_workers
    
    # 限制API调用频率
    self.rate_limit = rate_limit
    self.api_call = self._rate_limited_api_call()
    
def _rate_limited_api_call(self):
    """创建带频率限制的API调用装饰器"""
    @sleep_and_retry
    @limits(calls=self.rate_limit, period=60)  # 每分钟最多calls次请求
    def wrapper(func):
        return func
    return wrapper

def generate_sign(self, params):
    """生成API签名"""
    # 按照参数名ASCII排序
    sorted_params = sorted(params.items(), key=lambda x: x[0])
    
    # 拼接签名字符串
    sign_str = self.app_secret
    for key, value in sorted_params:
        sign_str += f"{key}{value}"
    sign_str += self.app_secret
    
    # 计算MD5并转为大写
    return hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()

def _get_single_product(self, product_id):
    """获取单个商品详情"""
    try:
        params = {
            "method": "jingdong.item.get",
            "app_key": self.app_key,
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
            "format": self.format,
            "v": self.version,
            "param_json": json.dumps({"skuId": product_id})
        }
        
        # 生成签名
        params["sign"] = self.generate_sign(params)
        
        # 调用API
        self.api_call(lambda: None)  # 应用频率限制
        response = requests.get(self.api_url, params=params, timeout=10)
        result = response.json()
        
        # 处理错误响应
        if "error_response" in result:
            error_msg = result["error_response"].get("msg", "未知错误")
            logger.error(f"商品ID {product_id} 获取失败: {error_msg}")
            return {"product_id": product_id, "success": False, "error": error_msg}
        
        # 提取有用信息
        item = result["jingdong_item_get_response"]["item"]
        product_info = {
            "product_id": item.get("skuId"),
            "name": item.get("name"),
            "price": item.get("jdPrice", {}).get("price"),
            "market_price": item.get("marketPrice", {}).get("price"),
            "brand": item.get("brand", {}).get("name"),
            "category": item.get("category", {}).get("name"),
            "stock": item.get("stock", {}).get("stockNum"),
            "image_url": item.get("imagePath"),
            "shop_name": item.get("shopInfo", {}).get("shopName"),
            "update_time": time.strftime("%Y-%m-%d %H:%M:%S"),
            "success": True
        }
        
        logger.info(f"商品ID {product_id} 获取成功")
        return product_info
        
    except Exception as e:
        logger.error(f"商品ID {product_id} 处理异常: {str(e)}")
        return {"product_id": product_id, "success": False, "error": str(e)}

def get_products_batch(self, product_ids, retry_failed=1):
    """
    批量获取商品信息
    
    Args:
        product_ids: 商品ID列表
        retry_failed: 失败重试次数
        
    Returns:
        商品信息列表
    """
    results = []
    failed_ids = []
    
    # 并发处理商品ID列表
    with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
        # 创建Future对象字典
        futures = {executor.submit(self._get_single_product, pid): pid for pid in product_ids}
        
        # 处理结果
        for future in as_completed(futures):
            result = future.result()
            results.append(result)
            if not result["success"]:
                failed_ids.append(result["product_id"])
    
    # 重试失败的请求
    if failed_ids and retry_failed > 0:
        logger.info(f"开始第 {retry_failed} 次重试,共 {len(failed_ids)} 个商品")
        time.sleep(2)  # 等待片刻再重试
        retry_results = self.get_products_batch(failed_ids, retry_failed - 1)
        
        # 合并重试结果
        for r in retry_results:
            # 替换原有失败记录
            for i, res in enumerate(results):
                if res["product_id"] == r["product_id"]:
                    results[i] = r
                    break
    
    return results

def save_to_json(self, data, filename):
    """保存数据到JSON文件"""
    try:
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        logger.info(f"数据已保存到 {filename}")
    except Exception as e:
        logger.error(f"保存文件失败: {str(e)}")

if name == "main": # 配置你的AppKey和AppSecret APP_KEY = "your_app_key" APP_SECRET = "your_app_secret"

# 初始化采集器,设置并发数和频率限制
collector = JDProductCollector(
    app_key=APP_KEY,
    app_secret=APP_SECRET,
    max_workers=5,  # 5个并发线程
    rate_limit=30   # 每分钟最多30次请求
)

# 要采集的商品ID列表
product_ids = [
    "100012345678",
    "100008348546",
    "100015818882",
    # 可以添加更多商品ID
]

# 批量获取商品信息
logger.info(f"开始采集 {len(product_ids)} 个商品信息")
start_time = time.time()

products_data = collector.get_products_batch(product_ids, retry_failed=2)

end_time = time.time()
logger.info(f"采集完成,耗时 {end_time - start_time:.2f} 秒")

# 统计结果
success_count = sum(1 for p in products_data if p["success"])
logger.info(f"成功获取 {success_count}/{len(product_ids)} 个商品信息")

# 保存结果到文件
collector.save_to_json(products_data, "jd_products_data.json")

# 打印部分结果示例
print("\n采集结果示例:")
for p in products_data[:3]:  # 打印前3个结果
    if p["success"]:
        print(f"ID: {p['product_id']}, 名称: {p['name']}, 价格: {p['price']}元")
    else:
        print(f"ID: {p['product_id']}, 状态: 失败, 原因: {p['error']}")

AI生成项目

代码解析与高效采集策略 上述代码实现了一个高效的京东商品信息采集工具,主要特点包括:

并发处理机制:使用 ThreadPoolExecutor 实现多线程并发请求,大幅提高批量采集效率

频率控制:通过 ratelimit 库实现请求频率限制,避免触发 API 调用上限

失败重试:内置失败重试机制,提高数据获取成功率

结构化数据提取:从 API 返回结果中提取关键信息,减少数据冗余

完善的日志系统:记录采集过程,便于问题排查和进度跟踪

优化建议与最佳实践 合理设置并发数:根据 API 配额和网络状况调整 max_workers 参数,通常 5-10 个线程较为合适

实现数据缓存:对频繁访问的商品信息进行本地缓存,减少 API 调用次数

分布式部署:对于超大量级的采集任务,可以考虑分布式部署,分散请求压力

增量更新:只采集有变化的商品信息,减少不必要的请求

异常监控:实现报警机制,当 API 调用失败率异常时及时通知

数据库存储:对于长期项目,建议将数据存储到 MySQL、MongoDB 等数据库中,便于后续分析

注意事项与合规说明 严格遵守使用规范,不得将数据用于非法用途

注意 API 调用配额,避免超限导致账号受限

商业使用前需获得授权,尊重数据知识产权

实现适当的请求间隔,避免对京东服务器造成过大压力

定期检查 API 版本更新,及时调整代码以适应接口变化

总结 通过京东 API 接口采集商品信息,是一种高效、稳定且合规的方案。本文提供的代码实现了批量商品信息的并发采集,并通过频率控制、失败重试等机制保证了采集效率和稳定性。

开发者可以根据实际需求扩展此工具,例如添加定时采集功能、实现数据可视化展示、构建商品价格监控系统等。在实际应用中,还需根据业务规模和 API 配额进行合理调整,以达到最佳的采集效果