手动上架TikTok太慢?RPA一键批量上架商品,效率提升3000%🚀
每天重复上架TikTok商品到手抽筋?图片处理、信息填写、价格设置到崩溃?别慌!作为影刀RPA的资深布道者,今天我要分享一个硬核技术方案,用RPA+AI实现TikTok商品全自动上架,让你彻底告别手动操作的噩梦!
一、背景痛点:商品上架的"效率黑洞"
在TikTok电商运营中,商品上架是基础但极其耗时的环节,手动操作简直就是一场效率灾难:
手动上架的十大痛点:
-
重复操作爆炸:每个商品都要重复填写标题、描述、价格、库存,枯燥到怀疑人生
-
图片处理繁琐:图片裁剪、尺寸调整、格式转换,每个步骤都耗时
-
信息填写复杂:商品属性、规格变体、物流设置,手动操作极易出错
-
多语言障碍:需要为不同市场填写多语言信息,翻译复制到手软
-
批量操作缺失:无法批量上架,新品上市时工作量爆炸
-
数据同步滞后:商品信息需要手动从ERP同步,效率低下
-
错误排查困难:上架失败时,手动排查问题耗时耗力
-
平台限制规避:手动操作难以规避平台频次限制,容易触发风控
-
多店铺管理混乱:切换不同店铺上架容易混淆,效率低下
-
规模扩展瓶颈:商品数量增加时,手动方式根本无法应对
数据冲击:按每个商品手动上架平均耗时10分钟计算,上架50个商品就要500分钟!这时间本可以用来优化商品策略或分析销售数据。
灵魂拷问 :当竞争对手用自动化系统批量上架数百商品时,你还要苦哈哈地一个个手动填写吗?今天,我们就用影刀RPA彻底颠覆传统商品上架方式!
二、解决方案:智能商品上架工作流设计
我们的核心思路是构建一个AI赋能的自动化上架系统,实现从数据准备到上架完成的全链路自动化。
整体架构:
商品数据准备 → 图片智能处理 → 多语言自动翻译 → 平台自动登录 → 批量信息填写 → 智能规避限制 → 上架状态监控 → 异常自动重试 → 数据同步更新
技术亮点:
-
智能图片优化:自动裁剪、压缩、格式转换商品图片
-
多语言AI翻译:基于商品信息自动生成多语言描述
-
批量上架引擎:支持同时上架多个商品,大幅提升效率
-
智能频率控制:自动控制操作频率,规避平台限制
-
多店铺管理:支持多个TikTok店铺轮换上架
-
实时状态监控:自动监控上架状态,异常情况及时处理
-
数据自动同步:上架完成后自动同步到ERP系统
这个方案不仅开箱即用,还能通过配置适应不同商品类型和店铺需求!
三、代码实现:手把手搭建商品上架机器人
下面我用影刀RPA的设计思路和详细代码,带你一步步构建这个智能上架系统。
环境准备
-
工具:影刀RPA社区版 + 浏览器自动化组件
-
数据源:商品信息Excel、图片素材库、多语言词库
-
平台:TikTok Seller Center
-
依赖库:pandas, PIL, googletrans, selenium
核心代码实现
# TikTok商品智能上架系统
from shadowbot import Browser, Excel, Image, AI, System, Database
import pandas as pd
import time
from datetime import datetime
import os
from PIL import Image as PILImage
import requests
from googletrans import Translator
import json
class TiktokProductUploader:
def __init__(self):
self.products_data = []
self.upload_results = {}
self.accounts = []
self.translator = Translator()
def main_flow(self):
"""主流程:从商品准备到上架完成"""
try:
print("🚀 启动TikTok商品智能上架系统...")
# 步骤1:加载商品数据和账号配置
self.load_configurations()
# 步骤2:商品数据预处理
self.preprocess_products_data()
# 步骤3:初始化浏览器环境
browser = self.init_browser()
# 步骤4:登录TikTok商家后台
self.login_seller_center(browser)
# 步骤5:批量上架商品
for product in self.products_data:
print(f"🛍️ 上架商品: {product['name']}")
# 选择最优店铺
account = self.select_best_account()
# 处理商品图片
processed_images = self.process_product_images(product)
# 执行上架流程
result = self.upload_single_product(browser, product, processed_images, account)
self.upload_results[product['sku']] = result
# 店铺冷却
self.account_cooldown(account)
# 步骤6:生成上架报告
self.generate_upload_report()
# 步骤7:数据同步更新
self.sync_to_erp_system()
print(f"🎉 商品上架完成!成功处理 {len(self.products_data)} 个商品")
except Exception as e:
print(f"❌ 系统执行失败: {e}")
self.error_handling(e)
def load_configurations(self):
"""加载商品数据和账号配置"""
print("📥 加载配置数据...")
# 加载商品数据
excel_path = "C:\\商品数据\\待上架商品列表.xlsx"
if File.exists(excel_path):
products_df = Excel.read_dataframe(excel_path)
for _, row in products_df.iterrows():
product = {
'sku': row['SKU'],
'name': row['商品名称'],
'category': row['商品类别'],
'price': float(row['价格']),
'cost': float(row['成本价']),
'stock': int(row['库存']),
'weight': float(row['重量']),
'description': row['商品描述'],
'specifications': json.loads(row['规格']) if pd.notna(row['规格']) else {},
'image_paths': row['图片路径'].split(';') if pd.notna(row['图片路径']) else [],
'target_markets': row['目标市场'].split(';') if pd.notna(row['目标市场']) else ['US'],
'tags': row['标签'].split(';') if pd.notna(row['标签']) else []
}
self.products_data.append(product)
# 加载店铺账号配置
accounts_path = "C:\\账号管理\\TikTok店铺账号.json"
if File.exists(accounts_path):
with open(accounts_path, 'r', encoding='utf-8') as f:
self.accounts = json.load(f)
print(f"✅ 成功加载 {len(self.products_data)} 个商品, {len(self.accounts)} 个店铺账号")
def preprocess_products_data(self):
"""商品数据预处理"""
print("🔧 商品数据预处理...")
for product in self.products_data:
# 生成多语言信息
product['multilingual_info'] = self.generate_multilingual_info(product)
# 生成优化后的标题和描述
product['optimized_title'] = self.optimize_product_title(product['name'])
product['optimized_description'] = self.optimize_product_description(product['description'])
# 计算推荐价格
product['recommended_price'] = self.calculate_recommended_price(product)
# 生成搜索关键词
product['search_keywords'] = self.generate_search_keywords(product)
def generate_multilingual_info(self, product):
"""生成多语言商品信息"""
multilingual = {}
target_languages = product['target_markets']
# 语言代码映射
language_map = {
'US': 'en', 'UK': 'en', 'CA': 'en',
'FR': 'fr', 'DE': 'de', 'IT': 'it',
'ES': 'es', 'JP': 'ja', 'KR': 'ko'
}
for market in target_languages:
lang_code = language_map.get(market, 'en')
try:
# 翻译标题
translated_title = self.translator.translate(
product['name'], dest=lang_code
).text
# 翻译描述
translated_description = self.translator.translate(
product['description'], dest=lang_code
).text
multilingual[market] = {
'title': translated_title,
'description': translated_description,
'tags': [self.translator.translate(tag, dest=lang_code).text
for tag in product['tags']]
}
except Exception as e:
print(f"翻译失败 {market}: {e}")
# 使用英文作为备选
multilingual[market] = {
'title': product['name'],
'description': product['description'],
'tags': product['tags']
}
return multilingual
def optimize_product_title(self, title):
"""优化商品标题"""
# 移除特殊字符
cleaned_title = re.sub(r'[^\w\s]', '', title)
# 添加热门关键词
hot_keywords = ['2024', 'New', 'Hot', 'Best Seller', 'Trending']
optimized = f"{cleaned_title} - {random.choice(hot_keywords)}"
# 限制标题长度(TikTok限制)
return optimized[:120] # TikTok标题长度限制
def optimize_product_description(self, description):
"""优化商品描述"""
# 添加表情符号
emojis = ['⭐', '🔥', '🚀', '💫', '🎯', '✨']
emoji_line = ' '.join(random.sample(emojis, 3))
# 结构化描述
optimized = f"{emoji_line}\n\n{description}\n\n{emoji_line}"
# 添加号召性用语
ctas = [
"Limited Stock! Order Now! 🛒",
"Free Shipping Worldwide! 🌍",
"30-Day Money Back Guarantee! ✅"
]
optimized += f"\n\n{random.choice(ctas)}"
return optimized
def calculate_recommended_price(self, product):
"""计算推荐价格"""
base_price = product['price']
cost = product['cost']
# 基于成本和市场竞争计算推荐价格
recommended = base_price
# 确保有合理的利润率(至少30%)
min_profit_margin = 0.3
if cost > 0:
min_price = cost / (1 - min_profit_margin)
recommended = max(recommended, min_price)
# 心理定价(以.99结尾)
recommended = math.floor(recommended) + 0.99
return round(recommended, 2)
def generate_search_keywords(self, product):
"""生成搜索关键词"""
base_keywords = product['tags']
# 添加类别相关关键词
category_keywords = {
'electronics': ['tech', 'gadget', 'electronic', 'device'],
'clothing': ['fashion', 'wear', 'apparel', 'outfit'],
'beauty': ['cosmetic', 'skincare', 'makeup', 'beauty'],
'home': ['home', 'household', 'decor', 'living']
}
category = product['category'].lower()
for key, words in category_keywords.items():
if key in category:
base_keywords.extend(words)
break
# 去重并限制数量
unique_keywords = list(set(base_keywords))
return unique_keywords[:10] # TikTok关键词数量限制
def init_browser(self):
"""初始化浏览器环境"""
browser = Browser.open_browser("chrome")
Browser.set_window_size(browser, 1400, 900)
Browser.set_timeout(browser, 30)
# 设置移动端用户代理(TikTok对移动端更友好)
Browser.set_headers(browser, {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
'Accept-Language': 'en-US,en;q=0.9'
})
return browser
def login_seller_center(self, browser):
"""登录TikTok商家后台"""
print("🔐 登录TikTok商家后台...")
try:
# 访问商家后台
Browser.navigate_to(browser, "https://seller.tiktok.com")
System.wait(5)
# 检查是否已登录
if self.check_seller_login(browser):
print("✅ 已处于登录状态")
return
# 执行登录
self.perform_seller_login(browser)
except Exception as e:
raise Exception(f"商家后台登录失败: {e}")
def check_seller_login(self, browser):
"""检查商家后台登录状态"""
try:
# 查找登录后的标识元素
dashboard_element = Browser.find_element(browser, "xpath",
"//div[contains(text(), 'Dashboard')]")
return dashboard_element is not None
except:
return False
def perform_seller_login(self, browser):
"""执行商家后台登录"""
if not self.accounts:
raise Exception("没有可用的店铺账号")
account = self.accounts[0] # 使用第一个账号登录
try:
# 点击登录按钮
login_btn = Browser.find_element(browser, "xpath",
"//button[contains(text(), 'Log in')]")
Browser.click(login_btn)
System.wait(3)
# 输入用户名/邮箱
username_input = Browser.find_element(browser, "xpath",
"//input[@type='email' or @type='text']")
Browser.input_text(username_input, account['username'])
# 点击继续
continue_btn = Browser.find_element(browser, "xpath",
"//button[contains(text(), 'Continue')]")
Browser.click(continue_btn)
System.wait(3)
# 输入密码
password_input = Browser.find_element(browser, "xpath",
"//input[@type='password']")
Browser.input_text(password_input, account['password'])
# 点击登录
submit_btn = Browser.find_element(browser, "xpath",
"//button[@type='submit']")
Browser.click(submit_btn)
# 等待登录完成
System.wait(10)
if not self.check_seller_login(browser):
raise Exception("登录验证失败")
print("✅ TikTok商家后台登录成功")
except Exception as e:
raise Exception(f"登录过程失败: {e}")
def select_best_account(self):
"""选择最优上架店铺"""
if not self.accounts:
raise Exception("没有可用的店铺账号")
# 基于店铺状态、权重等选择最优店铺
available_accounts = [acc for acc in self.accounts if acc['status'] == 'active']
if not available_accounts:
raise Exception("没有活跃的店铺账号")
# 按权重和最近使用时间选择
best_account = min(available_accounts,
key=lambda x: (x.get('last_used', 0), -x['weight']))
# 更新最后使用时间
best_account['last_used'] = time.time()
print(f" 🏪 选择店铺: {best_account['username']}")
return best_account
def process_product_images(self, product):
"""处理商品图片"""
print(" 🖼️ 处理商品图片...")
processed_images = []
for img_path in product['image_paths']:
if not File.exists(img_path):
print(f" 图片不存在: {img_path}")
continue
try:
# 图片预处理
processed_path = self.preprocess_product_image(img_path)
processed_images.append(processed_path)
except Exception as e:
print(f" 图片处理失败 {img_path}: {e}")
# 使用原图作为备选
processed_images.append(img_path)
return processed_images
def preprocess_product_image(self, image_path):
"""商品图片预处理"""
# 创建输出路径
output_dir = "C:\\临时图片\\"
if not File.exists(output_dir):
File.create_directory(output_dir)
output_path = os.path.join(output_dir, f"processed_{os.path.basename(image_path)}")
try:
# 打开图片
with PILImage.open(image_path) as img:
# 转换为RGB(确保兼容性)
if img.mode != 'RGB':
img = img.convert('RGB')
# 调整尺寸(TikTok推荐尺寸)
img = self.resize_image_for_tiktok(img)
# 优化图片质量
img = self.optimize_image_quality(img)
# 添加水印(可选)
img = self.add_watermark_if_needed(img)
# 保存处理后的图片
img.save(output_path, 'JPEG', quality=85, optimize=True)
return output_path
except Exception as e:
print(f" 图片预处理失败: {e}")
return image_path # 返回原图
def resize_image_for_tiktok(self, img):
"""调整图片尺寸适应TikTok要求"""
# TikTok推荐图片尺寸
target_size = (1000, 1000) # 正方形图片
# 计算调整尺寸
img.thumbnail(target_size, PILImage.Resampling.LANCZOS)
# 如果图片不是正方形,添加白色背景
if img.size != target_size:
new_img = PILImage.new('RGB', target_size, (255, 255, 255))
# 计算居中位置
x = (target_size[0] - img.size[0]) // 2
y = (target_size[1] - img.size[1]) // 2
new_img.paste(img, (x, y))
img = new_img
return img
def optimize_image_quality(self, img):
"""优化图片质量"""
# 这里可以添加锐化、对比度调整等
# 简化处理,直接返回原图
return img
def add_watermark_if_needed(self, img):
"""添加水印(如果需要)"""
# 可选功能,根据需求实现
# 比如添加品牌logo等
return img
def upload_single_product(self, browser, product, images, account):
"""上架单个商品"""
print(f" 📤 上架商品到店铺: {account['username']}")
try:
# 导航到商品管理页面
self.navigate_to_product_management(browser)
# 点击添加商品按钮
self.click_add_product_button(browser)
# 填写商品基本信息
self.fill_product_basic_info(browser, product)
# 上传商品图片
self.upload_product_images(browser, images)
# 填写价格和库存
self.fill_price_and_inventory(browser, product)
# 填写物流信息
self.fill_shipping_info(browser, product)
# 设置商品规格(如果有)
if product['specifications']:
self.set_product_variants(browser, product)
# 提交商品上架
success = self.submit_product_upload(browser)
# 获取商品链接(如果上架成功)
product_url = self.get_product_url(browser) if success else None
# 记录上架结果
result = {
'sku': product['sku'],
'account': account['username'],
'upload_time': datetime.now(),
'success': success,
'product_url': product_url,
'price': product['recommended_price'],
'stock': product['stock']
}
return result
except Exception as e:
print(f" ❌ 商品上架失败: {e}")
return {
'sku': product['sku'],
'account': account['username'],
'success': False,
'error': str(e),
'upload_time': datetime.now()
}
def navigate_to_product_management(self, browser):
"""导航到商品管理页面"""
try:
# 点击商品管理菜单
product_menu = Browser.find_element(browser, "xpath",
"//span[contains(text(), 'Products') or contains(text(), '商品')]")
Browser.click(product_menu)
System.wait(3)
# 点击商品列表子菜单
product_list = Browser.find_element(browser, "xpath",
"//span[contains(text(), 'Product List') or contains(text(), '商品列表')]")
Browser.click(product_list)
System.wait(3)
except Exception as e:
raise Exception(f"导航到商品管理页面失败: {e}")
def click_add_product_button(self, browser):
"""点击添加商品按钮"""
try:
# 查找添加商品按钮
add_btn = Browser.find_element(browser, "xpath",
"//button[contains(text(), 'Add Product') or contains(text(), '添加商品')]")
Browser.click(add_btn)
System.wait(3)
except Exception as e:
raise Exception(f"点击添加商品按钮失败: {e}")
def fill_product_basic_info(self, browser, product):
"""填写商品基本信息"""
try:
# 输入商品标题
title_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='Product title' or @placeholder='商品标题']")
Browser.clear_text(title_input)
Browser.input_text(title_input, product['optimized_title'])
# 输入商品描述
desc_input = Browser.find_element(browser, "xpath",
"//textarea[@placeholder='Product description' or @placeholder='商品描述']")
Browser.clear_text(desc_input)
Browser.input_text(desc_input, product['optimized_description'])
# 选择商品类别
self.select_product_category(browser, product['category'])
# 输入商品标签
self.input_product_tags(browser, product['search_keywords'])
System.wait(2)
except Exception as e:
raise Exception(f"填写商品基本信息失败: {e}")
def select_product_category(self, browser, category):
"""选择商品类别"""
try:
# 点击类别选择框
category_dropdown = Browser.find_element(browser, "xpath",
"//div[contains(@class, 'category-select')]")
Browser.click(category_dropdown)
System.wait(2)
# 搜索并选择类别
category_search = Browser.find_element(browser, "xpath",
"//input[@placeholder='Search category' or @placeholder='搜索类别']")
Browser.input_text(category_search, category)
System.wait(2)
# 选择搜索结果中的第一个选项
first_option = Browser.find_element(browser, "xpath",
"//div[contains(@class, 'category-option')]")
Browser.click(first_option)
System.wait(1)
except Exception as e:
print(f" 选择商品类别失败: {e}")
# 这不是关键错误,继续执行
def input_product_tags(self, browser, tags):
"""输入商品标签"""
try:
# 找到标签输入框
tags_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='Add tags' or @placeholder='添加标签']")
for tag in tags[:5]: # TikTok限制标签数量
Browser.input_text(tags_input, tag)
Browser.press_key(tags_input, "Enter")
System.wait(0.5)
except Exception as e:
print(f" 输入商品标签失败: {e}")
# 这不是关键错误,继续执行
def upload_product_images(self, browser, images):
"""上传商品图片"""
try:
# 找到图片上传区域
upload_area = Browser.find_element(browser, "xpath",
"//div[contains(@class, 'upload-area')]")
for img_path in images[:8]: # TikTok限制图片数量
# 上传图片
Browser.upload_file(upload_area, img_path)
System.wait(2) # 等待上传完成
# 检查上传是否成功
if not self.check_image_upload_success(browser):
print(f" 图片上传失败: {img_path}")
except Exception as e:
raise Exception(f"上传商品图片失败: {e}")
def check_image_upload_success(self, browser):
"""检查图片上传是否成功"""
try:
# 查找上传成功的标识
success_indicator = Browser.find_element(browser, "xpath",
"//div[contains(@class, 'upload-success')]")
return success_indicator is not None
except:
return False
def fill_price_and_inventory(self, browser, product):
"""填写价格和库存"""
try:
# 输入价格
price_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='Price' or contains(@name, 'price')]")
Browser.clear_text(price_input)
Browser.input_text(price_input, str(product['recommended_price']))
# 输入库存
stock_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='Stock' or contains(@name, 'stock')]")
Browser.clear_text(stock_input)
Browser.input_text(stock_input, str(product['stock']))
# 输入SKU
sku_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='SKU']")
if sku_input:
Browser.clear_text(sku_input)
Browser.input_text(sku_input, product['sku'])
System.wait(1)
except Exception as e:
raise Exception(f"填写价格和库存失败: {e}")
def fill_shipping_info(self, browser, product):
"""填写物流信息"""
try:
# 找到物流信息区域
shipping_section = Browser.find_element(browser, "xpath",
"//div[contains(text(), 'Shipping') or contains(text(), '物流')]")
Browser.click(shipping_section)
System.wait(2)
# 设置商品重量
weight_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='Weight' or contains(@name, 'weight')]")
if weight_input:
Browser.clear_text(weight_input)
Browser.input_text(weight_input, str(product['weight']))
# 选择物流模板(使用默认模板)
template_dropdown = Browser.find_element(browser, "xpath",
"//div[contains(@class, 'shipping-template')]")
if template_dropdown:
Browser.click(template_dropdown)
System.wait(1)
# 选择第一个模板
first_template = Browser.find_element(browser, "xpath",
"//div[contains(@class, 'template-option')]")
Browser.click(first_template)
System.wait(1)
except Exception as e:
print(f" 填写物流信息失败: {e}")
# 这不是关键错误,继续执行
def set_product_variants(self, browser, product):
"""设置商品规格变体"""
try:
# 检查是否有规格变体选项
variant_section = Browser.find_element(browser, "xpath",
"//div[contains(text(), 'Variants') or contains(text(), '规格')]")
if not variant_section:
return
Browser.click(variant_section)
System.wait(2)
# 添加规格变体
for variant_type, options in product['specifications'].items():
# 添加规格类型(如颜色、尺寸)
self.add_variant_type(browser, variant_type)
# 添加规格选项
for option in options:
self.add_variant_option(browser, option)
except Exception as e:
print(f" 设置商品规格失败: {e}")
# 这不是关键错误,继续执行
def add_variant_type(self, browser, variant_type):
"""添加规格类型"""
try:
# 点击添加规格按钮
add_variant_btn = Browser.find_element(browser, "xpath",
"//button[contains(text(), 'Add Variant')]")
Browser.click(add_variant_btn)
System.wait(1)
# 输入规格名称
variant_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='Variant name']")
Browser.input_text(variant_input, variant_type)
except Exception as e:
print(f" 添加规格类型失败: {e}")
def add_variant_option(self, browser, option):
"""添加规格选项"""
try:
# 找到选项输入框
option_input = Browser.find_element(browser, "xpath",
"//input[@placeholder='Option']")
Browser.input_text(option_input, option)
Browser.press_key(option_input, "Enter")
except Exception as e:
print(f" 添加规格选项失败: {e}")
def submit_product_upload(self, browser):
"""提交商品上架"""
try:
# 找到提交按钮
submit_btn = Browser.find_element(browser, "xpath",
"//button[contains(text(), 'Submit') or contains(text(), '提交')]")
Browser.click(submit_btn)
# 等待上架完成
System.wait(10)
# 检查上架是否成功
success_indicator = Browser.find_element(browser, "xpath",
"//div[contains(text(), 'success') or contains(text(), '成功')]")
return success_indicator is not None
except Exception as e:
raise Exception(f"提交商品上架失败: {e}")
def get_product_url(self, browser):
"""获取商品链接"""
try:
# 在上架成功页面获取商品链接
product_link = Browser.find_element(browser, "xpath",
"//a[contains(@href, '/product/')]")
return Browser.get_attribute(product_link, "href") if product_link else None
except:
return None
def account_cooldown(self, account):
"""店铺冷却"""
cooldown_time = random.randint(60, 180) # 60-180秒随机冷却
print(f" ⏳ 店铺冷却: {cooldown_time}秒")
System.wait(cooldown_time)
def generate_upload_report(self):
"""生成上架报告"""
print("📊 生成上架报告...")
success_count = sum(1 for result in self.upload_results.values() if result['success'])
total_products = len(self.upload_results)
report_data = {
'report_time': datetime.now(),
'total_products': total_products,
'success_count': success_count,
'success_rate': success_count / total_products if total_products > 0 else 0,
'total_revenue_potential': sum(result.get('price', 0) * result.get('stock', 0)
for result in self.upload_results.values() if result['success']),
'upload_details': self.upload_results
}
# 保存详细报告
self.save_detailed_report(report_data)
# 发送汇总通知
self.send_upload_summary(report_data)
def save_detailed_report(self, report_data):
"""保存详细报告"""
excel_path = f"C:\\上架报告\\TikTok商品上架报告_{datetime.now().strftime('%Y%m%d_%H%M')}.xlsx"
# 准备详细数据
rows = []
for sku, result in report_data['upload_details'].items():
rows.append({
'SKU': sku,
'上架店铺': result['account'],
'上架时间': result['upload_time'].strftime('%Y-%m-%d %H:%M:%S'),
'上架状态': '成功' if result['success'] else '失败',
'商品价格': result.get('price', 0),
'商品库存': result.get('stock', 0),
'商品链接': result.get('product_url', ''),
'错误信息': result.get('error', '')
})
if rows:
Excel.save_dataframe(pd.DataFrame(rows), excel_path)
print(f" ✅ 详细报告已保存: {excel_path}")
def send_upload_summary(self, report_data):
"""发送上架汇总"""
success_rate = report_data['success_rate'] * 100
message = f"""
📢 TikTok商品上架完成!
📊 上架统计:
• 总商品数: {report_data['total_products']}
• 成功上架: {report_data['success_count']}
• 成功率: {success_rate:.1f}%
• 预计营收: ${report_data['total_revenue_potential']:,.2f}
⏰ 报告时间: {report_data['report_time'].strftime('%Y-%m-%d %H:%M')}
"""
print(message)
def sync_to_erp_system(self):
"""同步到ERP系统"""
print("🔄 同步数据到ERP系统...")
try:
# 获取成功上架的商品数据
successful_products = [
result for result in self.upload_results.values()
if result['success']
]
if successful_products:
# 构建同步数据
sync_data = []
for product in successful_products:
sync_data.append({
'sku': product['sku'],
'platform': 'TikTok',
'listing_url': product.get('product_url', ''),
'listing_price': product.get('price', 0),
'listing_stock': product.get('stock', 0),
'listing_date': product['upload_time'].strftime('%Y-%m-%d %H:%M:%S'),
'account': product['acc