在电商数据分析、价格监控和市场调研等场景中,获取淘宝平台的商品数据至关重要。本文将分别使用 Python 和 Node.js 两种编程语言,详细介绍如何调用淘宝关键词搜索 API,实现商品数据的采集,并提供完整的代码实现和实践指南。
淘宝 API 接入准备
在接入淘宝 API 之前,需要完成以下准备工作:
- 注册账号:注册账号并完成实名认证。
- 创建应用:获取 ApiKey 和 ApiSecret。
- 申请 API 权限:在应用管理中申请
taobao.tbk.dg.material.optional接口的访问权限。 - 了解 API 参数:熟悉 API 的请求参数和返回格式,例如关键词搜索、排序方式、分页等。
Python 实现方案
下面是使用 Python 调用淘宝关键词搜索 API 的完整代码实现:
import requests
import json
import time
import hmac
import hashlib
from urllib.parse import urlencode
import os
from dotenv import load_dotenv
class TaobaoAPI:
def __init__(self, app_key, app_secret, server_url='https://gw.api.taobao.com/router/rest'):
"""初始化淘宝API客户端"""
self.app_key = app_key
self.app_secret = app_secret
self.server_url = server_url
def generate_sign(self, params):
"""生成API请求签名"""
# 对参数进行排序
sorted_params = sorted(params.items(), key=lambda x: x[0])
# 拼接参数字符串
sign_str = self.app_secret
for k, v in sorted_params:
sign_str += f"{k}{v}"
sign_str += self.app_secret
# 使用HMAC-SHA1算法生成签名
sign = hmac.new(
self.app_secret.encode('utf-8'),
sign_str.encode('utf-8'),
hashlib.sha1
).hexdigest().upper()
return sign
def call(self, method, params):
"""调用淘宝API接口"""
# 公共参数
public_params = {
'app_key': self.app_key,
'method': method,
'format': 'json',
'v': '2.0',
'sign_method': 'hmac',
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
}
# 合并公共参数和业务参数
all_params = {**public_params, **params}
# 生成签名
sign = self.generate_sign(all_params)
all_params['sign'] = sign
# 发送请求
try:
response = requests.post(self.server_url, data=all_params)
response.raise_for_status() # 检查请求是否成功
result = response.json()
return result
except requests.exceptions.RequestException as e:
print(f"请求出错: {e}")
return None
except json.JSONDecodeError as e:
print(f"JSON解析出错: {e}")
return None
def search_taobao_items(app_key, app_secret, keyword, page_no=1, page_size=20, sort='default'):
"""搜索淘宝商品"""
api = TaobaoAPI(app_key, app_secret)
# 业务参数
params = {
'q': keyword,
'page_no': page_no,
'page_size': page_size,
'sort': sort, # 排序方式:default(默认),price-asc(价格从低到高),price-desc(价格从高到低),sale-desc(销量从高到低)
'has_coupon': 'true', # 只搜索有优惠券的商品
'need_free_shipment': 'true', # 只搜索包邮商品
}
# 调用淘宝客商品搜索API
result = api.call('taobao.tbk.dg.material.optional', params)
if result:
# 处理返回结果
if 'tbk_dg_material_optional_response' in result:
response = result['tbk_dg_material_optional_response']
if 'result_list' in response and 'map_data' in response['result_list']:
items = response['result_list']['map_data']
print(f"第 {page_no} 页搜索结果: 找到 {len(items)} 个商品")
return items
else:
print(f"第 {page_no} 页未找到商品数据")
else:
print(f"API调用失败: {result}")
return []
def search_all_pages(app_key, app_secret, keyword, max_pages=10, sort='default'):
"""搜索多页商品数据"""
all_items = []
for page in range(1, max_pages + 1):
print(f"正在搜索第 {page} 页...")
items = search_taobao_items(app_key, app_secret, keyword, page, sort=sort)
if not items:
break # 没有更多数据,退出循环
all_items.extend(items)
# 控制请求频率,避免被限流
time.sleep(1)
print(f"总共搜索到 {len(all_items)} 个商品")
return all_items
def save_to_csv(items, filename='taobao_items.csv'):
"""将商品数据保存到CSV文件"""
import csv
if not items:
print("没有数据可保存")
return
# 定义CSV文件的列名
fieldnames = ['title', 'price', 'original_price', 'sales_volume', 'coupon_amount', 'shop_title', 'item_url']
with open(filename, 'w', newline='', encoding='utf-8-sig') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
# 写入表头
writer.writeheader()
# 写入数据
for item in items:
# 提取需要的字段
row = {
'title': item.get('title', ''),
'price': item.get('zk_final_price', ''),
'original_price': item.get('reserve_price', ''),
'sales_volume': item.get('volume', ''),
'coupon_amount': item.get('coupon_amount', ''),
'shop_title': item.get('shop_title', ''),
'item_url': item.get('item_url', '')
}
writer.writerow(row)
print(f"数据已保存到 {filename}")
if __name__ == "__main__":
# 加载环境变量
load_dotenv()
# 获取AppKey和AppSecret
app_key = os.getenv("TAOBAO_APP_KEY")
app_secret = os.getenv("TAOBAO_APP_SECRET")
if not app_key or not app_secret:
print("请设置TAOBAO_APP_KEY和TAOBAO_APP_SECRET环境变量")
exit(1)
# 搜索关键词
keyword = input("请输入搜索关键词: ")
# 搜索商品
items = search_all_pages(app_key, app_secret, keyword, max_pages=5, sort='price-asc')
# 保存数据
if items:
save_to_csv(items, f"{keyword}_商品数据.csv")
Node.js 实现方案
下面是使用 Node.js 调用淘宝关键词搜索 API 的完整代码实现:
const https = require('https');
const crypto = require('crypto');
const querystring = require('querystring');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
class TaobaoAPI {
constructor(appKey, appSecret, serverUrl = 'https://gw.api.taobao.com/router/rest') {
this.appKey = appKey;
this.appSecret = appSecret;
this.serverUrl = serverUrl;
}
/**
* 生成API请求签名
* @param {Object} params 请求参数
* @returns {string} 签名结果
*/
generateSign(params) {
// 对参数进行排序
const sortedParams = Object.keys(params).sort().reduce((acc, key) => {
acc[key] = params[key];
return acc;
}, {});
// 拼接参数字符串
let signStr = this.appSecret;
for (const key in sortedParams) {
signStr += `${key}${sortedParams[key]}`;
}
signStr += this.appSecret;
// 使用HMAC-SHA1算法生成签名
const sign = crypto
.createHmac('sha1', this.appSecret)
.update(signStr)
.digest('hex')
.toUpperCase();
return sign;
}
/**
* 调用淘宝API接口
* @param {string} method API方法名
* @param {Object} params 业务参数
* @returns {Promise<Object>} API响应结果
*/
call(method, params) {
return new Promise((resolve, reject) => {
// 公共参数
const publicParams = {
app_key: this.appKey,
method: method,
format: 'json',
v: '2.0',
sign_method: 'hmac',
timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)
};
// 合并公共参数和业务参数
const allParams = { ...publicParams, ...params };
// 生成签名
const sign = this.generateSign(allParams);
allParams.sign = sign;
// 解析服务器URL
const url = new URL(this.serverUrl);
// 准备请求参数
const postData = querystring.stringify(allParams);
// 准备HTTP请求选项
const options = {
hostname: url.hostname,
port: url.port || 443,
path: url.pathname,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
// 发送HTTP请求
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const result = JSON.parse(data);
resolve(result);
} catch (error) {
reject(new Error(`JSON解析错误: ${error.message}`));
}
});
});
req.on('error', (error) => {
reject(new Error(`请求错误: ${error.message}`));
});
req.write(postData);
req.end();
});
}
}
/**
* 搜索淘宝商品
* @param {string} appKey 应用Key
* @param {string} appSecret 应用Secret
* @param {string} keyword 搜索关键词
* @param {number} pageNo 页码
* @param {number} pageSize 每页数量
* @param {string} sort 排序方式
* @returns {Promise<Object[]>} 商品列表
*/
async function searchTaobaoItems(appKey, appSecret, keyword, pageNo = 1, pageSize = 20, sort = 'default') {
const api = new TaobaoAPI(appKey, appSecret);
// 业务参数
const params = {
q: keyword,
page_no: pageNo,
page_size: pageSize,
sort: sort, // 排序方式:default(默认),price-asc(价格从低到高),price-desc(价格从高到低),sale-desc(销量从高到低)
has_coupon: 'true', // 只搜索有优惠券的商品
need_free_shipment: 'true' // 只搜索包邮商品
};
try {
// 调用淘宝客商品搜索API
const result = await api.call('taobao.tbk.dg.material.optional', params);
if (result) {
// 处理返回结果
if (result.tbk_dg_material_optional_response) {
const response = result.tbk_dg_material_optional_response;
if (response.result_list && response.result_list.map_data) {
const items = response.result_list.map_data;
console.log(`第 ${pageNo} 页搜索结果: 找到 ${items.length} 个商品`);
return items;
} else {
console.log(`第 ${pageNo} 页未找到商品数据`);
return [];
}
} else {
console.log(`API调用失败:`, result);
return [];
}
} else {
console.log('API调用无响应');
return [];
}
} catch (error) {
console.error(`搜索出错: ${error.message}`);
return [];
}
}
/**
* 搜索多页商品数据
* @param {string} appKey 应用Key
* @param {string} appSecret 应用Secret
* @param {string} keyword 搜索关键词
* @param {number} maxPages 最大搜索页数
* @param {string} sort 排序方式
* @returns {Promise<Object[]>} 所有商品列表
*/
async function searchAllPages(appKey, appSecret, keyword, maxPages = 10, sort = 'default') {
let allItems = [];
for (let page = 1; page <= maxPages; page++) {
console.log(`正在搜索第 ${page} 页...`);
const items = await searchTaobaoItems(appKey, appSecret, keyword, page, 20, sort);
if (items.length === 0) {
break; // 没有更多数据,退出循环
}
allItems = allItems.concat(items);
// 控制请求频率,避免被限流
await new Promise(resolve => setTimeout(resolve, 1000));
}
console.log(`总共搜索到 ${allItems.length} 个商品`);
return allItems;
}
/**
* 将商品数据保存到CSV文件
* @param {Object[]} items 商品列表
* @param {string} filename 文件名
*/
function saveToCSV(items, filename = 'taobao_items.csv') {
if (items.length === 0) {
console.log("没有数据可保存");
return;
}
// 创建CSV内容
let csvContent = '标题,价格,原价,销量,优惠券金额,店铺名称,商品链接\n';
items.forEach(item => {
const row = [
item.title || '',
item.zk_final_price || '',
item.reserve_price || '',
item.volume || '',
item.coupon_amount || '',
item.shop_title || '',
item.item_url || ''
];
// 转义CSV中的特殊字符
const escapedRow = row.map(value => {
if (typeof value === 'string') {
return `"${value.replace(/"/g, '""')}"`;
}
return value;
});
csvContent += escapedRow.join(',') + '\n';
});
// 写入文件
fs.writeFile(filename, csvContent, 'utf8', (err) => {
if (err) {
console.error(`保存CSV文件出错: ${err.message}`);
} else {
console.log(`数据已保存到 ${filename}`);
}
});
}
async function main() {
// 获取AppKey和AppSecret
const appKey = process.env.TAOBAO_APP_KEY;
const appSecret = process.env.TAOBAO_APP_SECRET;
if (!appKey || !appSecret) {
console.error("请设置TAOBAO_APP_KEY和TAOBAO_APP_SECRET环境变量");
return;
}
// 搜索关键词
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
readline.question('请输入搜索关键词: ', async (keyword) => {
readline.close();
try {
// 搜索商品
const items = await searchAllPages(appKey, appSecret, keyword, 5, 'price-asc');
// 保存数据
if (items.length > 0) {
saveToCSV(items, `${keyword}_商品数据.csv`);
}
} catch (error) {
console.error(`程序执行出错: ${error.message}`);
}
});
}
// 执行主函数
main();
开发注意事项与避坑指南
在接入淘宝 API 时,需要注意以下几点:
-
API 权限问题:
- 需要申请
taobao.tbk.dg.material.optional接口的访问权限 - 部分高级功能需要成为淘宝联盟会员并绑定推广位
- 需要申请
-
签名生成规则:
- 参数必须按字典序排序
- 签名过程中不要对参数名和参数值进行 URL 编码
- 签名结果需要转换为大写
-
频率限制:
- 免费应用有 QPS 限制,建议每次请求间隔 1 秒以上
- 超出频率限制会返回错误码
isv.access-control-exceed-limit
-
数据解析注意事项:
- 检查返回结果中是否包含预期的字段
- 处理可能的空值或异常数据格式
- 商品图片 URL 可能需要添加协议前缀
-
合规使用:
- 采集的数据仅用于个人学习或合法商业用途
- 避免过度频繁请求,以免影响 API 服务稳定性
- 遵守协议
扩展功能建议
- 数据可视化:使用 Matplotlib (Python) 或 Chart.js ( Node.js ) 将价格分布等数据可视化
- 定时任务:使用 APScheduler (Python) 或 node-cron ( Node.js ) 实现定时采集数据
- 数据库存储:将数据存入 MySQL 或 MongoDB 等数据库进行长期分析
- 异常处理增强:添加重试机制和更完善的错误处理
通过以上步骤,你可以使用 Python 或 Node.js 快速接入淘宝关键词搜索 API,实现海量商品数据的采集和分析。根据实际需求,你还可以进一步扩展功能,构建更强大的电商数据分析系统。