🌙 shopify采集字段说明
網址:https://www.on.com/en-us/
采集完成數據詳情:samsoe_sales.xls
Shopify 产品导入 CSV 文件字段说明
| 字段名称 | 说明 |
|---|---|
| Handle | 产品唯一标识符(不可重复),通常是产品名称的小写版本,用“-”连接 |
| Title | 产品标题,显示在商品页面的名称 |
| Body (HTML) | 产品描述,可包含 HTML 格式 |
| Vendor | 供应商名称(品牌或制造商) |
| Type | 产品类型,用于分类 |
| Tags | 产品标签,多个标签用逗号分隔 |
| Published | 是否发布(TRUE = 已发布,FALSE = 未发布) |
| Option1 Name | 选项 1 的名称(如颜色、尺寸) |
| Option1 Value | 选项 1 的值(如红色、M 号) |
| Option2 Name | 选项 2 的名称(如果适用) |
| Option2 Value | 选项 2 的值(如果适用) |
| Option3 Name | 选项 3 的名称(如果适用) |
| Option3 Value | 选项 3 的值(如果适用) |
| Variant SKU | 库存单位(SKU),用于追踪库存 |
| Variant Grams | 变体的重量(以克为单位) |
| Variant Inventory Tracker | 库存追踪方式(如 Shopify) |
| Variant Inventory Qty | 变体的库存数量 |
| Variant Inventory Policy | 库存策略(deny = 无库存时不可购买,continue = 无库存仍可下单) |
| Variant Fulfillment Service | 履行服务提供商(如 manual 或第三方物流) |
| Variant Price | 变体价格(最终售价) |
| Variant Compare At Price | 变体的对比价格(原价或折扣前价格) |
| Variant Requires Shipping | 是否需要运输(TRUE = 需要,FALSE = 不需要) |
| Variant Taxable | 是否需要缴税(TRUE = 需要,FALSE = 不需要) |
| Variant Barcode | 变体的条形码(如 UPC、EAN 或 ISBN) |
| Image Src | 产品图片 URL(直接可访问) |
| Image Position | 图片的显示顺序(数字越小,越靠前) |
| Image Alt Text | 图片的替代文本,有助于 SEO 和无障碍访问 |
| Gift Card | 是否为礼品卡(TRUE = 是,FALSE = 否) |
| SEO Title | SEO 标题,出现在搜索结果的产品标题 |
| SEO Description | SEO 描述,优化搜索引擎的产品简介 |
| Variant Image | 变体专属图片的 URL(可选) |
| Status | 产品状态(active = 已上架,draft = 草稿,archived = 已归档) |
| Collection | 产品所属的集合(可选) |
示例脚本:
import requests
import json
import time
import csv
from datetime import datetime
def get_product_images(primary_image):
"""根据primaryImage生成1-5的图片链接"""
images = []
if primary_image:
# 从primaryImage中提取基本URL
# 例如从 https://images.lululemon.com/is/image/lululemon/LW3HQFS_038426_1
# 提取到 https://images.lululemon.com/is/image/lululemon/LW3HQFS_038426
base_url = primary_image.rsplit('_', 1)[0]
# 生成1到5的图片链接
for i in range(1, 6):
image_url = f"{base_url}_{i}"
images.append(image_url)
return images
def convert_to_shopify_format(product_data):
"""将产品数据转换为Shopify格式"""
# 打印调试信息
print(f"\n处理产品: {product_data['displayName']}")
shopify_product = {
"title": product_data["displayName"],
"body_html": "", # 可以添加产品描述
"vendor": "lululemon",
"product_type": product_data["parentCategoryUnifiedId"].replace("-", " ").title(),
"created_at": datetime.now().isoformat(),
"handle": product_data["unifiedId"],
"published_at": datetime.now().isoformat(),
"template_suffix": "",
"status": "active",
"published_scope": "web",
"tags": [],
"variants": [],
"options": [
{
"name": "Color",
"position": 1,
"values": []
},
{
"name": "Size",
"position": 2,
"values": [str(i) for i in range(0, 21, 2)] # 生成0,2,4,...,20的尺码
}
],
"images": []
}
# 收集所有颜色
colors = {} # 用于存储颜色和对应的SKU样式
# 从 skuStyleOrder 收集颜色信息
for sku_style in product_data["skuStyleOrder"]:
# 收集颜色信息
if sku_style["colorName"] not in colors:
colors[sku_style["colorName"]] = {
"colorId": sku_style["colorId"],
"styleId": sku_style["styleId"]
}
if sku_style["colorName"] not in shopify_product["options"][0]["values"]:
shopify_product["options"][0]["values"].append(sku_style["colorName"])
# 为每个颜色创建所有尺码的变体
for color_name, color_info in colors.items():
# 为每个尺码创建变体
for size in shopify_product["options"][1]["values"]:
# 构建SKU
sku = f"{color_info['styleId']}_{size}"
variant = {
"sku": sku,
"price": product_data["listPrice"][0],
"compare_at_price": None,
"option1": color_name,
"option2": size,
"available": True,
"inventory_quantity": 1,
"requires_shipping": True
}
shopify_product["variants"].append(variant)
print(f"\n创建的变体数量: {len(shopify_product['variants'])}")
print(f"使用的尺码范围: {shopify_product['options'][1]['values']}")
# 处理图片 - 使用primaryImage生成1-5的图片链接
for swatch in product_data["swatches"]:
if swatch["primaryImage"]:
images = get_product_images(swatch["primaryImage"])
# 获取该颜色的所有变体SKU
color_name = next(name for name, info in colors.items() if info["colorId"] == swatch["colorId"])
variant_ids = [v["sku"] for v in shopify_product["variants"] if v["option1"] == color_name]
for idx, img_url in enumerate(images, 1):
shopify_product["images"].append({
"src":img_url,
"position": len(shopify_product["images"]) + 1,
"variant_ids": variant_ids
})
return shopify_product
def write_products_to_csv(products, writer):
"""将产品数据写入CSV文件"""
for product in products:
base_row = {
'Handle': product['handle'],
'Title': product['title'],
'Body (HTML)': product['body_html'],
'Vendor': product['vendor'],
'Type': product['product_type'],
'Tags': '',
'Published': 'TRUE',
'Option1 Name': 'Color',
'Option2 Name': 'Size',
'Option3 Name': '',
'Option3 Value': '',
'Variant Grams': '0',
'Variant Inventory Tracker': 'shopify',
'Variant Inventory Qty': '100',
'Variant Inventory Policy': 'deny',
'Variant Fulfillment Service': 'manual',
'Variant Requires Shipping': 'TRUE',
'Variant Taxable': 'TRUE',
'Variant Barcode': '',
'Image Alt Text': '',
'Gift Card': 'FALSE',
'SEO Title': product['title'],
'SEO Description': '',
'Google Shopping / Google Product Category': '',
'Google Shopping / Gender': '',
'Google Shopping / Age Group': '',
'Google Shopping / MPN': '',
'Google Shopping / AdWords Grouping': '',
'Google Shopping / AdWords Labels': '',
'Google Shopping / Condition': '',
'Google Shopping / Custom Product': '',
'Google Shopping / Custom Label 0': '',
'Google Shopping / Custom Label 1': '',
'Google Shopping / Custom Label 2': '',
'Google Shopping / Custom Label 3': '',
'Google Shopping / Custom Label 4': '',
'Variant Weight Unit': 'g',
'Variant Tax Code': '',
'Cost per item': '',
'Status': 'active'
}
# 为每个变体写入一行
for variant in product['variants']:
row = base_row.copy()
row.update({
'Option1 Value': variant['option1'],
'Option2 Value': variant['option2'],
'Variant SKU': variant['sku'],
'Variant Price': variant['price'],
'Variant Compare At Price': variant.get('compare_at_price', ''),
})
# 查找该变体对应的图片
variant_images = [img['src'] for img in product['images']
if variant['sku'] in img['variant_ids']]
if variant_images:
# 写入第一张图片信息
row['Image Src'] = variant_images[0]
row['Image Position'] = '1'
row['Variant Image'] = variant_images[0]
writer.writerow(row)
# 写入剩余图片
for idx, img_url in enumerate(variant_images[1:], 2):
image_row = {
'Handle': product['handle'],
'Image Src': img_url,
'Image Position': str(idx)
}
writer.writerow(image_row)
else:
# 如果没有图片,仍然写入产品信息
writer.writerow(row)
def get_lululemon_products():
url = "https://shop.lululemon.com/snb/graphql"
page = 1
# 创建CSV文件和writer对象
csv_filename = f'lululemon_products_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv'
fieldnames = [
"Handle", "Title", "Body (HTML)", "Vendor", "Type", "Tags", "Published",
"Option1 Name", "Option1 Value", "Option2 Name", "Option2 Value",
"Option3 Name", "Option3 Value", "Variant SKU", "Variant Grams",
"Variant Inventory Tracker", "Variant Inventory Qty", "Variant Inventory Policy",
"Variant Fulfillment Service", "Variant Price", "Variant Compare At Price",
"Variant Requires Shipping", "Variant Taxable", "Variant Barcode",
"Image Src", "Image Position", "Image Alt Text", "Gift Card",
"SEO Title", "SEO Description", "Google Shopping / Google Product Category",
"Google Shopping / Gender", "Google Shopping / Age Group",
"Google Shopping / MPN", "Google Shopping / AdWords Grouping",
"Google Shopping / AdWords Labels", "Google Shopping / Condition",
"Google Shopping / Custom Product", "Google Shopping / Custom Label 0",
"Google Shopping / Custom Label 1", "Google Shopping / Custom Label 2",
"Google Shopping / Custom Label 3", "Google Shopping / Custom Label 4",
"Variant Image", "Variant Weight Unit", "Variant Tax Code",
"Cost per item", "Status"
]
with open(csv_filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
headers = {
"accept": "application/graphql+json, application/json",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/json",
"origin": "https://shop.lululemon.com",
"priority": "u=1, i",
"referer": "https://shop.lululemon.com/c/women-clothes/n14uwk",
"sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0",
"x-lll-referrer": "Channel=Web,Page=CDP",
"x-lll-request-correlation-id": "029b94b5-e82d-463b-84e0-a787e2e72aea"
}
while True:
payload = {
"query": """query CategoryPageDataQuery($category:String!,$cid:String,$forceMemberCheck:Boolean,$nValue:String,$cdpHash:String,$sl:String!,$locale:String!,$Ns:String,$storeId:String,$pageSize:Int,$page:Int,$onlyStore:Boolean,$useHighlights:Boolean,$abFlags:[String],$styleboost:[String],$fusionExperimentVariant:String){categoryPageData(category:$category nValue:$nValue cdpHash:$cdpHash locale:$locale sl:$sl Ns:$Ns page:$page pageSize:$pageSize storeId:$storeId onlyStore:$onlyStore forceMemberCheck:$forceMemberCheck cid:$cid useHighlights:$useHighlights abFlags:$abFlags styleboost:$styleboost fusionExperimentVariant:$fusionExperimentVariant){activeCategory allLocaleNvalues{CA US __typename}categoryLabel fusionExperimentId fusionExperimentVariant fusionQueryId h1Title isBopisEnabled isFusionQuery isWMTM name results:totalProducts totalProductPages currentPage type bopisProducts{allAvailableSizes currencyCode defaultSku displayName listPrice parentCategoryUnifiedId productOnSale:onSale productSalePrice:salePrice pdpUrl productCoverage repositoryId:productId productId inStore unifiedId highlights{highlightLabel highlightIconWeb priority visibility subText abFlag{abFlagName showIcon showHighlight showSubText visibility __typename}__typename}skuStyleOrder{colorGroup colorId colorName inStore size sku skuStyleOrderId styleId01 styleId02 styleId __typename}swatches{primaryImage hoverImage url colorId inStore __typename}__typename}storeInfo{totalInStoreProducts totalInStoreProductPages storeId __typename}products{allAvailableSizes currencyCode defaultSku displayName intendedCupSize listPrice parentCategoryUnifiedId productOnSale:onSale productSalePrice:salePrice pdpUrl productCoverage repositoryId:productId productId inStore unifiedId highlights{highlightLabel highlightIconWeb priority visibility subText abFlag{abFlagName showIcon showHighlight showSubText visibility __typename}__typename}skuStyleOrder{colorGroup colorId colorName inStore size sku skuStyleOrderId styleId01 styleId02 styleId __typename}swatches{primaryImage hoverImage url colorId inStore __typename}__typename}seoLinks{next prev self __typename}__typename}}""",
"operationName": "CategoryPageDataQuery",
"variables": {
"nValue": None,
"cdpHash": "n14uwk",
"category": "women-clothes",
"locale": "en_US",
"sl": "US",
"page": page,
"pageSize": 12,
"forceMemberCheck": False,
"abFlags": ["cdpSeodsEnabled"],
"useHighlights": True
}
}
try:
print(f"正在获取第 {page} 页数据...")
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
data = response.json()
# 检查是否还有产品数据
if not data["data"]["categoryPageData"]["products"]:
break
# 转换产品数据并直接写入CSV
products = [convert_to_shopify_format(product) for product in data["data"]["categoryPageData"]["products"]]
write_products_to_csv(products, writer)
print(f"第 {page} 页数据已写入CSV文件")
page += 1
time.sleep(1) # 添加延迟,避免请求过快
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
break
except Exception as e:
print(f"处理数据时出错: {e}")
break
print(f"数据已保存到 {csv_filename}")
if __name__ == "__main__":
get_lululemon_products()