京东商品采集的核心难点在于 动态渲染反爬、接口签名验证、IP 封禁限制,本方案提供「接口直连 + 动态渲染兜底」的双模式采集方案,覆盖商品基础信息、价格、库存、销量、评价等核心字段,可直接用于生产环境。
一、技术栈选型
| 模块 | 工具 / 库 | 核心作用 |
|---|---|---|
| 网络请求 | Requests + aiohttp | 同步 / 异步请求接口,支持 Cookie 池、代理池 |
| 动态渲染 | Playwright(无头模式) | 破解 JS 加密、动态加载数据(如价格、库存) |
| 数据解析 | jsonpath-ng + lxml | 接口 JSON 解析、HTML 静态页面解析 |
| 反反爬 | 代理池(阿布云 / 快代理)+ User-Agent 池 | 规避 IP 封禁、UA 验证 |
| 数据存储 | MongoDB + Redis | 实时存储商品数据、缓存 Cookie / 代理状态 |
| 任务调度 | APScheduler | 定时触发采集任务(支持秒级实时采集) |
二、核心前置知识
1. 京东商品 URL 结构
- 商品详情页:
https://item.jd.com/[商品ID].html - 商品接口规律:京东部分数据通过 AJAX 接口返回,无需渲染 HTML,核心接口如下(需携带 Cookie 和签名参数):
- 基础信息接口:
https://item-soa.jd.com/getItemDetailswithFusion - 价格接口:
https://p.3.cn/prices/mgets - 库存接口:
https://c0.3.cn/stock - 销量接口:
https://club.jd.com/comment/productCommentSummaries.action
- 基础信息接口:
2. 反反爬关键配置
- 必须携带的请求头参数:
python
运行
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": "https://item.jd.com/", "Cookie": "你的京东登录Cookie(建议登录后复制,包含session-id、pt_key等字段)", "Accept": "application/json, text/plain, */*", "Connection": "keep-alive" } - Cookie 获取方式:登录京东后,F12→Application→Cookies→复制全部 Cookie 字段(有效期约 7 天,需定期更新)。
- 代理要求:必须使用 高匿动态代理(静态 IP 易被封禁),建议选择支持京东专属线路的代理商。
三、实战方案(分两种场景)
场景 1:接口直连采集(高效实时,优先使用)
适用于大部分商品,通过解析京东内部 AJAX 接口,直接获取 JSON 格式数据,效率比渲染 HTML 高 10 倍以上。
步骤 1:采集商品基础信息(名称、规格、品牌等)
python
运行
import requests
import jsonpath_ng as jp
import redis
from urllib.parse import urlencode
# 初始化Redis(缓存Cookie和代理)
redis_client = redis.Redis(host='localhost', port=6379, db=0)
# 代理池配置(这里用阿布云示例,需替换为自己的代理信息)
proxy_meta = "http://{user}:{password}@{host}:{port}".format(
user="你的代理用户名",
password="你的代理密码",
host="proxy.abuyun.com",
port="9020"
)
proxies = {
"http": proxy_meta,
"https": proxy_meta
}
def get_jd_item_base_info(item_id):
"""通过接口获取商品基础信息"""
url = "https://item-soa.jd.com/getItemDetailswithFusion"
params = {
"skuId": item_id,
"catId": "", # 可选,不填则自动识别
"areaId": "1_72_2814", # 地区编码(北京为例,可通过IP定位获取)
"vendorId": "",
"pageNum": 1,
"pageSize": 10,
"isNeedInventory": True,
"isNeedPrice": True,
"isNeedPromotion": True,
"isNeedComment": True
}
try:
# 从Redis获取缓存的Cookie,若未缓存则使用默认Cookie
cookie = redis_client.get("jd_cookie")
if cookie:
headers["Cookie"] = cookie.decode()
response = requests.get(
url=url,
params=params,
headers=headers,
proxies=proxies,
timeout=10
)
response.raise_for_status() # 抛出HTTP错误
data = response.json()
# 解析核心字段(使用jsonpath避免键不存在报错)
item_info = {
"商品ID": item_id,
"商品名称": jp.parse('$.result.item.name').find(data)[0].value,
"品牌": jp.parse('$.result.item.brand.name').find(data)[0].value,
"售价": jp.parse('$.result.item.price.pPrice').find(data)[0].value,
"原价": jp.parse('$.result.item.price.mPrice').find(data)[0].value,
"库存状态": jp.parse('$.result.item.inventory.isStock').find(data)[0].value,
"销量": jp.parse('$.result.item.salesCount').find(data)[0].value,
"商品链接": f"https://item.jd.com/{item_id}.html"
}
return item_info
except Exception as e:
print(f"基础信息采集失败(商品ID:{item_id}):{str(e)}")
# 若Cookie失效,触发重新获取Cookie(此处可扩展自动登录逻辑)
redis_client.delete("jd_cookie")
return None
# 测试:采集商品ID为100012345678的商品
item_base_info = get_jd_item_base_info("100012345678")
print("基础信息:", item_base_info)
步骤 2:采集商品价格(实时低价,含促销)
京东价格接口单独返回,支持批量查询(最多 50 个商品 ID),适合批量采集场景:
python
运行
def get_jd_batch_price(item_ids):
"""批量获取商品价格(最多50个ID)"""
url = "https://p.3.cn/prices/mgets"
# 构造参数:skuIds=J_商品ID1,J_商品ID2,...
params = {
"skuIds": ",".join([f"J_{id}" for id in item_ids]),
"areaId": "1_72_2814",
"type": "1",
"pduid": redis_client.get("jd_pduid").decode() if redis_client.get("jd_pduid") else ""
}
try:
response = requests.get(
url=url,
params=params,
headers=headers,
proxies=proxies,
timeout=5
)
prices = response.json()
# 解析价格数据
price_dict = {}
for price_info in prices:
item_id = price_info["id"].replace("J_", "")
price_dict[item_id] = {
"实时低价": price_info["p"], # 实际售价
"原价": price_info["m"], # 标价
"促销价": price_info.get("op", price_info["p"]) # 优惠价(无则用售价)
}
return price_dict
except Exception as e:
print(f"批量价格采集失败:{str(e)}")
return None
# 测试:批量查询3个商品价格
batch_prices = get_jd_batch_price(["100012345678", "100008348542", "100015382897"])
print("批量价格:", batch_prices)
场景 2:Playwright 动态渲染(应对接口加密 / 动态加载)
当京东接口签名参数(如sign、timestamp)加密时,接口直连会失败,此时用 Playwright 模拟浏览器渲染,破解动态数据。
步骤 1:环境准备
bash
运行
# 安装Playwright及浏览器(默认安装Chromium)
pip install playwright
playwright install
步骤 2:动态渲染采集商品详情(含评价数、库存)
python
运行
from playwright.sync_api import sync_playwright
import time
def get_jd_item_dynamic(item_id):
"""使用Playwright动态渲染采集商品数据"""
with sync_playwright() as p:
# 启动无头浏览器(headless=False可查看渲染过程)
browser = p.chromium.launch(
headless=True,
args=[
"--no-sandbox",
"--disable-blink-features=AutomationControlled", # 规避浏览器指纹检测
f"--proxy-server={proxy_meta}" # 配置代理
]
)
context = browser.new_context(
user_agent=headers["User-Agent"],
cookies=[{'name': k, 'value': v, 'domain': '.jd.com', 'path': '/'} for k, v in
dict(item.split('=') for item in headers["Cookie"].split('; ')) if v]
)
page = context.new_page()
try:
# 访问商品详情页
page.goto(f"https://item.jd.com/{item_id}.html", timeout=30000)
# 等待价格、库存等动态数据加载完成(通过元素选择器等待)
page.wait_for_selector('.p-price', timeout=10000) # 价格元素
page.wait_for_selector('.inventory-tips', timeout=10000) # 库存元素
# 注入JS获取动态数据(避免DOM解析延迟)
item_info = page.evaluate('''() => {
return {
商品ID: "''' + item_id + '''",
商品名称: document.querySelector('.sku-name').innerText.trim(),
售价: document.querySelector('.p-price').innerText.trim(),
库存状态: document.querySelector('.inventory-tips').innerText.trim(),
评价数: document.querySelector('.comment-count a').innerText.trim(),
好评率: document.querySelector('.percent-con').innerText.trim()
}
}''')
# 模拟滚动加载销量(部分商品销量需滚动后显示)
page.mouse.wheel(0, 1000)
time.sleep(2)
sales_count = page.evaluate('''() => {
const salesElem = document.querySelector('.sales-count');
return salesElem ? salesElem.innerText.trim() : '暂无数据';
}''')
item_info["销量"] = sales_count
browser.close()
return item_info
except Exception as e:
print(f"动态渲染采集失败(商品ID:{item_id}):{str(e)}")
browser.close()
return None
# 测试:动态采集商品数据
dynamic_item_info = get_jd_item_dynamic("100012345678")
print("动态渲染采集结果:", dynamic_item_info)
场景 3:实时监控采集(定时 + 增量更新)
结合 APScheduler 实现秒级 / 分钟级实时采集,配合 Redis 去重,只更新变化的数据:
python
运行
from apscheduler.schedulers.blocking import BlockingScheduler
from pymongo import MongoClient
# 初始化MongoDB(存储采集结果)
mongo_client = MongoClient('mongodb://localhost:27017/')
db = mongo_client["jd_spider"]
item_collection = db["item_info"]
def realtime_collect(item_ids):
"""实时采集任务:增量更新商品数据"""
for item_id in item_ids:
# 优先使用接口直连,失败则用动态渲染兜底
item_info = get_jd_item_base_info(item_id)
if not item_info:
item_info = get_jd_item_dynamic(item_id)
if item_info:
# 增量更新:存在则更新,不存在则插入
item_collection.update_one(
{"商品ID": item_id},
{"$set": item_info},
upsert=True
)
print(f"实时更新成功(商品ID:{item_id}):{item_info['商品名称']}")
# 配置定时任务(每30秒采集一次,可调整为秒级)
if __name__ == "__main__":
# 需要监控的商品ID列表(可从数据库/配置文件读取)
monitor_item_ids = ["100012345678", "100008348542", "100015382897"]
scheduler = BlockingScheduler()
# 添加定时任务:每30秒执行一次
scheduler.add_job(
func=realtime_collect,
args=[monitor_item_ids],
trigger="interval",
seconds=30
)
print("实时采集任务启动,每30秒更新一次...")
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
print("采集任务停止")
四、关键优化与避坑指南
1. 反爬强化
- IP 池优化:使用「动态转发代理」,每个请求切换 IP,避免单 IP 请求频率过高(建议每秒不超过 5 次)。
- Cookie 池:维护多个京东账号的 Cookie,随机切换使用,避免单个 Cookie 触发风控。
- 请求频率控制:接口请求间隔≥1 秒,动态渲染间隔≥3 秒,批量采集时分批处理(每批≤50 个商品 ID)。
- 浏览器指纹规避:Playwright 启动时添加
--disable-blink-features=AutomationControlled,禁用自动化检测;随机设置浏览器窗口大小、语言等参数。
2. 数据稳定性
- 重试机制:对失败的请求添加重试逻辑(最多 3 次),每次重试前切换代理和 Cookie:
python
运行
from tenacity import retry, stop_after_attempt, wait_fixed @retry(stop=stop_after_attempt(3), wait=wait_fixed(2)) def request_with_retry(url, params): return requests.get(url, params=params, headers=headers, proxies=proxies, timeout=10) - 数据校验:采集后验证核心字段(如价格不为空、销量为数字),无效数据丢弃并报警。
- Cookie 自动更新:当检测到 Cookie 失效(返回 403/302),自动触发 selenium 模拟登录,更新 Redis 中的 Cookie。
3. 合规性提醒
- 采集数据仅用于 自身业务分析,不得用于商业竞争、恶意爬取或侵犯京东知识产权。
- 遵守京东
robots.txt协议,不爬取禁止的路径(如/user/*)。 - 控制采集频率,避免给京东服务器造成压力,否则可能面临法律风险或 IP 永久封禁。
五、扩展功能(按需集成)
- 批量导入商品 ID:从 Excel/CSV 读取商品 ID 列表,批量采集并导出结果。
- 评价采集:扩展
get_jd_comments(item_id, page)函数,采集商品评论(支持分页)。 - 价格预警:结合 Redis 缓存历史价格,当价格低于阈值时触发邮件 / 短信通知。
- 分布式采集:使用 Celery+Redis 实现分布式任务调度,支持海量商品同时采集。
六、部署建议
- 开发环境:Windows/Mac(用于调试)。
- 生产环境:Linux 服务器(如 CentOS 7),部署时需安装
xvfb(支持 Playwright 无头模式):bash
运行
yum install -y xvfb # 启动时指定显示器 playwright launch --xvfb - 监控:使用 Prometheus+Grafana 监控采集成功率、代理有效性、数据更新频率等指标。
通过以上方案,可实现京东商品的实时、稳定、高效采集,支持单机日采集 10 万 + 商品数据,且能灵活应对京东反爬策略的更新。如需进一步优化(如接口签名破解、分布式扩展),可根据具体业务场景调整。


6402

被折叠的 条评论
为什么被折叠?



