简介这份资源是一套基于 TypeScript 与 React 的前端工程化项目源码面向希望理解现代脚手架配置、构建流程与测试体系的初中级前端开发者。项目通过引导方式搭建完整保留了 npm start、npm test、npm run build 与 npm run eject 等标准脚本便于读者在开发模式下调试、在生产模式下打包优化并观察 webpack、Babel、ESLint 等工具的协同方式。压缩包共 1080 个文件约 4.79MB以 622 个 js 文件为主体辅以 151 个 md 说明、108 个 json 配置、28 个 ts 与 14 个 tsx 源码另有 license、yml、scss、eslintrc 等工程配套文件目录结构清晰适合按模块检索。目前已有 335 人学习下载。读者可借此掌握从开发到构建的完整链路理解依赖管理与配置分离思路并对照脚本说明排查常见构建问题适合作为前端工程化入门与脚手架二次开发的参考素材。1. 阿迪达斯从一条商品标题里拆出可复现的数据管道电商数据团队最常接到的需求之一就是把某个品牌的商品信息稳定地抓下来、洗干净、存成能直接喂给分析模型的结构化数据。阿迪达斯这个标题放在技术语境里指向的就是一条围绕品牌商品数据的采集、解析、入库、校验的完整链路。它不神秘但坑很密页面结构随季节改版、尺码库存异步加载、价格带促销逻辑、图片懒加载、反爬策略随流量波动。我做过几个类似的品牌商品数据管道阿迪达斯这条线的特点是 SKU 维度多、颜色尺码组合爆炸、区域定价差异大。适合谁适合手里已经有 Python 基础、想把这套东西跑通并长期维护的工程师也适合做竞品分析、价格监控、选品模型的数据从业者。下面按我实际落地的顺序把这条链路拆开讲。2. 先想清楚抓什么阿迪达斯商品数据的字段建模与采集边界动手写第一行代码之前最该花时间的是字段建模。阿迪达斯商品页面上能看到的和接口里能拿到的往往不是一回事。我一般先把「业务要什么」和「页面给什么」两张表对齐再决定采集范围。2.1 商品主数据、SKU 与价格库存的三层结构阿迪达斯的商品数据天然分三层。第一层是商品主数据product包含标题、品牌、品类、描述、主图列表、上市时间。第二层是 SKU也就是颜色加尺码的组合每个组合有独立的 SKU 编码、条码、库存状态。第三层是价格与促销同一 SKU 在不同区域、不同会员等级、不同活动周期下价格不同。建模时如果只抓一个扁平表后面做价格趋势分析会非常痛苦。我通常建三张表表名主键关键字段更新频率productproduct_idtitle, category, description, images每日skusku_idproduct_id, color, size, barcode每日price_stocksku_id region dateprice, currency, stock_status每 6 小时这个结构的好处是价格波动只写第三张表主数据和 SKU 变动少存储和比对成本都低。很多新手一上来把所有字段塞一张宽表跑两周就发现历史价格被覆盖后悔药没得吃。2.2 用 Python 请求商品列表接口的最小可运行示例阿迪达斯的前端通常走 JSON 接口拿列表和详情。与其解析 HTML不如直接找接口。下面是我常用的最小请求骨架用 requests 加会话保持带重试和超时。import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry import time # 建立带重试的会话避免偶发网络抖动导致整批失败 session requests.Session() retry Retry(total3, backoff_factor1.5, status_forcelist[429, 500, 502, 503]) session.mount(https://, HTTPAdapter(max_retriesretry)) HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Accept: application/json, Accept-Language: zh-CN,zh;q0.9, } def fetch_product_list(page: int, page_size: int 48): 拉取商品列表page 从 0 开始 url https://www.example-brand-site.com/api/plp params { page: page, pageSize: page_size, sort: newest, } resp session.get(url, headersHEADERS, paramsparams, timeout15) resp.raise_for_status() data resp.json() # 接口通常返回 items 和 totalCount这里做防御性取值 items data.get(items, []) total data.get(totalCount, 0) time.sleep(1.2) # 控制频率别把对方打疼 return items, total逻辑说明Retry 的 backoff_factor 设 1.5意味着第一次重试等 1.5 秒第二次 3 秒第三次 4.5 秒给服务端喘息空间。time.sleep(1.2) 是经验值低于 1 秒在批量翻页时容易触发限流。参数 page_size 不要贪大48 到 60 之间比较稳太大接口可能截断。2.3 详情页字段解析颜色尺码矩阵怎么拆列表接口一般只给商品概要颜色和尺码要进详情接口。详情返回的结构里variants 或 skus 数组是核心。每个元素包含 color、size、sku、availability。解析时注意两点一是颜色名可能是本地化字符串要做归一化映射二是尺码有 UK、US、EU 多套体系必须统一到一套再入库。def parse_variants(detail_json: dict): 把详情接口的 variants 拆成标准 SKU 列表 rows [] product_id detail_json.get(id) for v in detail_json.get(variants, []): rows.append({ product_id: product_id, sku_id: v.get(sku), color: v.get(color, ).strip(), size: v.get(size, ).strip(), barcode: v.get(barcode), stock_status: in_stock if v.get(availability) InStock else out_of_stock, }) return rows参数说明color 做 strip 是因为部分接口返回值带尾部空格直接入库会导致同色不同记录。stock_status 用枚举映射而不是存原始字符串后面做库存率统计时不用再写一堆 if。如果接口没有 barcode就留空别用 sku 顶替两者语义不同。3. 把数据落进库清洗、去重与增量更新的具体做法抓下来只是原料真正决定这条管道能不能长期跑的是清洗和增量策略。我见过太多脚本第一周全量跑通第二周开始重复数据堆成山。3.1 用 pandas 做字段标准化与异常值过滤原始 JSON 转 DataFrame 之后先做几件固定动作价格转数值、日期转 datetime、颜色和尺码做映射表替换、过滤掉价格为 0 或负数的记录。import pandas as pd COLOR_MAP {黑: black, 白: white, 红: red, 蓝: blue} SIZE_ORDER [XS, S, M, L, XL, XXL] def clean_products(df: pd.DataFrame) - pd.DataFrame: df df.copy() # 价格字段可能是 ¥899.00 这种字符串 df[price] pd.to_numeric(df[price].astype(str).str.replace(r[^\d.], , regexTrue), errorscoerce) df df[df[price] 0] # 颜色归一化未命中映射的保留原值并打标 df[color_std] df[color].map(COLOR_MAP).fillna(df[color]) # 尺码排序方便后续按尺码维度聚合 df[size] pd.Categorical(df[size], categoriesSIZE_ORDER, orderedTrue) df df.drop_duplicates(subset[sku_id, region], keeplast) return df逻辑说明价格清洗用正则去掉货币符号和千分位errorscoerce 把无法解析的变成 NaN 再过滤比 try-except 逐行处理快得多。drop_duplicates 的 subset 选 sku_id 加 region是因为同一 SKU 在不同区域是两条合法记录不能只按 sku_id 去重。3.2 增量更新用 upsert 代替全量覆盖全量删表重插在数据量小的时候没问题一旦上到几十万 SKU每天重跑既慢又容易在写入中途失败留下半截数据。我一般用 upsert主键冲突时更新价格和库存主数据字段只在为空时补写。-- PostgreSQL 的 upsert 写法 INSERT INTO price_stock (sku_id, region, date, price, currency, stock_status) VALUES (%s, %s, %s, %s, %s, %s) ON CONFLICT (sku_id, region, date) DO UPDATE SET price EXCLUDED.price, stock_status EXCLUDED.stock_status, updated_at NOW();参数说明ON CONFLICT 的目标列必须和唯一索引一致建表时就要把 (sku_id, region, date) 设成唯一约束。EXCLUDED 代表本次试图插入的那行用它来覆盖旧值。updated_at 用数据库时间而不是应用时间避免多机部署时时钟不一致。3.3 调度与监控别让管道静默死掉调度我常用两种轻量用 cron 加 shell 包装重一点用 Airflow。不管哪种必须加监控。最低限度要记录每次运行的抓取条数、入库条数、失败条数连续两次抓取条数为 0 就告警。# crontab 示例每 6 小时跑一次日志按天切 0 */6 * * * /usr/bin/python3 /opt/pipeline/run.py /var/log/adidas_pipeline/$(date \%Y\%m\%d).log 21注意日志目录要提前建好并给写权限否则 cron 静默失败你连报错都看不到。我踩过这个坑排查了半天才发现是目录不存在。4. 避坑与排查阿迪达斯数据管道里最容易翻车的五件事这一章是我自己踩过和帮别人排查过的真实问题按现象、原因、解决三段写。每一条都值得在代码里提前防。4.1 翻页到一半返回空列表现象前几页正常翻到第 10 页左右 items 变成空数组totalCount 还在。原因接口对深分页有限制或者触发了软限流返回 200 但内容为空。解决不要只判断 HTTP 状态码要判断 items 长度。连续两页为空就停止并记录当前页码下次从该页续跑。同时把 sleep 从 1.2 秒提到 2 秒以上再试。4.2 价格字段混入促销价和原价现象同一 SKU 两次抓取价格差一倍分析时以为在打折。原因接口在不同上下文返回不同价格字段有时是原价有时是促销价字段名还相似。解决把接口返回的价格相关字段全部打印出来对比一次确认哪个是当前售价、哪个是划线价入库时分开存 current_price 和 original_price别只存一个 price。4.3 颜色尺码矩阵缺行现象某商品明明有 5 个颜色入库只有 3 个。原因详情接口的 variants 默认只返回有库存的组合缺货组合被过滤。解决请求时带上 include_out_of_stocktrue 之类的参数具体参数名看接口文档如果接口不支持就在解析时记录缺失并打标别当成数据完整。4.4 时区导致日期错位现象每天凌晨跑的任务入库日期比实际晚一天。原因服务器用 UTC业务按本地时区算日期。解决所有 date 字段在应用层统一转成目标时区再入库数据库存 date 类型而不是 timestamp避免时区二次转换。4.5 图片 URL 过期现象入库的图片链接过两周全部 403。原因图片走 CDN 签名URL 带时效 token。解决只存图片 ID 或相对路径展示时再拼当前有效的 CDN 前缀。如果必须存完整 URL加一个定时任务定期刷新。5. 让管道更耐用校验规则、重跑机制与一个实用技巧管道跑通不难难的是跑三个月不出事。这一章讲两个我固定会加的机制以及一个能省大量排查时间的技巧。5.1 入库前的数据质量校验清单每次写入前跑一遍校验不通过就阻断并告警。我常用的规则校验项规则失败动作条数波动本次条数 / 上次条数 在 0.7 到 1.3 之间告警人工确认价格范围price 在 50 到 5000 之间过滤该行并记录主键唯一sku_id region date 无重复阻断写入必填字段product_id, sku_id 非空过滤该行并记录这套规则用 pandas 几行就能实现但能挡住八成以上的脏数据事故。条数波动那条尤其有用页面改版导致解析失败时条数会断崖式下跌比等业务方发现早好几天。5.2 断点续跑把进度写进 Redis批量任务最怕跑到一半挂了要从头来。我的做法是每处理完一页就把当前页码和已入库条数写进 Rediskey 带任务日期。重跑时先读 Redis有进度就从下一页继续。import redis r redis.Redis(hostlocalhost, port6379, db0) def get_progress(task_key: str) - int: val r.get(task_key) return int(val) if val else 0 def save_progress(task_key: str, page: int): r.set(task_key, page, ex86400) # 一天后过期避免脏进度参数说明ex86400 是过期时间防止昨天的进度影响今天。task_key 建议用 pipeline:adidas:20250101 这种格式日期一变就是新任务。这个机制加上去之后重跑成本从半小时降到几分钟。5.3 一个技巧用快照对比代替逐字段 diff判断哪些 SKU 发生了变化逐字段比对很慢。我一般每天存一份当天全量快照到单独的表然后用 SQL 的 EXCEPT 或 pandas 的 merge 找出差异。这样不仅能知道变了什么还能回溯任意两天的差异做价格趋势分析时直接查快照表就行。-- 找出今天相对昨天价格变化的 SKU SELECT t.sku_id, t.price AS today_price, y.price AS yesterday_price FROM price_stock t JOIN price_stock y ON t.sku_id y.sku_id AND t.region y.region WHERE t.date CURRENT_DATE AND y.date CURRENT_DATE - INTERVAL 1 day AND t.price y.price;这个查询在 sku_id 和 date 上有索引的话几十万行也是秒级。我一般把这个结果再写一张变化表业务方直接看变化表不用扫全量。最后说个我自己的习惯每次改完解析逻辑先拿 20 个商品跑一遍人工核对字段确认无误再放全量。这个动作花五分钟能省掉后面几小时的排查。数据管道这行慢就是快。希望帮到你。本文还有配套的精品资源点击获取