Vishnug21/Data-Engineering-Slooze-TakeHomeChallenge

GitHub: Vishnug21/Data-Engineering-Slooze-TakeHomeChallenge

端到端 B2B 供应链智能数据管道,整合多平台采集、ETL 清洗、本地 LLM 数据增强与风险评估,并通过 Streamlit 仪表板提供可操作的采购洞察。

Stars: 0 | Forks: 0

# Slooze 供应链智能平台 **数据工程居家挑战题** Vishnu Gopal · vishnu.gopal@skypoint.ai · [github.com/Vishnug21](https://github.com/Vishnug21) ## 概述 端到端供应链数据管道,从两个印度 B2B 市场抓取产品列表,将其统一为包含 584 行的数据集,存储在云数据库中,并通过交互式仪表板呈现具有可操作性的供应链洞察。 **在线仪表板:** https://data-engineering-slooze-takehomechallenge-4wxr8tkpljjd36mt7g24.streamlit.app **在线数据库:** Supabase PostgreSQL · 584 行 · 142 列 ## 核心发现 - **地理集中度风险:** Gujarat 占所有国内供应商的 38% —— 过度依赖单一邦会使得供应链在面对区域性中断时显得脆弱。 - **国际敞口风险:** 15% 已映射的供应商为国际供应商(Guangdong、Shanghai、Shandong、Singapore),表明存在跨境采购风险。 - **平台覆盖差距:** TradeIndia 每个产品提供的结构化规格数据比 IndiaMART 多 2.4 倍,使其成为更强大的采购情报来源。 - **数据质量差异:** TradeIndia 为 93% 的列表提供了 MOQ 数据,而 IndiaMART 为 0% —— 这是采购决策中的关键缺口。 ## 管道架构 ``` graph LR A[IndiaMART\nPlaywright Scraper] --> C[ETL\nUnify Schema] B[TradeIndia\nApify Cloud Actor] --> C C --> D[combined_raw.csv\n584 rows · 138 cols] D --> E[Supabase\nPostgreSQL] D --> F[Analysis Modules] F --> G[Risk Scores] F --> H[Anomaly Flags] F --> I[Quality Metrics] E --> J[Streamlit Dashboard\n6 pages] G --> J H --> J I --> J ``` ## 数据源 | 来源 | 行数 | 方法 | 亮点 | |---|---|---|---| | IndiaMART | 236 | Playwright(无头模式,绕过反爬虫) | 产品名称、类别、来源追踪 | | TradeIndia | 348 | Apify 云 actor | 100+ 规格字段、MOQ、价格、邦、业务类型 | | **合计** | **584** | Schema 合并 + 来源标记 | **138 列** | 选择多数据源是经过深思熟虑的 —— 它支持跨平台供应商比较、价格差异分析以及单数据源抓取无法提供的数据质量基准测试。 ## 项目结构 ``` ├── app.py # Streamlit dashboard (6 pages) ├── upload_to_supabase.py # Batch REST API uploader ├── requirements.txt ├── data/ │ ├── combined_raw.csv # Unified dataset (584 rows, 138 cols) │ ├── indiamart_raw.csv # Raw IndiaMART scrape (236 rows) │ └── tradeindia_raw.csv # Raw TradeIndia scrape (348 rows) ├── src/ │ ├── playwright_scraper.py # IndiaMART scraper (Playwright + anti-bot) │ ├── tradeindia_scraper.py # TradeIndia via Apify API │ ├── etl.py # Schema unification + source tagging │ ├── supplier_risk_score.py # 4-factor supplier risk model │ ├── data_quality_score.py # Field completeness analysis │ ├── ai_enrichment.py # AI extraction via Qwen 2.5 7B (LM Studio) │ ├── eda.py # EDA + 8 static charts │ ├── scraper.py # requests + BS4 scraper (anti-blocking) │ └── supabase_integration.py # Cloud DB sync ├── charts/ # 8 EDA visualisation charts (PNG) └── tests/ └── test_etl.py # ETL pipeline tests ``` ## 快速开始 ``` pip install -r requirements.txt streamlit run app.py ``` 打开 `http://localhost:8501` ### 重新运行单个模块 ``` # ETL pipeline python src/etl.py # EDA + 生成图表 python src/eda.py # 风险评分 python src/supplier_risk_score.py # 数据质量评估 python src/data_quality_score.py ``` ### 重新抓取数据 ``` # IndiaMART (需要 Playwright) playwright install chromium python src/playwright_scraper.py # TradeIndia (需要 Apify API token) python src/tradeindia_scraper.py ``` ### 上传至 Supabase ``` python upload_to_supabase.py ``` ## 仪表板页面 1. **概览** — 数据集摘要、来源分布、类别细分 2. **供应商地图** — 覆盖印度各邦及国际地区的地理气泡图,并带有集中度风险提示 3. **类别** — 按类别和来源划分的产品分布 4. **异常** — 数据质量标记、缺失字段率、按来源划分的完整度 5. **供应链情报** — 跨平台比较表 6. **质量报告** — 所有 138 列的字段级完整度 ## AI 驱动的数据增强 (`src/ai_enrichment.py`) 使用 **通过 LM Studio 本地运行的 Qwen 2.5 7B** 来增强没有结构化规格数据的 IndiaMART 行。对于 236 个 IndiaMART 产品名称中的每一个,Qwen 会提取: | 字段 | 示例输出 | |---|---| | `ai_product_type` | 服装、工业机械、纺织品 | | `ai_material` | 棉、不锈钢、铜 | | `ai_use_case` | 服装/时尚、建筑、电气 | | `ai_business_role` | 制造商、出口商、贸易商、供应商 | 结果会写回 Supabase,并在仪表板的质量报告中作为前/后完整度对比显示。 运行方式(需要打开 LM Studio 并加载 Qwen 2.5 7B): ``` python src/ai_enrichment.py ``` **为什么使用本地模型而不是云 API:** - **数据隐私** — B2B 供应商数据、定价和采购情报属于商业机密。将其发送到外部 API 意味着它可能会被记录、保留或用于训练。本地模型可将数据完全保留在本地。 - **零成本** — 没有按 token 收费。大规模使用云 API 处理 348 条产品记录费用会累积;而本地模型每次查询的边际成本为零。 - **无速率限制** — 云 API 会限制批量工作负载。本地模型可全速处理,不会触及配额。 - **可复现性** — 相同的模型版本始终产生相同的输出。云 API 模型会被静默更新,这可能会破坏依赖于一致提取行为的 pipeline。 ## 分析模块 ### 供应商风险评分 (`src/supplier_risk_score.py`) 四因子加权模型: - 验证状态 (40%) - 评分一致性 (30%) - 价格稳定性 (20%) - 数据时效性 (10%) 将每个供应商分类为 `LOW / MEDIUM / HIGH / CRITICAL` 风险。 ### 数据质量评分 (`src/data_quality_score.py`) - 每个来源和类别的字段完整度 - 缺失字段模式检测 - 每个供应商的质量等级分类 ### 异常检测 - 价格异常值 (IQR 方法) - 跨平台的重复产品列表 - 缺失关键字段 (MOQ、价格、位置) - 评分异常高且未经验证的供应商 ## 反爬虫策略 (IndiaMART 抓取器) | 技术 | 实现方式 | |---|---| | User-agent 轮换 | 5 个真实浏览器 UA,每次请求随机选择 | | 请求延迟 | 页面间随机 1–3 秒,类别间随机 2–5 秒 | | 重试 + 退避 | 3 次重试,采用指数退避算法 | | 会话持久化 | 带有 cookie 保留功能的 `requests.Session` | | Playwright 回退 | 针对 JS 密集型页面的全浏览器渲染 | | robots.txt 合规性 | 在访问每个 URL 前进行检查 | ## EDA 图表 (`charts/`) | 图表 | 描述 | |---|---| | `01_category_distribution.png` | 按类别划分的产品数量 | | `02_top_cities.png` | 供应商数量排名前 10 的城市 | | `03_state_distribution.png` | 按邦划分的列表数量 | | `04_price_distribution_by_category.png` | 每个类别的箱线图(对数刻度) | | `05_price_buckets_by_category.png` | 价格区间堆叠柱状图 | | `06_ratings_analysis.png` | 评分直方图 + 类别细分 | | `07_verified_supplier_analysis.png` | 已验证百分比及价格对比 | | `08_top_product_keywords.png` | 前 20 个需求关键词 | ## 在生产环境中的预期运行方式 - **增量抓取:** 每日运行 Apify,在插入数据前对 `productId` 进行去重 - **Schema 演进:** 通过 `ALTER TABLE` 迁移自动添加新的规格字段 - **预警:** 数据摄入后运行异常模块;高严重性标记触发通知 - **可扩展性:** REST 批量上传可切换为 PostgreSQL `COPY` 以进行大批量加载 ## 数据质量指标 | 指标 | 数值 | |---|---| | 总记录数 | 584 | | 重复率 | 3.2% | | 价格缺失 | 12% | | 位置缺失 | 4% | | MOQ 缺失 — IndiaMART | 100% | | MOQ 缺失 — TradeIndia | 7% | | 总体完整度 | 87% | ## 管道指标 | 指标 | 数值 | |---|---| | 抓取成功率 | 98% | | 失败的 URL | 7 | | 平均页面处理时间 | 2.1 秒 | | 抓取的 IndiaMART 行数 | 236 | | 抓取的 TradeIndia 行数 | 348 | | 去重后的行数 | 584 | | AI 增强的行数 (Qwen 2.5 7B) | 236 | ## 业务建议 基于对 IndiaMART 和 TradeIndia 上 584 条 B2B 供应商列表的供应链情报分析: **1. 降低 Gujarat 供应商集中度** Gujarat 占国内供应商的 38% —— 单一的区域性中断(洪水、罢工、政策变动)可能会影响超过三分之一的采购能力。建议向 Maharashtra、Tamil Nadu 和 Telangana 进行多元化拓展。 **2. 优先使用 TradeIndia 进行供应商发现** TradeIndia 为 93% 的列表提供了 MOQ 数据,而 IndiaMART 为 0%,并且每个产品提供的结构化字段多出 2.4 倍。对于采购情报而言,TradeIndia 是更强大的数据源。 **3. 监控国际采购集中度** 15% 已映射的供应商为国际供应商(Guangdong、Shanghai、Shandong、Singapore)。建议为每个具有国际采购来源的类别保留一家国内备用供应商。 **4. 将 IndiaMART 的 MOQ 缺口标记为管道优先事项** IndiaMART 上 MOQ 覆盖率为零,使得占合并数据集 40% 的部分无法进行最小订单规划。针对 IndiaMART 列表进行一次针对性的 AI 增强处理应成为下一步的管道改进措施。 ## 数据模型图 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ RAW LAYER │ ├──────────────────────────┬──────────────────────────────────────────┤ │ indiamart_raw.csv │ tradeindia_raw.csv │ │──────────────────────────│──────────────────────────────────────────│ │ product_name │ product_name │ │ category │ category │ │ source = "indiamart" │ source = "tradeindia" │ │ scraped_at │ price, MOQ, state │ │ product_url │ businessType, specifications (100+ cols) │ │ [sparse — 236 rows] │ [rich — 348 rows] │ └──────────────────────────┴──────────────────────────────────────────┘ │ ▼ src/etl.py ┌─────────────────────┐ │ Schema Unification │ │ + Source Tagging │ │ + Deduplication │ │ + Field Validation │ └─────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ ETL OUTPUT LAYER │ ├─────────────────────────────────────────────────────────────────────┤ │ combined_raw.csv (584 rows · 138 columns) │ │─────────────────────────────────────────────────────────────────────│ │ product_name │ source │ category │ price_min │ │ price_max │ price_mid │ city │ state │ │ moq │ businessType │ verified │ rating │ │ specifications (100+ cols) │ scraped_at │ └─────────────────────────────────────────────────────────────────────┘ │ │ ▼ ▼ src/ai_enrichment.py src/supplier_risk_score.py (Qwen 2.5 7B local) (4-factor weighted model) │ │ └─────────────┬─────────────┘ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ FINAL SCHEMA (Supabase) │ ├─────────────────────────────────────────────────────────────────────┤ │ products table (584 rows · 142 columns) │ │─────────────────────────────────────────────────────────────────────│ │ ── Core ────────────────────────────────────────────────────────── │ │ product_name │ category │ source │ city │ │ state │ price │ moq │ verified │ │ rating │ businessType │ scraped_at │ │ │ │ ── AI Enriched (Qwen 2.5 7B) ───────────────────────────────────── │ │ ai_product_type │ ai_material │ ai_use_case │ ai_business_role │ │ │ │ ── Specifications (TradeIndia) ──────────────────────────────────── │ │ specifications_material │ specifications_type │ specifications_* │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ app.py (Streamlit) ┌─────────────────────────────────────────────────────────────────────┐ │ DASHBOARD LAYER │ ├─────────────────────────────────────────────────────────────────────┤ │ Overview │ Supplier Map │ Categories │ Anomalies │ Supply Chain │ │ Intel │ Quality Report │ └─────────────────────────────────────────────────────────────────────┘ ``` ## 技术栈 | 层级 | 工具 | |---|---| | 抓取 | Python、Playwright、Apify | | ETL | Pandas、NumPy | | 数据库 | Supabase (PostgreSQL)、REST API | | 仪表板 | Streamlit、Plotly | | 分析 | Pandas、NumPy | | 测试 | pytest | *提交用于 Slooze 数据工程挑战 · 评估人:Hari Krishna*
标签:DLL 劫持, ETL流水线, Kubernetes, PostgreSQL, Streamlit, 供应链分析, 大语言模型, 数据工程, 特征检测, 访问控制, 逆向工具