# 商品档案公益 API 系统 — 规划方案 (v0.2) > 公益网站/服务:**采集全网商品信息**,对外提供**商品参数查询 API**。 > 原则:**只收集 + 只提供信息,不涉及任何购买/下单/比价导购**。 > 本版根据你的反馈定稿四件事:① 收录**官方标准零售价(MSRP)** ② 首批聚焦**食品快消** ③ **Go(系统) + Python(采集)** 多语言架构 ④ 附**开放数据源清单**。 --- ## 0. 你已确认的决策 | # | 决策 | 说明 | |---|------|------| | 1 | **价格 = 官方标准零售价 (MSRP)** | 厂商指导价/官方建议零售价,属**静态属性**,带来源+时间+币种标注;**不收录实时电商售价、不提供购买入口** | | 2 | **首批品类 = 食品快消 (Food & FMCG)** | 先把食品的数据模型打磨好(成分、营养、过敏原、规格、保质期…) | | 3 | **技术栈 = Go + Python** | Go 写对外 API/核心服务;Python 写采集/ETL/爬虫;通过 PostgreSQL + 消息队列解耦 | | 4 | **数据源 = 暂无,后期提供** | 本版先给出可立即接入的开放数据源清单 | --- ## 1. Go + Python 多语言架构(核心) 这是一个很经典且合理的组合。两端**不直接互相调用**,而是通过**共享数据库 + 消息队列**解耦,各自独立部署、独立扩展。 ``` ┌────────────────────── Python 侧 (采集/数据) ──────────────────────┐ │ │ 数据源 ─▶│ 采集 Workers (爬虫/适配器) ─▶ ETL 清洗/标准化/去重 ─▶ 入库 │ │ httpx / Playwright / scrapy pandas / 规则引擎 │ └───────────────────────────┬────────────────────────────────────────┘ │ 写入 ┌───────▼────────┐ ┌──────────────┐ │ PostgreSQL │◀──────▶│ 对象存储 S3 │ (商品图) │ (商品档案主库) │ └──────────────┘ └───────▲────────┘ │ 只读 ┌───────────────────────────┴────────────────────────────────────────┐ │ Go 侧 (对外服务) │ │ 公开 API (REST/JSON) + Redis 缓存/限流 + 搜索网关 + OpenAPI │ │ Gin/Echo/Chi/标准库 │ └───────────────────────────┬────────────────────────────────────────┘ │ 各种软件 / 开发者消费 ``` ### 1.1 职责划分 | 子系统 | 语言 | 职责 | |--------|------|------| | **公开 API 服务** | **Go** | 对外只读 API、限流、缓存、鉴权(可选 API Key)、检索网关、高并发承载 | | **采集 Workers** | **Python** | 每个数据源一个 adapter,抓取/调用 API、遵守 robots、限速、产出原始数据 | | **ETL / 数据处理** | **Python** | 清洗、字段映射、单位归一、实体去重与合并、质量评分 | | **调度 / 队列** | Python(worker) + Redis/消息队列 | 定时任务、增量更新、任务分发 | | **存储** | PostgreSQL + Redis + S3 | 主库 / 缓存+限流 / 图片 | | **检索** | 初期 PG 全文 → 后期 OpenSearch | 商品名/参数搜索与分面 | ### 1.2 为什么这样分? - **Go 做 API**:编译型、单二进制部署、并发模型适合高 QPS 的只读公益 API,运维简单。 - **Python 做采集**:爬虫/解析/数据处理生态最强(scrapy、playwright、pandas),迭代快。 - **解耦点 = 数据库**:Go 端**只读**主库(或读副本),Python 端负责写入。两端通过稳定的表结构约定协作,互不阻塞;将来任一端换语言/重写都不影响另一端。 - **契约**:用数据库 schema + 一份内部「数据契约文档」固定字段含义,避免两端理解不一致。 --- ## 2. 食品快消数据模型(细化) 食品参数差异大,沿用 **核心字段 + JSONB 灵活属性 + 营养结构化子表**。字段设计大量参考 Open Food Facts(成熟的食品开放库)。 ### 2.1 商品主表 `product` ```jsonc { "id": "uuid", "gtin": "6901234567892", // 条码(主键标识), EAN-13/UPC/EAN-8 "name": "示例牌 巧克力榛子酱 400g", "brand": "示例牌", // -> brand "manufacturer": "示例食品有限公司", // 生产商 "category": "食品/酱料/巧克力酱", // -> category 树 (可对齐 GS1 GPC / OFF categories) "net_content": {"value": 400, "unit": "g"}, // 净含量 "country_of_origin": "中国", "shelf_life": {"value": 12, "unit": "月"}, // 保质期 "storage": "常温避光保存", "images": ["S3_URL", ...], "msrp": { ... }, // 官方标准零售价, 见 2.3 "food": { ... }, // 食品专属结构化字段, 见 2.2 "attributes": [ {"key":"","value":"","unit":""} ], // 其余灵活参数(JSONB) "identifiers": {"ean":"", "upc":"", "off_id":""}, "sources": [ {"source":"", "url":"", "fetched_at":"", "fields":["msrp"]} ], "quality_score": 0.0, "status": "active|merged|deprecated", "created_at": "", "updated_at": "" } ``` ### 2.2 食品专属字段 `food`(结构化) ```jsonc { "ingredients_text": "白砂糖, 棕榈油, 榛子(13%), ...", // 配料表原文 "ingredients": [ {"name":"白砂糖","rank":1}, ... ], // 解析后(可选) "allergens": ["坚果", "大豆", "乳"], // 过敏原 "additives": ["E322 卵磷脂"], // 添加剂 "nutriments": { // 营养成分(每100g/100ml) "energy_kj": 2252, "energy_kcal": 539, "fat_g": 30.9, "saturated_fat_g": 10.6, "carbohydrates_g": 57.5, "sugars_g": 56.3, "protein_g": 6.3, "salt_g": 0.107 }, "nutrition_basis": "per_100g", // per_100g | per_100ml | per_serving "serving_size": "15g", "is_vegetarian": null, "is_vegan": null, // 可空 "nutri_score": "C", // 若引用 OFF "labels": ["无添加", "清真"] // 认证/标签 } ``` ### 2.3 官方标准零售价 `msrp`(重点) ```jsonc { "amount": 29.90, "currency": "CNY", "type": "msrp", // 仅 msrp/官方指导价; 不存实时电商成交价 "region": "CN", // 适用地区(价格随地区不同) "source": "厂商官网/官方价目表", "source_url": "https://...", "effective_date": "2026-01-01", // 价格生效/采集时间 "note": "官方建议零售价, 实际售价以零售商为准; 本站不提供购买" } ``` > 设计要点:价格是**带时间戳的历史快照**而非实时报价;明确 `type=msrp`、标注地区与来源;响应里附免责说明。**坚决不出现购买/跳转链接。** ### 2.4 辅助实体 `brand` / `manufacturer` / `category`(品类树) / `source`(数据来源登记) / `attribute_definition`(参数字典: 标准名·别名·单位) / `merge_log`(实体合并记录, 保留溯源)。 --- ## 3. 可立即接入的开放数据源清单(食品快消) 按"合规性 / 可用性"排序。这些可作为**种子数据 + 采集 adapter 的首批对象**。 | 数据源 | 内容 | 许可 | 接入方式 | 备注 | |--------|------|------|----------|------| | **Open Food Facts** ⭐ | 全球食品(成分/营养/过敏原/Nutri-Score/图片) | **ODbL**(数据)+DbCL+CC-BY-SA(图) | REST API + **每夜全量 dump**(CSV/MongoDB, ~9GB) | 食品首选;可贡献回写;限速 15 req/min/IP(读) | | **USDA FoodData Central** ⭐ | 美国食品营养成分(含 Branded 品牌库) | **CC0(公共领域)** | REST API(需免费 key) + JSON/CSV 下载 | 营养数据权威;商业可用 | | **GS1 / Verified by GS1**(中国商品信息服务平台) | 条码→品牌/规格/厂商(官方登记) | 受限(需企业/接口授权) | 网页查询 + API(≤1000 GTIN/次) | **条码→商品**最权威来源;2亿+条;中国数据首选 | | **brocade.io** | 开放 GTIN/条码产品库 | 开源/开放 | 免费 REST(免鉴权读) | 数据量有限,可作补充 | | **3023data 等条码接口** | 中国物品编码+UPC+ISBN | 商业(0.005~0.02元/次) | REST API | **付费**,作兜底补全,非首选 | | 各国**监管公开数据** | 食品备案/标签/能效等 | 多为公开 | 各平台 | 后续按需逐个评估合规 | **参考用开源项目(架构/数据模型借鉴,非数据源)**: - Open Food Facts Server (Product Opener) — 食品库的完整实现,可学其字段与流程 - UnoPIM / PCMT / brocade.io — 开源 PIM / 商品主数据系统,借鉴建模与去重 > 建议:**先用 Open Food Facts 全量 dump 作种子数据**(直接有海量真实食品),再用 GS1/USDA 做补全与校验。这样 MVP 阶段就有真实可查的数据。 --- ## 4. 公开 API 契约(Go 实现,只读) ``` GET /api/v1/products/barcode/{gtin} # ★最常用: 条码查档案 GET /api/v1/products/{id} # 内部ID查 GET /api/v1/products/search # ?q=&brand=&category=&allergen_free=&page=&size=&fields= GET /api/v1/products/{id}/nutriments # 仅营养 GET /api/v1/products/{id}/msrp # 仅官方零售价(含来源/时间/免责) GET /api/v1/brands | /categories # 品牌 / 品类树 GET /api/v1/sources/{id} # 数据来源透明说明 GET /healthz | /api/v1/openapi.json # 健康检查 / 机读文档 ``` 约定:版本化 `/v1/`;统一响应 `{data, meta(分页), sources(溯源)}`;分页 + `fields=` 裁剪;匿名按 IP 限流,可选免费 API Key 提配额;CDN+Redis 缓存(参数变化慢,命中率高);数据采用开放许可(CC BY / ODbL,注意 OFF 的 ODbL 传染性);**无任何购买/交易端点**。 --- ## 5. 合规与边界(公益项目重点) - **数据源许可要分清**:OFF 是 **ODbL**(衍生数据库需同样开放+署名),USDA 是 **CC0**(最宽松)。混用时要按最严格许可对外标注,避免许可冲突。 - 爬取守 robots.txt / 服务条款,礼貌限速,标明 User-Agent 身份。 - 只采**客观参数**;营销文案/评测原文不照搬(链接来源即可)。 - 无个人数据(PII),只处理商品信息。 - 站点显著声明:**仅提供信息、不提供购买、不构成消费建议**;价格为官方指导价历史快照。 - 提供权利方**纠错/下架**联系渠道。 --- ## 6. 里程碑(仍不写代码,仅规划,供确认) | 阶段 | 目标 | 关键产出 | |------|------|----------| | **M0 工程地基** | 仓库骨架 | Go API 骨架 + Python 采集骨架 + PostgreSQL + Docker Compose + CI + 数据契约文档 | | **M1 数据模型** | 食品 schema | 主表/食品字段/MSRP/辅助实体 的迁移与字典 | | **M2 种子数据** | 有真实数据 | 导入 Open Food Facts dump(食品子集) + USDA 营养补全 | | **M3 MVP API (Go)** | 可查询 | 条码/ID/搜索/营养/MSRP + OpenAPI 文档 + 限流缓存 | | **M4 采集管线 (Python)** | 自动更新 | 1~2 个 adapter(OFF API / GS1) + ETL + 去重 + 质量评分 + 调度 | | **M5 开放与规模化** | 上线 | 搜索引擎 + CDN + API Key + 众包纠错后台 + 开发者文档站 + 开放数据许可 | --- ## 7. 待你确认/补充 1. **价格范围**:确认只收「官方指导价 (MSRP)」、不碰实时电商价?(建议是) 2. **OFF 的 ODbL 许可**:可接受(意味着我们对外的数据库也要用 ODbL 并署名 OFF)?还是更想用 CC0 来源(USDA)为主以保持宽松? 3. **种子数据**:同意先导入 Open Food Facts 食品 dump 作为启动数据吗? 4. **Go Web 框架偏好**:Gin / Echo / Chi / 标准库 net/http,有偏好吗?(无偏好我默认 Chi 或标准库,轻量) 5. **地域范围**:首批面向中国市场商品,还是中外都收?(影响优先用 GS1-China 还是 OFF 全球库) > 你确认后,我把它定为 v1.0 规划,并据此拆成可执行的工程任务清单(仍按你的节奏,需要我动手写代码时再开始)。