抖店铺货自动化:7个核心功能的技术实现方案

抖店铺货自动化:7个核心功能的技术实现方案

做抖店批量运营的开发者,最终都会面临同一个问题:怎么用代码实现一套稳定、安全的铺货自动化系统?

这篇文章不讲废话,直接上技术方案。从多店铺隔离到AI优化,7个核心功能的技术实现思路和关键代码。


技术栈选择

语言:Python 3.10+

浏览器控制:Playwright(推荐,比Selenium稳定)

数据存储:SQLite(轻量,不需要额外部署)

AI图片处理:Pillow + OpenCV

为什么选Playwright而不是Selenium?

  • Playwright的Context隔离更彻底,适合多店铺场景
  • Playwright的API更现代,支持async/await
  • Playwright的稳定性更好,不容易因为浏览器更新而挂

功能一:多店铺独立浏览器环境

核心思路:为每个店铺创建独立的BrowserContext。

python 复制代码
from playwright.sync_api import sync_playwright
from pathlib import Path
import json

class StoreManager:
    def __init__(self):
        self.playwright = None
        self.browser = None
        self.stores = {}  # {store_name: BrowserContext}
    
    def init(self):
        self.playwright = sync_playwright().start()
        self.browser = self.playwright.chromium.launch(
            headless=True,
            args=['--disable-blink-features=AutomationControlled']
        )
    
    def add_store(self, store_name: str, cookie_file: str):
        """为每个店铺创建独立的浏览器上下文"""
        context = self.browser.new_context(
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            viewport={'width': 1920, 'height': 1080},
            locale='zh-CN'
        )
        # 注入反检测脚本
        context.add_init_script("""
            Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
            window.navigator.chrome = { runtime: {} };
        """)
        # 加载独立的登录Cookie
        cookie_path = Path(cookie_file)
        if cookie_path.exists():
            with open(cookie_path, 'r', encoding='utf-8') as f:
                cookies = json.load(f)
            context.add_cookies(cookies)
        
        self.stores[store_name] = context
    
    def get_page(self, store_name: str):
        return self.stores[store_name].new_page()
    
    def close(self):
        for ctx in self.stores.values():
            ctx.close()
        self.browser.close()
        self.playwright.stop()

关键点:每个店铺的Context是完全隔离的。Cookie、LocalStorage、Session互不干扰,从根本上杜绝串号。

数据全部存在本地,不存密码,不上传到第三方服务器。


功能二:智能选品(多维度筛选)

python 复制代码
import sqlite3

class ProductFilter:
    def __init__(self, db_path: str):
        self.conn = sqlite3.connect(db_path)
        self.conn.row_factory = sqlite3.Row
    
    def filter_products(self, **criteria) -> list:
        """
        多维度筛选商品
        criteria: min_rating, max_return_rate, min_shipping_rate, 
                  min_price, max_price, category
        """
        query = "SELECT * FROM products WHERE 1=1"
        params = []
        
        if 'min_rating' in criteria:
            query += " AND rating >= ?"
            params.append(criteria['min_rating'])
        
        if 'max_return_rate' in criteria:
            query += " AND return_rate <= ?"
            params.append(criteria['max_return_rate'])
        
        if 'min_shipping_rate' in criteria:
            query += " AND shipping_rate >= ?"
            params.append(criteria['min_shipping_rate'])
        
        if 'min_price' in criteria:
            query += " AND price >= ?"
            params.append(criteria['min_price'])
        
        if 'max_price' in criteria:
            query += " AND price <= ?"
            params.append(criteria['max_price'])
        
        if 'category' in criteria:
            query += " AND category = ?"
            params.append(criteria['category'])
        
        cursor = self.conn.execute(query, params)
        return [dict(row) for row in cursor.fetchall()]

# 使用示例
pf = ProductFilter('./products.db')
results = pf.filter_products(
    min_rating=95,        # 好评率95%以上
    max_return_rate=5,    # 退货率5%以下
    min_shipping_rate=98, # 发货率98%以上
    min_price=30,         # 最低价30元
    max_price=80          # 最高价80元
)

功能三:全自动铺货

python 复制代码
import asyncio
import random

class AutoPublisher:
    def __init__(self, store_manager: StoreManager):
        self.store_manager = store_manager
    
    async def publish_batch(self, store_name: str, products: list):
        page = self.store_manager.get_page(store_name)
        
        for i, product in enumerate(products):
            try:
                # 打开商品发布页面
                page.goto('https://haohuo.douyin.com/goods/publish')
                page.wait_for_load_state('networkidle')
                
                # 自动填写标题
                title = self._generate_title(product)
                page.fill('[name="title"]', title)
                
                # 选择类目
                page.click('[class*="category-select"]')
                page.wait_for_selector(f'text={product["category"]}')
                page.click(f'text={product["category"]}')
                
                # 设置价格(自动加价)
                price = self._calc_price(product)
                page.fill('[name="price"]', str(price))
                
                # 上传主图(AI优化后的图片)
                page.set_input_files('input[type="file"]', product['optimized_image'])
                
                # 提交发布
                page.click('button:has-text("发布")')
                page.wait_for_selector('.success-toast', timeout=10000)
                
                print(f"[{store_name}] 商品 {i+1}/{len(products)} 发布成功")
                
            except Exception as e:
                print(f"[{store_name}] 商品 {i+1} 发布失败: {e}")
            
            # 随机延时,避免触发风控
            await asyncio.sleep(random.uniform(3, 8))
    
    def _generate_title(self, product: dict) -> str:
        """自动生成标题:类目关键词 + 卖点 + 规格"""
        keywords = product.get('keywords', [])
        selling_points = product.get('selling_points', [])
        return f"{' '.join(keywords[:3])} {' '.join(selling_points[:2])}"
    
    def _calc_price(self, product: dict) -> float:
        """自动加价:成本 + 运费 + 利润"""
        cost = product['cost']
        freight = product.get('freight', 5)
        markup = product.get('markup_rate', 0.3)  # 默认30%利润
        return round(cost * (1 + markup) + freight, 2)

功能四:AI商品优化(图片处理)

python 复制代码
from PIL import Image, ImageDraw, ImageFont
import os

class ImageOptimizer:
    """AI辅助商品图片优化"""
    
    # 抖店不同位置的尺寸要求
    SIZES = {
        'main': (800, 800),        # 主图
        'detail': (750, 1000),     # 详情页
        'banner': (750, 300),      # 轮播图
    }
    
    def optimize(self, source_path: str, product_type: str) -> dict:
        """根据商品类型智能优化图片"""
        img = Image.open(source_path)
        result = {}
        
        for position, size in self.SIZES.items():
            optimized = self._smart_crop(img, size, product_type, position)
            output_path = source_path.replace('.', f'_{position}.')
            optimized.save(output_path, quality=95)
            result[position] = output_path
        
        return result
    
    def _smart_crop(self, img, target_size, product_type, position):
        """智能裁剪:根据商品类型调整裁剪策略"""
        w, h = img.size
        tw, th = target_size
        ratio = tw / th
        img_ratio = w / h
        
        if position == 'main':
            # 主图:居中裁剪,保留商品主体
            if img_ratio > ratio:
                new_w = int(h * ratio)
                left = (w - new_w) // 2
                cropped = img.crop((left, 0, left + new_w, h))
            else:
                new_h = int(w / ratio)
                top = (h - new_h) // 2
                cropped = img.crop((0, top, w, top + new_h))
        
        elif position == 'detail':
            # 详情页:保持比例,白边填充
            bg = Image.new('RGB', target_size, (255, 255, 255))
            img.thumbnail((tw, th), Image.LANCZOS)
            x = (tw - img.width) // 2
            y = (th - img.height) // 2
            bg.paste(img, (x, y))
            cropped = bg
        
        elif position == 'banner':
            # 轮播图:取顶部区域
            cropped = img.crop((0, 0, w, int(w / ratio)))
        
        return cropped.resize(target_size, Image.LANCZOS)

功能五:批量商品清理

python 复制代码
class ProductCleaner:
    def __init__(self, store_manager: StoreManager):
        self.store_manager = store_manager
    
    def clean_no_exposure(self, store_name: str, days: int = 3):
        """清理无曝光商品"""
        page = self.store_manager.get_page(store_name)
        
        # 进入商品管理页面
        page.goto('https://haohuo.douyin.com/goods/list')
        page.wait_for_load_state('networkidle')
        
        # 设置筛选条件:无曝光天数
        page.click('[class*="filter-btn"]')
        page.fill('[class*="no-exposure-days"]', str(days))
        page.click('button:has-text("筛选")')
        page.wait_for_selector('.product-list')
        
        # 全选
        page.click('[class*="select-all"]')
        
        # 批量下架
        page.click('button:has-text("批量下架")')
        page.wait_for_selector('.confirm-dialog')
        page.click('button:has-text("确认")')
        
        print(f"[{store_name}] 已清理 {days} 天无曝光商品")
    
    def clean_by_supplier(self, store_name: str, supplier: str):
        """按供应商批量清理"""
        page = self.store_manager.get_page(store_name)
        page.goto('https://haohuo.douyin.com/goods/list')
        page.wait_for_load_state('networkidle')
        
        # 搜索指定供应商的商品
        page.fill('[class*="search-input"]', supplier)
        page.press('[class*="search-input"]', 'Enter')
        page.wait_for_selector('.product-list')
        
        # 全选并删除
        page.click('[class*="select-all"]')
        page.click('button:has-text("批量删除")')
        page.wait_for_selector('.confirm-dialog')
        page.click('button:has-text("确认")')
        
        print(f"[{store_name}] 已清理供应商 [{supplier}] 的所有商品")

功能六:对话式控制

python 复制代码
import re

class CommandInterpreter:
    """聊天式命令解析"""
    
    HANDLERS = {}
    
    @classmethod
    def register(cls, pattern: str):
        def decorator(func):
            cls.HANDLERS[pattern] = func
            return func
        return decorator
    
    def execute(self, command: str, **kwargs):
        for pattern, handler in self.HANDLERS.items():
            if re.search(pattern, command):
                return handler(command, **kwargs)
        return "未识别的指令,支持的指令:铺货、下架、参加活动、停止"

# 注册命令
@CommandInterpreter.register(r'铺货|发布')
def cmd_publish(command, **kwargs):
    store = kwargs.get('store_name', 'default')
    return f"开始为 [{store}] 自动铺货..."

@CommandInterpreter.register(r'下架.*无曝光')
def cmd_unpublish_no_exposure(command, **kwargs):
    days = 3
    match = re.search(r'(\d+)天', command)
    if match:
        days = int(match.group(1))
    return f"正在清理 {days} 天无曝光商品..."

@CommandInterpreter.register(r'参加活动|报名活动')
def cmd_activity(command, **kwargs):
    return "正在查找可报名的活动..."

@CommandInterpreter.register(r'停止|暂停')
def cmd_stop(command, **kwargs):
    return "已停止当前任务"

# 使用
interpreter = CommandInterpreter()
print(interpreter.execute("铺货"))                          # 开始自动铺货...
print(interpreter.execute("下架7天无曝光商品"))              # 正在清理 7 天无曝光商品...
print(interpreter.execute("参加活动"))                      # 正在查找可报名的活动...

功能七:定时任务

python 复制代码
import schedule
import time
from datetime import datetime

class Scheduler:
    def __init__(self, publisher, cleaner, store_name):
        self.publisher = publisher
        self.cleaner = cleaner
        self.store_name = store_name
    
    def setup(self):
        """配置定时任务"""
        schedule.every().day.at("08:00").do(
            self._task_wrapper, "自动铺货", self.publisher.daily_publish, self.store_name
        )
        schedule.every().day.at("14:00").do(
            self._task_wrapper, "清理无曝光商品", self.cleaner.clean_no_exposure, self.store_name, 3
        )
        schedule.every().day.at("22:00").do(
            self._task_wrapper, "报名活动", self.publisher.join_activities, self.store_name
        )
    
    def _task_wrapper(self, task_name, func, *args):
        print(f"[{datetime.now().strftime('%H:%M')}] 开始执行: {task_name}")
        try:
            func(*args)
            print(f"[{datetime.now().strftime('%H:%M')}] 完成: {task_name}")
        except Exception as e:
            print(f"[{datetime.now().strftime('%H:%M')}] 失败: {task_name} - {e}")
    
    def run(self):
        """启动定时调度"""
        self.setup()
        print("定时任务已启动,等待执行...")
        while True:
            schedule.run_pending()
            time.sleep(60)

# 启动
if __name__ == '__main__':
    sm = StoreManager()
    sm.init()
    sm.add_store('店铺A', './cookies/store_a.json')
    
    scheduler = Scheduler(AutoPublisher(sm), ProductCleaner(sm), '店铺A')
    scheduler.run()

总结

7个核心功能的技术实现要点:

功能 关键技术 难点
多店铺隔离 Playwright独立Context 反检测脚本
智能选品 SQLite多维筛选 策略设计
全自动铺货 Playwright页面操作 随机延时防风控
AI商品优化 Pillow智能裁剪 不同位置适配
批量清理 DOM操作+批量选择 页面改版适配
对话式控制 正则命令解析 中文分词
定时任务 schedule库 异常处理

完整代码可以基于上面的示例进行整合。核心思路是:本地运行、数据本地存储、每个店铺独立隔离。

如果你的团队没有开发能力,市面上也有成熟的桌面自动化方案,原理基本一致。

相关推荐
liana87443 小时前
统一企业门户,告别多系统碎片化办公
大数据·安全
运维帮手大橙子3 小时前
自动驾驶通过红路灯路口卡停
人工智能·机器学习·自动驾驶
前端若水3 小时前
版本控制:智能体提示与配置的CI/CD
大数据·elasticsearch·ci/cd
不懒不懒3 小时前
【基于 YOLOv10 与 PyQt5 的汽车零件缺陷检测系统实战开发】
人工智能·计算机视觉·目标跟踪
GEO从入门到精通3 小时前
GEO学习与传统SEO学习有什么区别?
人工智能·学习·microsoft
yyuuuzz3 小时前
独立开发者线上服务运维的几点实践经验
运维·服务器·网络·云计算·aws
墨北小七3 小时前
如何用 Dify 替代传统客服机器人
人工智能·机器人
jarvisuni3 小时前
《掌门日记》之GPT5.5测评报告!
人工智能·ai编程
一头爱吃肉的牛3 小时前
2026年AI PPT工具体验:6款主流工具深度横评
人工智能·powerpoint