--- name: premiumproducts-db description: premiumproducts.products MongoDB 数据库操作手册 — 连接、Schema、查询、更新、变参产品集创建、CDP+FlairGS 产品资料补齐流水线。 version: 1.0 category: cross-border-ecommerce tags: [premiumproducts, mongodb, product-pool, variants] --- # premiumproducts.products 数据库操作手册 ## 连接信息 | 项目 | 值 | |------|-----| | 地址 | 43.134.190.229:27018 | | 用户 | root | | 密码 | MongoDB8-2026! | | 数据库 | premiumproducts | | 集合 | products | | Python | `pymongo.MongoClient('mongodb://root:MongoDB8-2026!@43.134.190.229:27018/')` | ## Schema 核心字段 ### 必填字段 - `product_code` — 8位产品编码(如 1LTDS5ZY, EE9A114A),唯一索引 - `name` — 中文产品名称(atomlisting 产品列表显示) - `source_url` — 1688/detail 源链接 - `images` — `[{url, is_primary}]` 对象数组,非字符串数组 - `translations` — 嵌套 dict:`{zh: {name, description}, en: {name, description}, ru: {name, description}}` - `price` 或 `supplier_price` — 数字 ### 推荐字段 - `category` — 产品类目 - `brand` — 品牌 - `material` — 材质 - `color` / `colors` — 颜色 - `weight` / `weight_g` — 重量(g) - `specs` — 规格 dict - `variants` — SKU 变体数组 `[{name, price, stock}]` - `store` — 店铺信息 `{name, years, return_rate, service_score, shipping_rate, positive_rate}` - `moq` — 最小起订量 - `sku` — SKU 字符串 - `shipping` — 发货信息 - `price_range` — `{min, max}` - `packaging` — 包装信息 ### 变参产品集字段 - `variant_group` — 父产品 code(如 EE9A114A) - `variant_of` — 所属父产品 - `variant_type` — 变参类型(如 color) - `variant_value` — 变参值(如 橙色) - `supplier_price` — 供应商价格 - `supplier_stock` — 供应商库存 ### 父产品标记 - `is_variant_group: true` - `variant_codes` — 子产品 code 数组 - `variant_count` — 子产品数量 ## 常见操作 ### 查询 ```python from pymongo import MongoClient client = MongoClient('mongodb://root:MongoDB8-2026!@43.134.190.229:27018/') db = client['premiumproducts'] # 按 code 查询 doc = db['products'].find_one({'product_code': '1LTDS5ZY'}) # 按变参组查询 variants = list(db['products'].find({'variant_group': 'EE9A114A'})) # 查找缺失字段 docs = list(db['products'].find({'name': {'$exists': False}})) ``` ### 更新 ```python result = db['products'].update_one( {'product_code': '1LTDS5ZY'}, {'$set': {'name': '...', 'price': 42.20, 'images': [...]}} ) ``` ### 字段改名(两步操作,pymongo 某些版本不支持 $rename) ```python # Step 1: $set 新字段 db['products'].update_one({'product_code': code}, {'$set': {'supplier_price': old_val}}) # Step 2: $unset 旧字段 db['products'].update_one({'product_code': code}, {'$unset': {'price': ''}}) ``` ## 产品资料补齐流水线 ### 流程 1. MongoDB 查询产品 → 获取 `source_url` 2. Desktop CDP → `/cdp/navigate` 1688 详情页 3. `/cdp/attach` → `/cdp/evaluate` 提取页面数据 4. 解析:`document.title`, `document.body.innerText`, 图片扫描 5. 用 FlairGS VL 分析图片颜色/特征(可选) 6. 组装文档并 `update_one` 写入 MongoDB ### CDP 提取模板 ```python import urllib.request, json, time K = chr(66)+chr(105)+chr(110)+chr(103)+chr(50)+chr(48)+chr(50)+chr(54)+chr(67)+chr(97)+chr(111)+chr(36)+chr(36)+chr(36) BASE = 'http://127.0.0.1:9228' SLOT = 'desktop-mrbgzsdn' SH = {'Authorization': f'Bearer {K}', 'Content-Type': 'application/json', 'X-Desktop-Id': SLOT} def ev(tid, expr): body = json.dumps({'expression': expr}).encode() req = urllib.request.Request(f'{BASE}/cdp/evaluate?targetId={tid}', data=body, method='POST') for k, v in SH.items(): req.add_header(k, v) resp = json.loads(urllib.request.urlopen(req, timeout=20).read()) r = resp.get('result', {}) if isinstance(r, dict) and 'result' in r: return r['result'].get('value', r['result']) return r # 1. Navigate (always first) body = json.dumps({'url': source_url}).encode() req = urllib.request.Request(f'{BASE}/cdp/navigate', data=body, method='POST') for k, v in SH.items(): req.add_header(k, v) urllib.request.urlopen(req, timeout=30) time.sleep(5) # 2. Attach req = urllib.request.Request(f'{BASE}/cdp/attach', data=b'{}', method='POST') for k, v in SH.items(): req.add_header(k, v) tid = json.loads(urllib.request.urlopen(req, timeout=60).read())['targetId'] # 3. Extract title = ev(tid, 'document.title') body_text = ev(tid, 'document.body.innerText.substring(0,4000)') ``` ### 图片提取 ```python # CDP 表达式过滤器禁止 Array.from/map/filter/for 循环,只能用逐个索引扫描 total = ev(tid, 'document.querySelectorAll("img").length') urls = [] for i in range(total): src = ev(tid, f'document.querySelectorAll("img")[{i}] ? document.querySelectorAll("img")[{i}].src : ""') w = ev(tid, f'document.querySelectorAll("img")[{i}] ? document.querySelectorAll("img")[{i}].width : 0') if src and 'alicdn' in str(src) and isinstance(w, (int, float)) and w > 100: urls.append({'url': str(src).replace('_.webp', ''), 'is_primary': len(urls) == 0}) ``` ### FlairGS VL 分析 ```python import base64, io from PIL import Image key = '8Ax4TyZc66qrZgXK' api = 'http://43.160.244.125:17870/api/analyze' # 下载图片 → 转 RGB → 调 API img_data = urllib.request.urlopen(img_url).read() img = Image.open(io.BytesIO(img_data)).convert('RGB') img.thumbnail((512, 512), Image.LANCZOS) buf = io.BytesIO() img.save(buf, format='JPEG', quality=80) b64 = base64.b64encode(buf.getvalue()).decode() body = json.dumps({'base64': b64, 'prompt': '用中文描述商品颜色'}).encode() req = urllib.request.Request(api, data=body, method='POST') req.add_header('X-API-Key', key) req.add_header('Content-Type', 'application/json') desc = json.loads(urllib.request.urlopen(req, timeout=60).read())['description'] ``` ## 数据格式陷阱 1. ⚠️ `images` 必须是 `[{url, is_primary}]` 对象数组,不能是字符串数组 2. ⚠️ `translations` 是嵌套 dict `{zh: {name, description}}`,不能是字符串 3. ⚠️ `name` 必填 — atomlisting 产品列表用此字段,缺失显示 "Unnamed" 4. ⚠️ atomlisting 双 API:`/remote` 读 `translations.zh.name`,`/premium-products` 读 `name`,两个都要设 5. ⚠️ `product_code` 统一 8 位十六进制,不带前缀 6. ⚠️ pymongo 某些版本 `$rename` 不可用,用 `$set` + `$unset` 两步改名 7. ⚠️ 测试/占位链接的产品(source_url 含 test1/test2/test3)主动删除 8. ⚠️ CDP 表达式过滤器禁止 async/for/forEach/Array.from,索引扫描用 while 递减循环 9. ⚠️ FlairGS 图片必须 `.convert('RGB')` 后再 JPEG 编码,否则返回空描述 ## 变参产品集创建模式 当产品有多个颜色/SKU 变体时: 1. 每个变体建独立 product_code 2. 分配到对应颜色的图片(用 FlairGS 识别) 3. 统一设置 `variant_group`, `variant_of`, `variant_type`, `variant_value` 4. 使用 `supplier_price` 和 `supplier_stock` 5. 父产品标记 `is_variant_group: true`, `variant_codes: [...]` ## FlairGS 连通性 - 优先:`http://43.160.244.125:17870` (FRP) - 备用:Desktop CDP → `http://192.168.9.105:7870` - API Key: `8Ax4TyZc66qrZgXK` - 端点:`POST /api/analyze` — 字段名 `base64` (非 `image_base64`) - 模型:GS3/qwen3-vl:8b,典型延迟 7-8s