# 亚马逊格式到店匠格式转换 - 核心工作内容分析

## 一、概述

本项目实现了从**亚马逊格式Excel数据**到**店匠（Shoplazza）商品导入模板**的格式转换，主要处理商品的多款式（变体）结构和属性字段映射。

**核心脚本**：`scripts/amazon_xlsx_to_shoplazza_xlsx.py`

---

## 二、父子款式处理（M/P/S 结构转换）

### 2.1 输入格式（亚马逊）

- **ASIN**：变体ID（SKU级别）
- **父ASIN**：父商品ID（SPU级别）
- 一个父ASIN可以包含多个ASIN（多个变体）

### 2.2 输出格式（店匠）

店匠模板定义了三种商品属性类型：

1. **S（单一款式）**：只有一个变体的商品
   - 输出：**1行**
   - 包含所有商品信息（标题、价格、库存等）

2. **M（主商品）+ P（子款式）**：包含多个变体的商品
   - 输出：**1行M + N行P**
   - **关键约束**：同一商品的P行必须紧跟在M行后面（模板导入强约束）

### 2.3 转换策略

```python
# 核心逻辑（简化版）
for 父ASIN in 所有父ASIN:
    variants = 获取该父ASIN下的所有ASIN
    
    if len(variants) == 1:
        生成 S 行（单一款式）
    else:
        生成 M 行（主商品）+ 多个 P 行（子款式）
```

### 2.4 关键处理点

#### 1. 父ASIN排序
- 确保父ASIN对应的变体在列表最前面
- 如果找不到父ASIN对应的变体，根据配置决定是否丢弃整个SPU

#### 2. 标题一致性检查
- 同一SPU下的所有变体标题必须一致
- 如果发现不一致：
  - 选项1：丢弃标题不一致的SKU（默认）
  - 选项2：修正为统一的主商品标题

#### 3. M行与P行的字段分工

**M行（主商品）填写**：
- ✅ 商品标题、描述、SEO信息
- ✅ 专辑、标签、供应商信息
- ✅ 商品主图
- ✅ 款式维度名（款式1/2/3的key）
- ❌ 不填：价格、库存、重量等SKU级字段（保持为空更安全）

**P行（子款式）填写**：
- ✅ 商品标题（与M行一致）
- ✅ 款式维度值（款式1/2/3的value）
- ✅ 价格、商品SKU（ASIN）、库存
- ✅ 重量、尺寸
- ✅ 子款式图（可选）
- ❌ 不填：描述、SEO、专辑等SPU级字段（保持为空）

---

## 三、属性字段处理（款式维度解析）

### 3.1 问题背景

亚马逊格式中，变体的"颜色/尺码"等信息**并不拆成多个列**，而是集中在 `SKU` 字符串里：

```
示例1: "Size: One Size | Color: Black"
示例2: "Color: Red | Style: 2-Pack"
```

而店匠模板需要：
- **M行**：`款式1/款式2/款式3` 填写**维度名**（如 Size、Color、Material）
- **P行**：`款式1/款式2/款式3` 填写**维度值**（如 One Size、Black、Cotton）

### 3.2 SKU解析逻辑

```python
def parse_sku_options(sku_text):
    """
    解析 SKU 列，提取 key:value 对
    输入: "Size: One Size | Color: Black"
    输出: {"Size": "One Size", "Color": "Black"}
    """
    # 1. 按 | 分割
    parts = sku_text.split("|")
    
    # 2. 按 : 拆成 key/value
    for part in parts:
        if ":" in part:
            key, value = part.split(":", 1)
            result[key.strip()] = value.strip()
    
    return result
```

### 3.3 维度选择策略（最多3个维度）

店匠模板只提供 `款式1~3` 三个维度，因此需要从多个变体中**智能选择最多3个维度**：

#### 优先级规则

1. **按预设优先级排序**：
   ```python
   PREFERRED_OPTION_KEYS = [
       "Size", "Color", "Style", "Pattern", "Material", 
       "Flavor", "Scent", "Pack", "Pack of", ...
   ]
   ```

2. **按出现频次排序**：统计每个key在所有变体中的出现次数

3. **综合排序**：
   ```python
   def key_sort(k):
       return (
           预设优先级（越小越优先）,
           -出现频次（越大越优先）,
           字母顺序（作为最后排序依据）
       )
   ```

#### 退化处理

如果解析不到任何 key/value，则退化为单维度：
- M行：`款式1 = "Variant"`
- P行：`款式1 = ASIN`（使用ASIN作为维度值）

### 3.4 维度映射示例

**输入数据**（3个变体）：
```
变体1: SKU = "Size: S | Color: Red"
变体2: SKU = "Size: M | Color: Red"  
变体3: SKU = "Size: S | Color: Blue"
```

**解析结果**：
- 维度统计：Size出现3次，Color出现3次
- 选择维度：Size（优先级1）、Color（优先级2）
- 最多3个，所以选择前2个

**输出格式**：
```
M行：
  款式1 = "Size"
  款式2 = "Color"
  款式3 = ""

P行1：
  款式1 = "S"
  款式2 = "Red"
  款式3 = ""

P行2：
  款式1 = "M"
  款式2 = "Red"
  款式3 = ""

P行3：
  款式1 = "S"
  款式2 = "Blue"
  款式3 = ""
```

---

## 四、字段映射总览

### 4.1 核心字段映射

| 店匠字段 | 亚马逊字段 | 处理逻辑 |
|---------|-----------|---------|
| **商品spu** | `父ASIN` | 无父ASIN则用ASIN |
| **商品SKU** | `ASIN` | 直接映射 |
| **商品标题*** | `商品标题` | 截断至255字符 |
| **商品图片*** | `商品主图` | URL直接映射 |
| **商品售价*** | `prime价格($)` 或 `价格($)` | 优先prime价格 |
| **创建时间** | `上架时间` | 日期格式转换（补齐时分秒） |
| **商品描述** | `商品标题` + `详细参数` | HTML拼接 |
| **专辑名称** | `大类目` | 无则取`类目路径`第一段 |
| **标签** | `品牌,大类目,小类目` | 逗号拼接 |
| **商品重量/重量单位** | `商品重量（单位换算）` | 解析数值和单位（g/kg/lb/oz） |
| **尺寸信息** | `商品尺寸` | 解析前三段数字，拼成 `L,W,H`（英寸） |

### 4.2 特殊字段处理

#### 1. 价格处理
```python
price = prime价格($) or 价格($) or 9.99  # 默认值9.99
```

#### 2. 库存处理
- 亚马逊数据源通常**没有库存**
- 脚本默认给每个变体固定库存：**100**

#### 3. 日期格式转换
```python
输入: "2018-05-09" 或 datetime对象
输出: "2018-05-09 00:00:00"  # 补齐时分秒
```

#### 4. 重量解析
```python
输入: "68.04 g" 或 "0.15 pounds"
输出: (68.04, "g") 或 (0.15, "lb")
```

#### 5. 尺寸解析
```python
输入: "7.9 x 7.9 x 2 inches"
输出: "7.9,7.9,2"  # L,W,H格式
```

#### 6. SEO URL Handle生成
```python
输入: "Legendary Whitetails Men's Buck Camp Flannel Shirt"
输出: "products/legendary-whitetails-mens-buck-camp-flannel-shirt"
# 规则：转小写、去特殊字符、空格转横线
```

---

## 五、重要工作内容总结

### 5.1 数据结构转换

1. **父子关系识别**：从扁平化的ASIN列表识别出SPU-SKU层级关系
2. **分组策略**：按父ASIN分组，决定生成S还是M+P结构
3. **行序保证**：确保同一SPU的M+P行连续，不被打断

### 5.2 属性字段解析

1. **SKU字符串解析**：从非结构化字符串中提取key:value对
2. **维度智能选择**：从多个可能的维度中选择最重要的3个
3. **优先级算法**：综合考虑预设优先级、出现频次、字母顺序

### 5.3 字段映射与转换

1. **格式转换**：日期、价格、重量、尺寸等格式标准化
2. **默认值填充**：库存、价格等缺失字段的默认值策略
3. **数据清洗**：标题截断、HTML转义、URL生成等

### 5.4 数据质量控制

1. **标题一致性检查**：确保同一SPU下所有变体标题一致
2. **父ASIN验证**：检查父ASIN是否存在于变体列表中
3. **错误处理**：提供配置选项决定是修正还是丢弃异常数据

### 5.5 性能优化

1. **批量处理**：支持多文件批量转换
2. **文件拆分**：按最大行数自动拆分输出文件（保证同一SPU不拆分）
3. **快速读写**：使用`iter_rows(values_only=True)`和write_only模式提升性能

---

## 六、关键技术难点

### 6.1 维度选择算法

**挑战**：从多个变体的SKU字符串中，智能选择最重要的3个维度

**解决方案**：
- 统计所有变体中每个key的出现频次
- 结合预设优先级列表（Size > Color > Style > ...）
- 综合排序选择前3个

### 6.2 数据一致性保证

**挑战**：确保同一SPU下的所有变体数据一致

**解决方案**：
- 标题一致性检查和修正
- 父ASIN排序保证
- M行和P行的字段分工明确

### 6.3 文件拆分策略

**挑战**：按最大行数拆分文件，但不能拆分同一SPU

**解决方案**：
- 先按SPU分组生成所有行
- 拆分时以SPU为单位，不拆分单个SPU的行

---

## 七、扩展点

### 7.1 可配置项

- 库存默认值（当前100）
- 价格默认值（当前9.99）
- 上架/收税/物流策略（当前硬编码Y/N）

### 7.2 可增强功能

- **更强的多款式解析**：如果SKU字段不规范，可从`详细参数`中提取Color/Size
- **图片策略优化**：P行可改为使用M行合并的多图（逗号拼接）
- **元字段支持**：支持店匠的元字段导入

---

## 八、使用示例

### 8.1 小批量验证

```bash
python scripts/amazon_xlsx_to_shoplazza_xlsx.py \
  --input-dir data/mai_jia_jing_ling/products_data \
  --template docs/商品导入模板.xlsx \
  --output data/mai_jia_jing_ling/amazon_shoplazza_import_SAMPLE.xlsx \
  --max-files 1 --max-products 50
```

### 8.2 全量转换

```bash
python scripts/amazon_xlsx_to_shoplazza_xlsx.py \
  --input-dir data/mai_jia_jing_ling/products_data \
  --template docs/商品导入模板.xlsx \
  --output data/mai_jia_jing_ling/amazon_shoplazza_import_ALL.xlsx
```

### 8.3 自动拆分文件

```bash
python scripts/amazon_xlsx_to_shoplazza_xlsx.py \
  --input-dir data/mai_jia_jing_ling/products_data \
  --template docs/商品导入模板.xlsx \
  --output data/mai_jia_jing_ling/amazon_shoplazza_import_SPLIT.xlsx \
  --max-rows-per-output 40000
```

---

## 九、总结

亚马逊格式到店匠格式的转换，核心工作包括：

1. **父子款式结构转换**：从ASIN/父ASIN关系转换为M/P/S结构
2. **属性字段解析**：从SKU字符串中提取并智能选择款式维度
3. **字段映射与转换**：40+个字段的格式转换和默认值处理
4. **数据质量控制**：一致性检查、错误处理、数据清洗
5. **性能优化**：批量处理、文件拆分、快速读写

这是一个典型的**数据格式转换ETL任务**，涉及数据结构重组、字符串解析、智能算法选择等多个技术领域。












