在电商数据分析和内容运营领域,获取商品主图视频是一项常见但颇具挑战性的需求。作为一名长期从事电商数据采集的开发者,我经常需要处理淘宝商品视频的获取任务。经过多次实践和优化,我总结出两种可靠的解决方案:官方API接口和Web端逆向工程。
淘宝商品主图视频通常包含商品的核心展示内容,时长在9-30秒之间,分辨率可达720p甚至1080p。这些视频对于竞品分析、内容运营和选品决策都具有重要价值。然而,淘宝的视频获取机制相对复杂,需要开发者掌握特定的技术方法。
使用淘宝开放平台官方API是最稳定合规的获取方式。首先需要注册成为淘宝开放平台开发者并创建应用:
提示:个人开发者账号无法申请此接口权限,必须使用企业资质注册。审核通常需要1-3个工作日。
淘宝API采用OAuth2.0认证机制,我们需要先获取access_token:
python复制import requests
import time
import hashlib
APP_KEY = "你的AppKey"
APP_SECRET = "你的AppSecret"
def get_token():
url = "https://oauth.taobao.com/token"
params = {
"grant_type": "client_credentials",
"client_id": APP_KEY,
"client_secret": APP_SECRET,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
}
response = requests.post(url, data=params)
return response.json()["access_token"]
这里使用的是"client_credentials"模式,即机器对机器认证,不需要用户授权。获取到的token有效期为24小时,可以缓存复用。
淘宝API要求对所有请求参数进行签名验证。签名算法如下:
python复制def _sign(params: dict) -> str:
# 过滤空值参数
params = {k: v for k, v in params.items() if v is not None}
# 拼接签名字符串
string = APP_SECRET + "".join(f"{k}{v}" for k, v in sorted(params.items())) + APP_SECRET
# 计算MD5并转为大写
return hashlib.md5(string.encode()).hexdigest().upper()
签名过程需要注意:
核心接口调用代码如下:
python复制def item_video(num_iid: str, token: str):
url = "https://eco.taobao.com/router/rest"
params = {
"method": "taobao.item_video",
"app_key": APP_KEY,
"access_token": token,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"format": "json",
"v": "2.0",
"sign_method": "md5",
"num_iid": num_iid,
"fields": "url,duration,cover_url"
}
params["sign"] = _sign(params)
res = requests.post(url, data=params).json()
if "error_response" in res:
raise RuntimeError(res["error_response"]["msg"])
return res["item_video_response"]["video"]
接口返回的数据包含三个关键字段:
获取到视频URL后,我们可以使用流式下载来保存视频文件:
python复制def download(mp4_url: str, filename: str):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
with requests.get(mp4_url, stream=True, headers=headers) as r:
with open(filename, "wb") as f:
for chunk in r.iter_content(chunk_size=1024 * 64):
if chunk:
f.write(chunk)
print("视频已保存:", filename)
使用流式下载(chunk_size=64KB)可以避免大文件占用过多内存,同时设置合理的User-Agent可以降低被拦截的风险。
当无法使用官方API时,我们可以通过分析淘宝网页端的视频请求来获取视频数据。具体步骤如下:
典型请求URL格式:
code复制https://h5api.m.taobao.com/h5/mtop.taobao.detail.getvideo/1.0/?jsv=2.6.1&appKey=12574478&t=...&sign=...&data={"itemId":"728649613560","videoType":"main"}
我们需要模拟这个请求的签名和参数构造:
python复制import requests
import time
import json
import random
import hashlib
from urllib.parse import quote
APP_KEY = "12574478" # 淘宝H5固定AppKey
APP_SECRET = "" # Web端为空
def h5_sign(data: str, t: str) -> str:
return hashlib.md5((APP_SECRET + t + data + APP_SECRET).encode()).hexdigest()
def get_video_id(num_iid: str):
t = str(int(time.time() * 1000))
data = json.dumps({"itemId": num_iid, "videoType": "main"}, separators=(",", ":"))
params = {
"jsv": "2.6.1",
"appKey": APP_KEY,
"t": t,
"api": "mtop.taobao.detail.getvideo",
"v": "1.0",
"type": "jsonp",
"dataType": "jsonp",
"callback": f"mtopjsonp{random.randint(1000, 9999)}",
"data": data,
"sign": h5_sign(data, t)
}
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
"Referer": "https://item.taobao.com/"
}
url = "https://h5api.m.taobao.com/h5/mtop.taobao.detail.getvideo/1.0/"
response = requests.get(url, params=params, headers=headers)
# 解析JSONP响应
json_str = re.search(r"\((.+?)\)", response.text).group(1)
return json.loads(json_str)["data"]
从上述接口获取到videoId后,我们可以构造视频播放地址:
python复制def get_video_url(video_id: str):
play_url = f"https://v.taobao.com/video/play?videoId={video_id}&format=mp4&definition=720p"
# 处理302跳转获取真实地址
response = requests.get(play_url, allow_redirects=False)
if response.status_code == 302:
return response.headers["Location"]
raise RuntimeError("获取视频地址失败")
实际视频地址通常是一个CDN链接,格式如:
code复制https://cloud.video.taobao.com/play/u/.../p/1/e/6/t/1/...mp4
对于大量视频下载需求,我们可以使用asyncio实现异步并发:
python复制import aiohttp
import aiofiles
import asyncio
async def aio_download(url: str, path: str):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
async with aiofiles.open(path, "wb") as file:
async for chunk in response.content.iter_chunked(1024 * 64):
await file.write(chunk)
async def batch_download(video_list: list):
semaphore = asyncio.Semaphore(50) # 控制并发数
async def task(video_info):
async with semaphore:
try:
await aio_download(video_info["url"], f"{video_info['id']}.mp4")
print(f"成功下载: {video_info['id']}")
except Exception as e:
print(f"下载失败 {video_info['id']}: {str(e)}")
await asyncio.gather(*[task(video) for video in video_list])
为避免被封禁,建议采取以下措施:
python复制import random
PROXY_POOL = ["http://ip1:port", "http://ip2:port", ...]
def get_random_proxy():
return random.choice(PROXY_POOL)
def get_random_delay():
return random.uniform(0.2, 1.0)
| 错误代码 | 原因 | 解决方案 |
|---|---|---|
| 7 | 无效的AppKey | 检查AppKey是否正确 |
| 11 | 无效的签名 | 检查签名算法实现 |
| 25 | 权限不足 | 确认已申请item_video接口权限 |
| 40 | 调用次数超限 | 免费档1000次/天,可升级套餐 |
403 Forbidden错误
视频ID获取失败
302跳转失败
通过批量获取同类商品的主图视频,可以分析:
获取优质商品视频可用于:
分析大量商品视频可以帮助:
在实际项目中,我通常会结合两种方案:使用官方API获取核心数据,当遇到限制时切换到Web方案作为补充。同时会建立本地缓存机制,避免重复请求相同数据。对于大规模采集任务,建议分布式部署在多台服务器,并做好任务调度和失败重试机制。