文章附件下载:www.pan38.com/dow/share.p… 提取密码:4740
这个淘宝批量上传商品工具主要功能包括:
支持从Excel批量导入商品数据 自动压缩和上传商品图片 多线程并发处理提高上传效率 完善的错误处理和重试机制 支持从其他平台一键搬家功能 完整的淘宝API调用封装 商品SKU属性批量设置 地理位置信息设置
import os import time import json import requests from PIL import Image from io import BytesIO import pandas as pd from concurrent.futures import ThreadPoolExecutor
class TaobaoUploader: def init(self, app_key, app_secret, session_key): self.app_key = app_key self.app_secret = app_secret self.session_key = session_key self.base_url = "eco.taobao.com/router/rest" self.headers = { "Content-Type": "application/x-www-form-urlencoded;charset=utf-8" } self.image_cache = {} self.max_workers = 5 self.upload_retry = 3
def _sign_request(self, params):
# 生成签名逻辑
sorted_params = sorted(params.items(), key=lambda x: x[0])
query_string = ""
for k, v in sorted_params:
query_string += f"{k}{v}"
sign = hashlib.md5((self.app_secret + query_string + self.app_secret).encode()).hexdigest().upper()
return sign
def _call_api(self, method, params):
# 调用淘宝API
base_params = {
"method": method,
"app_key": self.app_key,
"session": self.session_key,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"format": "json",
"v": "2.0",
"sign_method": "md5"
}
params.update(base_params)
params["sign"] = self._sign_request(params)
for i in range(self.upload_retry):
try:
response = requests.post(self.base_url, data=params, headers=self.headers)
result = response.json()
if "error_response" in result:
error = result["error_response"]
raise Exception(f"API Error: {error.get('msg', 'Unknown error')}")
return result
except Exception as e:
if i == self.upload_retry - 1:
raise e
time.sleep(1)
def upload_image(self, image_path):
# 上传图片到淘宝
if image_path in self.image_cache:
return self.image_cache[image_path]
try:
with open(image_path, "rb") as f:
image_data = f.read()
# 压缩图片
img = Image.open(BytesIO(image_data))
if img.size[0] > 800 or img.size[1] > 800:
img.thumbnail((800, 800))
buffer = BytesIO()
img.save(buffer, format="JPEG", quality=85)
image_data = buffer.getvalue()
# 上传图片
params = {
"image": ("image.jpg", image_data, "image/jpeg")
}
response = requests.post(
"https://upload.taobao.com/upload/image",
files=params,
headers={"Authorization": f"Bearer {self.session_key}"}
)
result = response.json()
if "url" not in result:
raise Exception("Failed to upload image")
self.image_cache[image_path] = result["url"]
return result["url"]
except Exception as e:
print(f"Failed to upload image {image_path}: {str(e)}")
return None
def process_product(self, product_data):
# 处理单个商品
try:
# 上传主图
main_images = []
for img_path in product_data["main_images"]:
img_url = self.upload_image(img_path)
if img_url:
main_images.append(img_url)
if not main_images:
raise Exception("No valid main images")
# 上传详情图
desc_images = []
for img_path in product_data["desc_images"]:
img_url = self.upload_image(img_path)
if img_url:
desc_images.append(img_url)
# 构建商品参数
params = {
"num": str(product_data["stock"]),
"price": str(product_data["price"]),
"title": product_data["title"],
"desc": product_data["description"],
"cid": str(product_data["category_id"]),
"props": json.dumps(product_data["properties"]),
"sku_properties": json.dumps(product_data["sku_properties"]),
"sku_quantities": json.dumps(product_data["sku_quantities"]),
"sku_prices": json.dumps(product_data["sku_prices"]),
"location.state": product_data["location"]["state"],
"location.city": product_data["location"]["city"],
"pic_path": ";".join(main_images),
"item_images": json.dumps([{"url": url} for url in desc_images])
}
# 调用商品上传API
result = self._call_api("taobao.item.add", params)
return result.get("item_add_response", {}).get("item", {}).get("num_iid")
except Exception as e:
print(f"Failed to process product {product_data['title']}: {str(e)}")
return None
def batch_upload(self, products):
# 批量上传商品
success_count = 0
failed_count = 0
results = []
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures = []
for product in products:
futures.append(executor.submit(self.process_product, product))
for future in futures:
try:
result = future.result()
if result:
success_count += 1
results.append(result)
else:
failed_count += 1
except Exception as e:
failed_count += 1
print(f"Product upload failed: {str(e)}")
print(f"Upload completed. Success: {success_count}, Failed: {failed_count}")
return results
def read_from_excel(self, file_path):
# 从Excel读取商品数据
try:
df = pd.read_excel(file_path)
products = []
for _, row in df.iterrows():
product = {
"title": row["title"],
"price": float(row["price"]),
"stock": int(row["stock"]),
"category_id": int(row["category_id"]),
"description": row.get("description", ""),
"properties": json.loads(row.get("properties", "{}")),
"sku_properties": json.loads(row.get("sku_properties", "[]")),
"sku_quantities": json.loads(row.get("sku_quantities", "[]")),
"sku_prices": json.loads(row.get("sku_prices", "[]")),
"location": {
"state": row.get("state", ""),
"city": row.get("city", "")
},
"main_images": row["main_images"].split(";"),
"desc_images": row.get("desc_images", "").split(";")
}
products.append(product)
return products
except Exception as e:
print(f"Failed to read Excel file: {str(e)}")
return []
def migrate_from_other_platform(self, source_url, auth_token):
# 从其他平台迁移商品
try:
response = requests.get(source_url, headers={"Authorization": f"Bearer {auth_token}"})
products = response.json()
return self.batch_upload(products)
except Exception as e:
print(f"Migration failed: {str(e)}")
return []
if name == "main": # 配置淘宝开放平台应用信息 APP_KEY = "your_app_key" APP_SECRET = "your_app_secret" SESSION_KEY = "your_session_key"
uploader = TaobaoUploader(APP_KEY, APP_SECRET, SESSION_KEY)
# 从Excel批量上传
products = uploader.read_from_excel("products.xlsx")
if products:
uploader.batch_upload(products)
# 从其他平台一键搬家
# uploader.migrate_from_other_platform("https://other-platform.com/api/products", "auth_token")