最近在做一个电商数据分析项目,需要从京东商品详情API提取关键信息。作为Python开发者,我发现虽然JSON解析看似简单,但实际处理电商平台返回的数据时,会遇到各种预料之外的问题。本文将分享我通过实战总结出的完整解析方案,涵盖从基础字段提取到复杂数据处理的全流程。
京东提供了多种数据获取方式:
我建议初学者先用官方测试接口练手。以下是获取单品详情的典型请求示例:
python复制import requests
def get_jd_item(sku_id):
url = f"https://api.jd.com/routerjson?method=jd.union.open.goods.detail&skuIds={sku_id}"
headers = {
"User-Agent": "Mozilla/5.0",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
return response.text
注意:实际使用时需要添加签名参数和授权信息,测试阶段可以先使用模拟数据
核心工具只需要Python标准库的json模块,但根据需求可以搭配:
pandas:用于数据分析和批量处理simplejson:处理超大型JSON文件时性能更好orjson:最快的JSON解析库(需安装)基础环境配置:
bash复制pip install pandas orjson
京东商品API返回的JSON通常包含三层结构:
json复制{
"error_code": 0,
"reason": "success",
"result": {
"sku_id": "100060195820",
"title": "京东京造 轻量便携保温杯...",
"price": "99.9",
"spec_list": [
{"name": "颜色", "value": "白色"},
{"name": "容量", "value": "350ml"}
]
}
}
| 字段路径 | 类型 | 说明 | 示例 |
|---|---|---|---|
| result.sku_id | string | 商品唯一标识 | "100060195820" |
| result.price | string | 当前售价 | "99.9" |
| result.original_price | string | 原价 | "129.9" |
| result.sales | string | 销量显示 | "10万+" |
| result.spec_info | string | 规格简版 | "颜色:白色|容量:350ml" |
| result.spec_list | array | 规格详情 | [{"name":"颜色","value":"白色"}] |
python复制import json
from typing import Dict, Any
def parse_jd_json(json_str: str) -> Dict[str, Any]:
try:
data = json.loads(json_str)
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON: {e}")
if data.get("error_code") != 0:
raise RuntimeError(f"API error: {data.get('reason')}")
result = data.get("result", {})
# 基础字段提取
parsed = {
"sku_id": result.get("sku_id"),
"title": result.get("title"),
"current_price": float(result.get("price", 0)),
"original_price": float(result.get("original_price", 0)),
"sales_text": result.get("sales"),
"in_stock": result.get("stock_state") == "有货"
}
return parsed
关键点:
try-except捕获JSON解析异常.get()方法并提供默认值京东的规格信息有两种表现形式:
推荐优先使用spec_list,处理更规范:
python复制def parse_specifications(item_data: Dict) -> Dict:
spec_list = item_data.get("spec_list", [])
specs = {}
for spec in spec_list:
name = spec.get("name", "").strip()
value = spec.get("value", "").strip()
if name and value:
specs[name] = value
# 回退方案:解析spec_info
if not specs and "spec_info" in item_data:
for pair in item_data["spec_info"].split("|"):
if ":" in pair:
k, v = map(str.strip, pair.split(":", 1))
specs[k] = v
return specs
京东销量显示有几种形式:
转换函数:
python复制def normalize_sales(sales_str: str) -> int:
if not sales_str:
return 0
sales_str = sales_str.replace(",", "").replace("+", "")
if "万" in sales_str:
num_part = sales_str.replace("万", "")
try:
return int(float(num_part) * 10000)
except ValueError:
return 0
else:
try:
return int(float(sales_str))
except ValueError:
return 0
当需要处理大量商品数据时,建议:
示例代码:
python复制import concurrent.futures
def batch_parse(json_strings: List[str], workers=4) -> List[Dict]:
def safe_parse(json_str):
try:
return parse_jd_json(json_str)
except Exception as e:
print(f"Parse failed: {e}")
return None
with concurrent.futures.ThreadPoolExecutor(workers) as executor:
results = list(executor.map(safe_parse, json_strings))
return [r for r in results if r is not None]
将解析结果转为DataFrame便于分析:
python复制import pandas as pd
def create_item_df(parsed_items: List[Dict]) -> pd.DataFrame:
df = pd.DataFrame(parsed_items)
# 计算折扣率
df["discount"] = (1 - df["current_price"] / df["original_price"]).round(2)
# 提取品牌信息(从title中)
df["brand"] = df["title"].str.extract(r"^([^\s]+)")[0]
return df
python复制import orjson
def parse_with_orjson(json_str):
return orjson.loads(json_str)
orjson比标准库快3-5倍
python复制# 不推荐
price = data.get("result", {}).get("price")
# 推荐
result = data.get("result", {})
price = result.get("price")
python复制def read_large_json(file_path):
with open(file_path, "r", encoding="utf-8") as f:
for line in f:
yield json.loads(line)
JSONDecodeError:数据不是合法JSON
KeyError:字段不存在
.get()方法ValueError:类型转换失败
python复制with open("debug.json", "w", encoding="utf-8") as f:
f.write(response_text)
使用JSON验证工具:
打印数据结构:
python复制from pprint import pprint
pprint(data, depth=2) # 限制打印深度
python复制# 存储示例
{
"raw_data": "...",
"parsed_data": {...},
"metadata": {
"fetch_time": "2023-08-20T14:30:00",
"api_version": "v1.2"
}
}
我在实际项目中总结出的最佳实践是:每次解析都记录完整的上下文信息,这样当数据结构变化时,可以快速定位问题并调整解析逻辑。