platform-assistant/scripts/parse_products.py
Sisyphus afac18e843 feat(F002): W26 + W29.x + W30 + W31 平台助手全部改动首次 commit
- W26: NestJS API + Next.js Web + Prisma + SQLite scaffold
- W26: Lead 模型 + Crawler + 询价发布助手 (线索池 + 一键发布)
- W29.x: MCP 集成 (Integration 模型 + connectMcp + publish_rfq 5 工具端到端跑通)
- W30: 3 字段补充 (notes / quotationType / quotationDemand)
- W31 P1: 自动填 enterpriseId / userId (Prisma companyUserId 字段 + get_app_identity tool + lead.service.ts publishArgs)
- W31: detail 详情页 + admin UI 集成管理 (OpenAppListView + AuditLogListView)

关联: ~/Documents/02-平台开发/产品开发/F002-W31-交接文档.md
GIT-AUDIT-REPORT-2026-06-24.md
2026-06-24 11:07:11 +08:00

149 lines
5.1 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
商品列表解析脚本
用法: python3 parse_products.py <文件路径>
输出: JSON [{ "name": "商品名", "spec": "规格", "category": "分类" }, ...]
"""
import sys
import json
import os
def _read_excel(filepath: str):
import pandas as pd
is_unnamed_cols = False
# Attempt 1: default header=0
df = pd.read_excel(filepath, dtype=str)
raw_cols = list(df.columns)
unnamed_count = sum(1 for c in raw_cols if c.startswith('Unnamed'))
total_cols = len(raw_cols)
# If most columns are "Unnamed" or header looks like a title, retry with header=1
if unnamed_count > total_cols / 2 or total_cols == 1:
is_unnamed_cols = True
df = pd.read_excel(filepath, dtype=str, header=1)
# If still mostly unnamed, try without header and use first non-empty row as header
raw_cols = list(df.columns)
unnamed_count = sum(1 for c in raw_cols if c.startswith('Unnamed'))
if unnamed_count > len(raw_cols) / 2:
is_unnamed_cols = True
raw = pd.read_excel(filepath, dtype=str, header=None)
for i in range(min(5, len(raw))):
row = raw.iloc[i]
vals = [str(v).strip() for v in row if str(v).strip().lower() != 'nan']
if len(vals) > 2:
df = pd.read_excel(filepath, dtype=str, header=i)
break
return df
def _read_csv(filepath: str):
import pandas as pd
df = pd.read_csv(filepath, dtype=str, encoding='utf-8-sig')
return df
def _match_col(norm_map: dict, keywords: list[str]) -> str:
for kw in keywords:
nk = kw.lower().replace(' ', '').replace(' ', '')
if nk in norm_map:
return norm_map[nk]
# 模糊匹配:关键词是列名的子串
for kw in keywords:
nk = kw.lower().replace(' ', '').replace(' ', '')
for norm, orig in norm_map.items():
if nk in norm:
return orig
return ''
def parse_file(filepath: str) -> list[dict]:
ext = os.path.splitext(filepath)[1].lower()
if ext in ('.xlsx', '.xls'):
df = _read_excel(filepath)
elif ext == '.csv':
df = _read_csv(filepath)
else:
raise ValueError(f'不支持的文件格式: {ext}')
if df.empty:
return []
# 标准化列名
raw_cols = list(df.columns)
norm_map = {}
for c in raw_cols:
norm = c.strip().lower().replace(' ', '').replace(' ', '')
norm_map[norm] = c
name_col = _match_col(norm_map, ['商品名称', '商品名', '名称', '产品名称', '品名', 'name', 'productname', '产品名'])
spec_col = _match_col(norm_map, ['规格', '规格型号', '型号', 'spec', '规格描述', '规格参数'])
cat_col = _match_col(norm_map, ['分类', '商品分类', '品类', 'category', '类别', '类目'])
price_col = _match_col(norm_map, ['价格', '单价', '报价', 'price', '售价', '销售价', '报价(元)', '报价(元)', '含税价'])
unit_col = _match_col(norm_map, ['单位', '计量单位', 'unit', '数量单位'])
brand_col = _match_col(norm_map, ['品牌', 'brand', '厂家', '制造商', '生产厂家'])
qty_col = _match_col(norm_map, ['数量', 'quantity', '库存', '库存数量', 'qty'])
if not name_col and raw_cols:
name_col = raw_cols[0]
results = []
for _, row in df.iterrows():
name_raw = row.get(name_col)
if name_raw is None:
continue
name = str(name_raw).strip()
if not name or name.lower() == 'nan':
continue
spec = str(row.get(spec_col, '') or '').strip()
if spec.lower() == 'nan':
spec = ''
category = str(row.get(cat_col, '') or '').strip()
if category.lower() == 'nan':
category = ''
price = row.get(price_col)
if price is not None:
try:
price = float(str(price).replace(',', '').replace('¥', '').replace('¥', '').strip())
except (ValueError, TypeError):
price = 0
else:
price = 0
unit = str(row.get(unit_col, '') or '').strip()
if unit.lower() == 'nan':
unit = ''
brand = str(row.get(brand_col, '') or '').strip()
if brand.lower() == 'nan':
brand = ''
qty_raw = row.get(qty_col)
quantity = 0
if qty_raw is not None:
try:
quantity = int(float(str(qty_raw).replace(',', '').strip()))
except (ValueError, TypeError):
quantity = 0
results.append({
'name': name,
'spec': spec,
'category': category,
'price': price,
'unit': unit,
'brand': brand,
'quantity': quantity,
})
return results
if __name__ == '__main__':
if len(sys.argv) < 2:
print(json.dumps({'error': '请提供文件路径'}))
sys.exit(1)
try:
data = parse_file(sys.argv[1])
print(json.dumps(data, ensure_ascii=False))
except Exception as e:
print(json.dumps({'error': str(e)}, ensure_ascii=False))
sys.exit(1)