唯品会(VIP.com)作为国内知名的品牌折扣电商平台,其item_get接口提供了通过商品 ID 获取商品详细信息的能力。该接口对于电商分析、竞品研究和价格监控等场景具有重要价值,能够获取商品价格、规格、库存、促销信息等关键数据。
一、唯品会 item_get 接口核心特性分析
1. 接口定位与核心价值
2. 接口权限与调用限制
3. 核心参数解析
必选参数
可选参数
二、签名生成与返回数据结构
1. 签名生成逻辑
2. 返回数据结构解析
三、Python 实现方案
import requests
import time
import hmac
import hashlib
import base64
import json
import logging
import pandas as pd
import matplotlib.pyplot as plt
import re
from datetime import datetime
from typing import Dict, Optional, List, Tuple
# 配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
# 配置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False
class VipItemDetail:
"""唯品会item_get接口封装类,用于根据ID获取和分析商品详情数据"""
def __init__(self, app_key: str, app_secret: str):
"""
初始化唯品会API客户端
:param app_key: 应用的app_key
:param app_secret: 应用的app_secret
"""
self.app_key = app_key
self.app_secret = app_secret.encode('utf-8') # 转换为字节
self.api_url = "https://api.vip.com/rest/item/get"
# 频率控制
self.rate_limit = 20 # 默认基础权限,高级权限可修改为100次/分钟
self.call_timestamps = [] # 存储调用时间戳(毫秒级)
def set_rate_limit(self, limit: int) -> None:
"""设置调用频率限制(次/分钟)"""
if 20 <= limit <= 100:
self.rate_limit = limit
logging.info(f"已设置调用频率限制为 {limit} 次/分钟")
else:
logging.warning("频率限制必须在20-100之间,未修改")
def _generate_sign(self, params: Dict) -> str:
"""生成签名(HMAC-SHA256算法)"""
# 1. 按参数名ASCII升序排序
sorted_params = sorted(params.items(), key=lambda x: x[0])
# 2. 拼接为"key=value&key=value"格式
param_str = "&".join([f"{k}={v}" for k, v in sorted_params])
# 3. HMAC-SHA256加密并Base64编码
hmac_sha256 = hmac.new(self.app_secret, param_str.encode('utf-8'), hashlib.sha256)
sign = base64.b64encode(hmac_sha256.digest()).decode('utf-8')
return sign
def _check_rate_limit(self) -> None:
"""检查并控制调用频率"""
current_time = time.time() * 1000 # 毫秒级
# 保留1分钟内的调用记录
self.call_timestamps = [t for t in self.call_timestamps if current_time - t < 60000]
# 若超过限制,计算需要等待的时间
if len(self.call_timestamps) >= self.rate_limit:
oldest_time = self.call_timestamps[0]
sleep_time = (60000 - (current_time - oldest_time)) / 1000 + 0.1 # 额外加0.1秒保险
logging.warning(f"调用频率超限,等待 {sleep_time:.1f} 秒")
time.sleep(sleep_time)
# 再次清理过期记录
self.call_timestamps = [t for t in self.call_timestamps if time.time()*1000 - t < 60000]
# 记录本次调用时间
self.call_timestamps.append(current_time)
def get_item_detail(self, item_id: str,
include_promotion: bool = True,
include_spec: bool = True,
include_brand: bool = True,
include_history_price: bool = False,
region: str = "110000", # 默认北京地区
fields: Optional[str] = None) -> Optional[Dict]:
"""
根据ID获取商品详情数据
:param item_id: 商品ID
:param include_promotion: 是否包含促销信息
:param include_spec: 是否包含规格详情
:param include_brand: 是否包含品牌信息
:param include_history_price: 是否包含历史价格
:param region: 地区编码
:param fields: 指定返回字段,逗号分隔
:return: 商品详情数据
"""
# 构建基础参数
base_params = {
"app_key": self.app_key,
"timestamp": str(int(time.time() * 1000)), # 毫秒级时间戳
"format": "json",
"v": "2.0",
"item_id": item_id,
"include_promotion": "true" if include_promotion else "false",
"include_spec": "true" if include_spec else "false",
"include_brand": "true" if include_brand else "false",
"include_history_price": "true" if include_history_price else "false",
"region": region
}
# 添加指定字段参数
if fields:
base_params["fields"] = fields
# 生成签名
sign = self._generate_sign(base_params)
base_params["sign"] = sign
# 检查频率限制
self._check_rate_limit()
try:
# 发送请求
response = requests.get(self.api_url, params=base_params, timeout=10)
response.raise_for_status()
# 解析响应
result = response.json()
# 处理错误
if result.get("code") != 0:
logging.error(f"API调用错误: {result.get('msg')} (错误码: {result.get('code')})")
return None
# 提取结果
item_data = result.get("data", {})
if not item_data:
logging.warning("未获取到商品详情数据")
return None
logging.info(f"成功获取商品 {item_id} 的详情数据")
return item_data
except requests.exceptions.RequestException as e:
logging.error(f"请求异常: {str(e)}")
return None
except json.JSONDecodeError:
logging.error(f"响应解析失败: {response.text[:200]}...")
return None
def batch_get_item_details(self, item_ids: List[str],
include_promotion: bool = True,
include_spec: bool = True,
include_brand: bool = True) -> Tuple[List[Dict], int]:
"""
批量获取多个商品的详情数据
:param item_ids: 商品ID列表
:param include_promotion: 是否包含促销信息
:param include_spec: 是否包含规格详情
:param include_brand: 是否包含品牌信息
:return: 商品详情列表和成功获取的数量
"""
all_items = []
success_count = 0
for item_id in item_ids:
logging.info(f"正在获取商品 {item_id} 的详情...")
item_data = self.get_item_detail(
item_id=item_id,
include_promotion=include_promotion,
include_spec=include_spec,
include_brand=include_brand,
include_history_price=False # 批量获取默认不获取历史价格,减少数据量
)
if item_data:
all_items.append(item_data)
success_count += 1
logging.info(f"批量获取完成,共请求 {len(item_ids)} 个商品,成功获取 {success_count} 个")
return all_items, success_count
def analyze_item(self, item_data: Dict) -> Dict:
"""分析单个商品数据"""
if not item_data:
return {"error": "没有商品数据可分析"}
# 1. 价格分析
price_info = {
"current_price": float(item_data.get("price", 0)),
"original_price": float(item_data.get("original_price", 0)),
"discount": 0, # 折扣率
"has_member_price": False,
"member_price": 0,
"price_drop": 0 # 降价幅度
}
# 计算折扣率
if price_info["original_price"] > 0:
price_info["discount"] = round(price_info["current_price"] / price_info["original_price"], 2)
price_info["price_drop"] = round(price_info["original_price"] - price_info["current_price"], 2)
# 会员价分析
if "member_price" in item_data and float(item_data["member_price"]) > 0:
price_info["has_member_price"] = True
price_info["member_price"] = float(item_data["member_price"])
# 历史价格分析
history_price_info = {
"has_history": False,
"min_price": 0,
"max_price": 0,
"price_change_count": 0,
"30day_lowest": 0
}
if "history_price" in item_data and item_data["history_price"]:
history_price_info["has_history"] = True
prices = [float(p["price"]) for p in item_data["history_price"]]
history_price_info["min_price"] = min(prices)
history_price_info["max_price"] = max(prices)
history_price_info["price_change_count"] = len(prices) - 1
# 计算30天最低价
now = datetime.now()
thirty_days_ago = now.timestamp() - 30 * 24 * 3600
recent_prices = []
for p in item_data["history_price"]:
try:
price_time = datetime.strptime(p["time"], "%Y-%m-%d %H:%M:%S").timestamp()
if price_time >= thirty_days_ago:
recent_prices.append(float(p["price"]))
except (ValueError, KeyError):
continue
if recent_prices:
history_price_info["30day_lowest"] = min(recent_prices)
# 2. 库存与规格分析
spec_info = {
"total_stock": int(item_data.get("stock", 0)),
"spec_count": 0,
"color_count": 0,
"size_count": 0,
"has_stock_variation": False # 不同规格库存是否有差异
}
specs = item_data.get("specs", [])
if specs and isinstance(specs, list):
spec_info["spec_count"] = len(specs)
# 提取颜色和尺码数量
colors = set()
sizes = set()
stocks = []
for spec in specs:
attributes = spec.get("attributes", {})
if "颜色" in attributes:
colors.add(attributes["颜色"])
if "尺码" in attributes:
sizes.add(attributes["尺码"])
try:
stocks.append(int(spec.get("stock", 0)))
except (ValueError, TypeError):
continue
spec_info["color_count"] = len(colors)
spec_info["size_count"] = len(sizes)
# 检查库存是否有差异
if len(stocks) > 1 and len(set(stocks)) > 1:
spec_info["has_stock_variation"] = True
# 3. 促销分析
promotion_info = {
"has_promotion": False,
"promotion_count": 0,
"promotion_types": [],
"max_discount": 0,
"has_coupon": False,
"coupon_count": 0
}
promotions = item_data.get("promotions", [])
if promotions and isinstance(promotions, list):
promotion_info["has_promotion"] = True
promotion_info["promotion_count"] = len(promotions)
# 提取促销类型
types = set()
for p in promotions:
p_type = p.get("type", "unknown")
types.add(p_type)
# 记录最大折扣
if "discount" in p:
try:
discount = float(p["discount"])
if discount < promotion_info["max_discount"] or promotion_info["max_discount"] == 0:
promotion_info["max_discount"] = discount
except ValueError:
continue
promotion_info["promotion_types"] = list(types)
# 检查是否有优惠券
coupons = [p for p in promotions if p.get("type") == "coupon"]
if coupons:
promotion_info["has_coupon"] = True
promotion_info["coupon_count"] = len(coupons)
# 4. 品牌分析
brand_info = {
"has_brand_info": False,
"brand_id": "",
"brand_name": "",
"brand_rating": 0,
"brand_product_count": 0
}
if "brand_info" in item_data and item_data["brand_info"]:
brand = item_data["brand_info"]
brand_info["has_brand_info"] = True
brand_info["brand_id"] = brand.get("brand_id", "")
brand_info["brand_name"] = brand.get("brand_name", "")
try:
brand_info["brand_rating"] = float(brand.get("rating", 0))
brand_info["brand_product_count"] = int(brand.get("product_count", 0))
except (ValueError, TypeError):
pass
# 5. 销售与评价分析
sales_info = {
"sales_count": int(item_data.get("sales_count", 0)),
"comment_count": int(item_data.get("comment_count", 0)),
"avg_rating": 0,
"positive_rate": 0,
"has_bad_comment": False
}
try:
sales_info["avg_rating"] = float(item_data.get("avg_rating", 0))
sales_info["positive_rate"] = float(item_data.get("positive_rate", 0)) / 100 # 转换为0-1范围
except (ValueError, TypeError):
pass
# 检查是否有差评
if "comment_stats" in item_data:
comment_stats = item_data["comment_stats"]
try:
if int(comment_stats.get("bad_count", 0)) > 0:
sales_info["has_bad_comment"] = True
except ValueError:
pass
# 6. 服务分析
service_info = {
"return_policy": "",
"shipping_time": "",
"has_free_shipping": False,
"warranty": ""
}
if "service_info" in item_data:
service = item_data["service_info"]
service_info["return_policy"] = service.get("return_policy", "")
service_info["shipping_time"] = service.get("shipping_time", "")
service_info["has_free_shipping"] = service.get("has_free_shipping", False)
service_info["warranty"] = service.get("warranty", "")
return {
"item_id": item_data.get("item_id"),
"title": item_data.get("title"),
"category": item_data.get("category"),
"price_analysis": price_info,
"history_price_analysis": history_price_info,
"spec_analysis": spec_info,
"promotion_analysis": promotion_info,
"brand_analysis": brand_info,
"sales_analysis": sales_info,
"service_analysis": service_info,
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
def compare_items(self, items_data: List[Dict]) -> Dict:
"""对比多个商品数据"""
if len(items_data) < 2:
return {"error": "至少需要2个商品进行对比"}
comparison = {
"total_items": len(items_data),
"price_comparison": [],
"discount_comparison": [],
"sales_comparison": [],
"rating_comparison": [],
"spec_comparison": []
}
# 提取各商品关键指标用于对比
for item in items_data:
item_id = item.get("item_id")
title = item.get("title", "")[:30] # 截断长标题
# 价格对比
comparison["price_comparison"].append({
"item_id": item_id,
"title": title,
"current_price": float(item.get("price", 0)),
"original_price": float(item.get("original_price", 0)),
"discount": round(float(item.get("price", 0))/float(item.get("original_price", 1)), 2)
})
# 折扣对比
comparison["discount_comparison"].append({
"item_id": item_id,
"title": title,
"discount": round(float(item.get("price", 0))/float(item.get("original_price", 1)), 2),
"has_promotion": "promotions" in item and len(item.get("promotions", [])) > 0
})
# 销量对比
comparison["sales_comparison"].append({
"item_id": item_id,
"title": title,
"sales_count": int(item.get("sales_count", 0)),
"comment_count": int(item.get("comment_count", 0))
})
# 评分对比
comparison["rating_comparison"].append({
"item_id": item_id,
"title": title,
"avg_rating": float(item.get("avg_rating", 0)),
"positive_rate": float(item.get("positive_rate", 0))/100 if item.get("positive_rate") else 0
})
# 规格对比
specs = item.get("specs", [])
colors = set()
sizes = set()
for spec in specs:
attributes = spec.get("attributes", {})
if "颜色" in attributes:
colors.add(attributes["颜色"])
if "尺码" in attributes:
sizes.add(attributes["尺码"])
comparison["spec_comparison"].append({
"item_id": item_id,
"title": title,
"color_count": len(colors),
"size_count": len(sizes),
"total_stock": int(item.get("stock", 0))
})
# 排序各对比项以便分析
comparison["price_comparison"].sort(key=lambda x: x["current_price"])
comparison["discount_comparison"].sort(key=lambda x: x["discount"])
comparison["sales_comparison"].sort(key=lambda x: x["sales_count"], reverse=True)
comparison["rating_comparison"].sort(key=lambda x: x["avg_rating"], reverse=True)
return comparison
def visualize_comparison(self, comparison: Dict, output_dir: str = ".") -> None:
"""可视化多个商品的对比结果"""
if "error" in comparison:
logging.warning(comparison["error"])
return
# 1. 价格与原价对比条形图
if comparison["price_comparison"]:
plt.figure(figsize=(12, 6))
items = [item["title"] for item in comparison["price_comparison"]]
current_prices = [item["current_price"] for item in comparison["price_comparison"]]
original_prices = [item["original_price"] for item in comparison["price_comparison"]]
x = range(len(items))
width = 0.35
plt.bar([i - width/2 for i in x], current_prices, width, label='当前价')
plt.bar([i + width/2 for i in x], original_prices, width, label='原价')
plt.xlabel('商品')
plt.ylabel('价格 (元)')
plt.title('商品价格对比')
plt.xticks(x, items, rotation=45)
plt.legend()
plt.tight_layout()
plt.savefig(f"{output_dir}/vip_price_comparison.png")
plt.close()
logging.info(f"价格对比图表已保存至 {output_dir}/vip_price_comparison.png")
# 2. 折扣对比条形图
if comparison["discount_comparison"]:
plt.figure(figsize=(12, 6))
items = [item["title"] for item in comparison["discount_comparison"]]
discounts = [item["discount"] * 10 for item in comparison["discount_comparison"]] # 转换为十分制
bars = plt.bar(items, discounts, color=['green' if item["has_promotion"] else 'blue'
for item in comparison["discount_comparison"]])
# 添加促销标记
for i, item in enumerate(comparison["discount_comparison"]):
if item["has_promotion"]:
bars[i].set_label('带促销' if i == 0 else "")
plt.xlabel('商品')
plt.ylabel('折扣 (10=原价, 越低越优惠)')
plt.title('商品折扣对比')
plt.xticks(rotation=45)
plt.legend()
for i, v in enumerate(discounts):
plt.text(i, v + 0.2, f"{v/10:.1f}折", ha='center')
plt.tight_layout()
plt.savefig(f"{output_dir}/vip_discount_comparison.png")
plt.close()
logging.info(f"折扣对比图表已保存至 {output_dir}/vip_discount_comparison.png")
# 3. 销量与评价对比条形图
if comparison["sales_comparison"]:
plt.figure(figsize=(12, 6))
items = [item["title"] for item in comparison["sales_comparison"]]
sales = [item["sales_count"] for item in comparison["sales_comparison"]]
comments = [item["comment_count"] for item in comparison["sales_comparison"]]
x = range(len(items))
width = 0.35
plt.bar([i - width/2 for i in x], sales, width, label='销量')
plt.bar([i + width/2 for i in x], comments, width, label='评价数')
plt.xlabel('商品')
plt.ylabel('数量')
plt.title('商品销量与评价对比')
plt.xticks(x, items, rotation=45)
plt.legend()
plt.tight_layout()
plt.savefig(f"{output_dir}/vip_sales_comparison.png")
plt.close()
logging.info(f"销量对比图表已保存至 {output_dir}/vip_sales_comparison.png")
# 4. 评分对比条形图
if comparison["rating_comparison"]:
plt.figure(figsize=(12, 6))
items = [item["title"] for item in comparison["rating_comparison"]]
ratings = [item["avg_rating"] for item in comparison["rating_comparison"]]
positive_rates = [item["positive_rate"] * 100 for item in comparison["rating_comparison"]]
x = range(len(items))
width = 0.35
plt.bar([i - width/2 for i in x], ratings, width, label='平均评分')
plt.bar([i + width/2 for i in x], positive_rates, width, label='好评率(%)')
plt.xlabel('商品')
plt.ylabel('分数/百分比')
plt.title('商品评分对比')
plt.xticks(x, items, rotation=45)
plt.legend()
plt.tight_layout()
plt.savefig(f"{output_dir}/vip_rating_comparison.png")
plt.close()
logging.info(f"评分对比图表已保存至 {output_dir}/vip_rating_comparison.png")
def visualize_price_history(self, item_data: Dict, output_dir: str = ".") -> None:
"""可视化单个商品的价格历史"""
if not item_data or "history_price" not in item_data or not item_data["history_price"]:
logging.warning("没有价格历史数据可可视化")
return
try:
# 提取并排序价格历史
price_history = sorted(item_data["history_price"],
key=lambda x: datetime.strptime(x["time"], "%Y-%m-%d %H:%M:%S"))
times = [datetime.strptime(p["time"], "%Y-%m-%d %H:%M:%S") for p in price_history]
prices = [float(p["price"]) for p in price_history]
# 创建图表
plt.figure(figsize=(12, 6))
plt.plot(times, prices, 'b-', marker='o')
# 标记当前价格
current_price = float(item_data.get("price", 0))
plt.axhline(y=current_price, color='r', linestyle='--', label=f'当前价格: {current_price}元')
plt.title(f'商品价格历史: {item_data.get("title", "")[:20]}...')
plt.xlabel('时间')
plt.ylabel('价格 (元)')
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend()
plt.xticks(rotation=45)
plt.tight_layout()
# 保存图表
item_id = item_data.get("item_id", "unknown")
plt.savefig(f"{output_dir}/vip_price_history_{item_id}.png")
plt.close()
logging.info(f"价格历史图表已保存至 {output_dir}/vip_price_history_{item_id}.png")
except Exception as e:
logging.error(f"生成价格历史图表失败: {str(e)}")
def export_to_excel(self, items_data: List[Dict], analyses: List[Dict], comparison: Optional[Dict],
filename: str) -> None:
"""导出商品数据到Excel"""
if not items_data and not analyses:
logging.warning("没有数据可导出")
return
try:
with pd.ExcelWriter(filename) as writer:
# 商品基本信息
if items_data:
basic_info = []
for item in items_data:
info = {
"商品ID": item.get("item_id"),
"标题": item.get("title"),
"类目": item.get("category"),
"品牌": item.get("brand_info", {}).get("brand_name"),
"当前价(元)": item.get("price"),
"原价(元)": item.get("original_price"),
"折扣": round(float(item.get("price", 0))/float(item.get("original_price", 1)), 2) if item.get("original_price") else 0,
"销量": item.get("sales_count"),
"评价数": item.get("comment_count"),
"评分": item.get("avg_rating"),
"总库存": item.get("stock"),
"规格数量": len(item.get("specs", []))
}
basic_info.append(info)
df_basic = pd.DataFrame(basic_info)
df_basic.to_excel(writer, sheet_name='商品基本信息', index=False)
# 规格详情
for i, item in enumerate(items_data):
if item.get("specs"):
spec_details = []
for spec in item.get("specs", []):
details = {
"规格ID": spec.get("spec_id"),
"属性组合": ", ".join([f"{k}:{v}" for k, v in spec.get("attributes", {}).items()]),
"价格(元)": spec.get("price"),
"库存": spec.get("stock"),
"是否有货": "是" if int(spec.get("stock", 0)) > 0 else "否"
}
spec_details.append(details)
df_sku = pd.DataFrame(spec_details)
df_sku.to_excel(writer, sheet_name=f'规格详情_{item.get("item_id")[:6]}', index=False)
# 促销信息
for i, item in enumerate(items_data):
if item.get("promotions"):
promotion_details = []
for promo in item.get("promotions", []):
details = {
"促销ID": promo.get("id"),
"促销类型": promo.get("type"),
"促销名称": promo.get("name"),
"开始时间": promo.get("start_time"),
"结束时间": promo.get("end_time"),
"描述": promo.get("description")
}
promotion_details.append(details)
df_promo = pd.DataFrame(promotion_details)
df_promo.to_excel(writer, sheet_name=f'促销_{item.get("item_id")[:6]}', index=False)
# 分析结果
if analyses:
analysis_summary = []
for analysis in analyses:
summary = {
"商品ID": analysis.get("item_id"),
"标题": analysis.get("title"),
"当前价(元)": analysis["price_analysis"]["current_price"],
"原价(元)": analysis["price_analysis"]["original_price"],
"折扣": analysis["price_analysis"]["discount"],
"降价幅度(元)": analysis["price_analysis"]["price_drop"],
"30天最低价(元)": analysis["history_price_analysis"]["30day_lowest"],
"销量": analysis["sales_analysis"]["sales_count"],
"评分": analysis["sales_analysis"]["avg_rating"],
"好评率": analysis["sales_analysis"]["positive_rate"],
"颜色数": analysis["spec_analysis"]["color_count"],
"尺码数": analysis["spec_analysis"]["size_count"],
"总库存": analysis["spec_analysis"]["total_stock"],
"是否有促销": "是" if analysis["promotion_analysis"]["has_promotion"] else "否"
}
analysis_summary.append(summary)
df_analysis = pd.DataFrame(analysis_summary)
df_analysis.to_excel(writer, sheet_name='分析摘要', index=False)
# 对比结果
if comparison and "error" not in comparison:
df_price = pd.DataFrame(comparison["price_comparison"])
df_price.to_excel(writer, sheet_name='价格对比', index=False)
df_discount = pd.DataFrame(comparison["discount_comparison"])
df_discount.to_excel(writer, sheet_name='折扣对比', index=False)
df_sales = pd.DataFrame(comparison["sales_comparison"])
df_sales.to_excel(writer, sheet_name='销量对比', index=False)
logging.info(f"数据已导出至 {filename}")
except Exception as e:
logging.error(f"导出Excel失败: {e}")
# 示例调用
if __name__ == "__main__":
# 替换为实际的参数(从唯品会开放平台获取)
APP_KEY = "your_app_key"
APP_SECRET = "your_app_secret"
ITEM_ID = "123456789" # 商品ID示例
# 多个商品ID用于批量获取和对比
MULTIPLE_ITEM_IDS = ["123456789", "987654321", "112233445"]
# 初始化API客户端
vip_item = VipItemDetail(APP_KEY, APP_SECRET)
# 若为高级权限,设置更高的频率限制
# vip_item.set_rate_limit(100)
# 1. 获取单个商品详情
print("=== 获取单个商品详情 ===")
item_detail = vip_item.get_item_detail(
item_id=ITEM_ID,
include_promotion=True,
include_spec=True,
include_brand=True,
include_history_price=True, # 获取历史价格
region="110000" # 北京地区
)
if item_detail:
print(f"商品ID: {item_detail.get('item_id')}")
print(f"标题: {item_detail.get('title')[:50]}...")
print(f"类目: {item_detail.get('category')}")
print(f"当前价格: ¥{item_detail.get('price')}")
print(f"原价: ¥{item_detail.get('original_price')}")
print(f"折扣: {round(float(item_detail.get('price', 0))/float(item_detail.get('original_price', 1)), 2)}")
print(f"销量: {item_detail.get('sales_count')}")
print(f"评分: {item_detail.get('avg_rating')}")
print(f"总库存: {item_detail.get('stock')}")
print(f"规格数量: {len(item_detail.get('specs', []))}")
print(f"品牌名称: {item_detail.get('brand_info', {}).get('brand_name')}")
print(f"是否有促销: {'是' if len(item_detail.get('promotions', [])) > 0 else '否'}")
# 2. 分析商品详情
print("\n=== 商品详情分析 ===")
if item_detail:
analysis = vip_item.analyze_item(item_detail)
print("价格分析:")
print(f" 当前价格: ¥{analysis['price_analysis']['current_price']}")
print(f" 原价: ¥{analysis['price_analysis']['original_price']}")
print(f" 折扣: {analysis['price_analysis']['discount']} (省¥{analysis['price_analysis']['price_drop']})")
print(f" 会员价: {'有' if analysis['price_analysis']['has_member_price'] else '无'}")
print("\n历史价格分析:")
if analysis["history_price_analysis"]["has_history"]:
print(f" 历史最低价: ¥{analysis['history_price_analysis']['min_price']}")
print(f" 30天最低价: ¥{analysis['history_price_analysis']['30day_lowest']}")
print(f" 价格变动次数: {analysis['history_price_analysis']['price_change_count']}")
else:
print(" 无历史价格数据")
print("\n规格分析:")
print(f" 总库存: {analysis['spec_analysis']['total_stock']}")
print(f" 颜色数量: {analysis['spec_analysis']['color_count']}")
print(f" 尺码数量: {analysis['spec_analysis']['size_count']}")
print("\n促销分析:")
print(f" 是否有促销: {'是' if analysis['promotion_analysis']['has_promotion'] else '否'}")
if analysis['promotion_analysis']['has_promotion']:
print(f" 促销类型: {', '.join(analysis['promotion_analysis']['promotion_types'])}")
print(f" 是否有优惠券: {'是' if analysis['promotion_analysis']['has_coupon'] else '否'}")
print("\n销售分析:")
print(f" 销量: {analysis['sales_analysis']['sales_count']}")
print(f" 评价数: {analysis['sales_analysis']['comment_count']}")
print(f" 平均评分: {analysis['sales_analysis']['avg_rating']}")
print(f" 好评率: {analysis['sales_analysis']['positive_rate']:.2%}")
# 生成价格历史图表
vip_item.visualize_price_history(item_detail)
# 3. 批量获取多个商品详情并对比
print("\n=== 批量获取与商品对比 ===")
items, success_count = vip_item.batch_get_item_details(
item_ids=MULTIPLE_ITEM_IDS
)
if items and len(items) >= 2:
# 分析每个商品
analyses = [vip_item.analyze_item(item) for item in items]
# 对比商品
comparison = vip_item.compare_items(items)
print("\n价格对比 (从低到高):")
for i, item in enumerate(comparison["price_comparison"][:3], 1):
print(f"{i}. {item['title']} - ¥{item['current_price']} (原价: ¥{item['original_price']})")
print("\n折扣对比 (从低到高):")
for i, item in enumerate(comparison["discount_comparison"][:3], 1):
print(f"{i}. {item['title']} - {item['discount']}折 (促销: {'有' if item['has_promotion'] else '无'})")
print("\n销量对比 (从高到低):")
for i, item in enumerate(comparison["sales_comparison"][:3], 1):
print(f"{i}. {item['title']} - 销量: {item['sales_count']}")
# 4. 可视化对比结果
vip_item.visualize_comparison(comparison)
# 5. 导出数据到Excel
vip_item.export_to_excel(items, analyses, comparison, "唯品会商品详情分析.xlsx")
elif len(items) == 1:
print("获取的商品数量不足,无法进行对比分析")
else:
print("未获取到足够的商品数据")