Microsoft Designer 批量生成产品宣传图的脚本方案

文章导读
直接回应你的问题:Microsoft Designer 目前没有为公开批量生成场景提供官方 Python SDK,所以可落地的方案是用 Selenium 模拟浏览器操作,把“新建设计、填产品资料、调整布局、导出图片”这套重复动作固化成脚本。这个方案的好处是不依赖未公开接口,边界也清楚:只要页面结构没大改,脚本就能跑;页面改版后要重新定位元素。
📋 目录
  1. 分析Designer页面操作路径
  2. 搭建Python+Selenium自动化骨架
  3. 批量读取产品数据并填充
  4. 导出文件与整理命名
  5. 异常处理与最终验证
A A

直接回应你的问题:Microsoft Designer 目前没有为公开批量生成场景提供官方 Python SDK,所以可落地的方案是用 Selenium 模拟浏览器操作,把“新建设计、填产品资料、调整布局、导出图片”这套重复动作固化成脚本。这个方案的好处是不依赖未公开接口,边界也清楚:只要页面结构没大改,脚本就能跑;页面改版后要重新定位元素。

此方案适用于产品信息字段固定、使用同一设计模板的批量出图场景。处理方向是:先用浏览器开发者工具梳理 Designer 页面操作路径,再用 Selenium 搭建自动化骨架,通过 CSV 批量填充数据,最后集中导出并规范命名。验证方式是选取 2-3 条记录试跑,核对输出图片数量与内容。风险边界在于页面 DOM 变动、登录态失效和网络延迟会导致脚本中断,需要先做小批量验证再扩大范围。

分析Designer页面操作路径

自动化脚本要稳定,必须先画出人工操作的每一步。进入 Designer 网页版后,典型路径是:打开首页 → 登录(首次需要,之后靠 cookie 维持)→ 点击“新建设计”或模板 → 选择画布尺寸 → 在页面左侧或顶部输入产品名称、描述、价格 → 调整图片位置、字体、颜色 → 点击“导出”或“下载”。每一步对应浏览器里的一个可操作元素,这些元素要用 CSS 选择器或 XPath 定位。

通常需要准备以下选择器:登录按钮、新建设计入口、画布尺寸选项、产品名称输入框、描述输入框、价格输入框、图片替换按钮、下载按钮。其中输入框和按钮相对稳定,而动态弹出的模板选择列表可能因为网络延迟没有及时渲染,所以脚本必须用显式等待,不能直接 sleep 固定时间。

搭建Python+Selenium自动化骨架

推荐用 Python 3 搭配 Selenium,配合 ChromeDriver 或 EdgeDriver。下面是一个可运行的骨架,包含启动浏览器、登录(如果必要)、创建设计、等待元素出现的方法。登录逻辑需要根据实际页面判断;如果浏览器已保存会话,可以跳过登录步骤。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import time

# 设置下载目录,便于后续统一整理
options = Options()
options.add_experimental_option("prefs", {
    "download.default_directory": "/path/to/downloads",
    "download.prompt_for_download": False
})

driver = webdriver.Chrome(options=options)
wait = WebDriverWait(driver, 20)

try:
    driver.get("https://designer.example.com")

    # 如果出现登录入口,输入账号密码。这里用占位符,需要结合环境确认具体字段。
    try:
        login_btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-testid='login']")))
        login_btn.click()
        email = wait.until(EC.presence_of_element_located((By.NAME, "email")))
        email.send_keys("your_account@example.com")
        password = driver.find_element(By.NAME, "password")
        password.send_keys("your_password")
        driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
        time.sleep(3)
    except Exception:
        # 没有登录流程就继续
        pass

    # 新建设计
    new_design_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'新建设计')]")))
    new_design_btn.click()

    # 等待画布加载完成,以某个输入框出现为准
    wait.until(EC.presence_of_element_located((By.ID, "product-name-input")))

    print("设计页已打开")
finally:
    # 先不关闭,供下面填充步骤使用
    pass

骨架里的选择器只是示例,请以浏览器开发者工具实际看到的为准。建议给所有交互操作加显式等待,优先使用 ID 或 data-testid 这类稳定属性。

批量读取产品数据并填充

把产品信息放到 CSV 里,字段可以包含 name、description、price、image_path 等。脚本用 csv.DictReader 逐行读取,并循环创建、填充设计。下面的代码展示如何读取 CSV 并定位到对应输入框。

Microsoft Designer 批量生成产品宣传图的脚本方案
import csv

with open('products.csv', 'r', encoding='utf-8-sig') as f:
    reader = csv.DictReader(f)
    for row in reader:
        # 每行代表一个产品,这里拿到字段
        product_name = row['name']
        product_desc = row['description']
        product_price = row['price']

        # 定位到之前打开的输入框(实际选择器需重新确认)
        name_input = driver.find_element(By.ID, "product-name-input")
        name_input.clear()
        name_input.send_keys(product_name)

        desc_input = driver.find_element(By.ID, "product-desc-input")
        desc_input.clear()
        desc_input.send_keys(product_desc)

        price_input = driver.find_element(By.ID, "product-price-input")
        price_input.clear()
        price_input.send_keys(product_price)

        # 如果产品有配图,可通过文件上传控件替换,同样需要先定位
        # image_input = driver.find_element(By.NAME, "image-file")
        # image_input.send_keys(row['image_path'])

        # 预留:触发导出,见下节。需要把导出和命名逻辑整合进循环。

建议把“填充数据”和“导出”放进同一个循环里。每处理完一行就立即导出并重置画布,避免不同产品的数据互相串扰。如果 Designer 有自动保存,也可以先建一个模板,复制后修改字段,但复制操作的选择器同样需要单独验证。

导出文件与整理命名

导出后下载的文件通常会进入浏览器预设的下载目录,文件名可能是乱码或默认字符串。脚本需要监控下载目录,出现新文件后立即移动并重命名。为了避免重名,可以在名称后追加序号或时间戳。下面示例处理单个文件的下载与命名。

import os
import glob
import time

def wait_for_download(download_dir, timeout=30):
    """等待下载目录出现新文件,返回最新的文件路径"""
    end_time = time.time() + timeout
    latest = None
    while time.time() < end_time:
        files = glob.glob(os.path.join(download_dir, "*"))
        files = [f for f in files if not f.endswith(".crdownload")]  # 过滤未完成文件
        if files:
            # 找到修改时间最新的文件
            latest = max(files, key=os.path.getmtime)
            # 下载完成后文件大小通常停止变化,这里简单等待 1 秒再取值
            time.sleep(1)
            return latest
    raise TimeoutError("下载超时")

# 在循环内调用导出按钮
# driver.find_element(By.XPATH, "//button[contains(text(),'导出')]").click()

raw_file = wait_for_download(download_dir)

# 按产品名称命名,附加序号避免冲突
output_name = f"{product_name}_{sequence}.png"
output_path = os.path.join(output_dir, output_name)

# 如果目标文件已存在,追加下划线
while os.path.exists(output_path):
    output_name = f"{product_name}_{sequence}_new.png"
    output_path = os.path.join(output_dir, output_name)
    sequence += 1

os.rename(raw_file, output_path)
print("已保存:", output_path)

下载完成后要清理临时文件,或者把下载目录和最终存放目录分开。如果导出格式默认不是 PNG,可以在 Designer 的导出选项里先设置,脚本再点击对应选项。

异常处理与最终验证

页面加载慢、元素被遮挡、网络超时都会让脚本卡死。处理方式是:给每个关键操作加显式等待,并用 try-except 捕获超时异常,然后重试或跳过。下面给出检查元素是否存在、超时重试的示例。

from selenium.common.exceptions import TimeoutException, NoSuchElementException

def safe_click(driver, by, selector, retry=2):
    """查找元素并点击,失败重试"""
    for attempt in range(retry):
        try:
            element = WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable((by, selector))
            )
            element.click()
            return True
        except TimeoutException:
            driver.refresh()
            time.sleep(2)
    return False

# 使用示例
if not safe_click(driver, By.XPATH, "//button[contains(text(),'导出')]"):
    print("导出按钮点击失败,跳过当前产品")
    # 可以考虑保存错误状态,以便事后补跑

# 循环全部结束后,检查输出文件数量
import os
output_files = os.listdir(output_dir)
print("期望数量:", expected_count)
print("实际数量:", len(output_files))

# 检查文件大小是否接近,排除空文件
for f in output_files:
    path = os.path.join(output_dir, f)
    if os.path.getsize(path) == 0:
        print("空文件:", f)

最终验证时,先确认 CSV 行数与输出文件数一致,再随机打开几张图检查产品名称和文案是否正确。如果发现部分记录缺失或命名错误,可以通过保存的日志定位是哪一行失败。建议首次批量前先跑 3 条产品,观察整个流程稳定后再全量执行。