ALL-Link 价格提取 Skill
提取 ALL-Link 空运运价表 → 24列标准输出 → 上传 WPS。
⚠️ 铁律:仅提取用户最新提交文件,禁止复制历史数据
- 禁止查看/引用/复制任何历史脚本中的 price/data 数组
- 禁止从历史输出文件(如
*_output.xlsx)直接读取数据 - 禁止硬编码历史图片/Excel 路径作为源文件
- 每次提取必须从用户当前提交文件全新读取
- 有就是有,没有就是没有:不得用历史数据填补缺失值
- 历史提取数据仅作规则参考,不能作为当前输出
一、核心参数(固定不变)
| 参数 | 值 | |------|-----| | 起始港 | PVG | | 价格编号 | alllink_alllink_001 | | 来源 | ALLLINK | | 货型 | 统一 1:1(无阶梯比重) | | 散托类型 | 统一 散货/托盘 | | 开始比重 | 0 | | 结束比重 | 9999 |
二、强制流程(铁律)
每次收到 ALL-Link 文件后按以下步骤执行:
1. 确定批次日期(文件日期/收件日期)
2. 更新脚本中 cutoff_date = datetime(年份, 月, 日)
3. 对照源文件逐 Sheet 确认配置:
- Sheet 名称/编号是否正确
- 航司列表是否完整
- default_date 是否需要更新
- 表头是否有新增特殊格式
4. 运行脚本提取
5. validate_columns() 验证
6. **自动上传 WPS**(`main()` 尾部调用 `upload_wps.upload_excel_and_notify()`,无需手动操作)
三、Sheet 类型与提取顺序
ALL-Link 文件包含 12 个 Sheet,分 4 类处理,main() 中固定顺序:
第1步: extract_standard_sheets() → Sheet 1-6, 9, 10, 12
第2步: extract_sheet11() → MU 日本线(特殊列头)
第3步: extract_sheet7_qt() → QT 专线(3数据块)
第4步: extract_sheet8_uc() → UC 智利航空(DEST在col0)
顺序对最终结果无影响,但必须四个函数都调用。
四、标准 Sheet 配置(extract_standard_sheets)⚠️ 每次批次需要更新
sheet_config = {
'1': {'carriers': ['MU', 'CK', 'CA', 'CZ'], 'default_date': datetime(2026, 5, 20)},
'2': {'carriers': ['KZ', 'CV', 'D0'], 'default_date': datetime(2026, 5, 18)},
'3': {'carriers': ['O3'], 'default_date': datetime(2026, 5, 18)},
'4': {'carriers': ['CK', 'CA', 'CZ', 'Y8'], 'default_date': datetime(2026, 5, 21)},
'5': {'carriers': ['KZ', 'D0', 'QF', 'KE', 'MU'], 'default_date': datetime(2026, 5, 21)},
'6': {'carriers': ['CX', 'CZ', '5Y'], 'default_date': datetime(2026, 5, 14)},
'9': {'carriers': ['MU', 'CA', 'CX', 'JL', 'KZ', 'RH', 'CK'], 'default_date': datetime(2026, 5, 18)},
'10': {'carriers': ['MH', 'GA'], 'default_date': datetime(2026, 5, 11)},
'12': {'carriers': ['MU', 'HO', 'NZ'], 'default_date': datetime(2026, 5, 14)},
}
⚠️ 新批次必须做的事:
- 打开源文件逐个 Sheet 对照,确认航司列表是否正确
default_date是兜底值,生效日期优先从表头Effective Date提取- 航司列表必须按源文件中实际出现顺序排列
五、生效日期处理
5.1 查找优先级
- 当前航司行查找
Effective Date(parse_effective_date(row)) - 向后扫描 8 行兜底查找
- config default_date 兜底
5.2 过滤规则
cutoff_date = datetime(2026, 5, 18) # ← 每批次修改
if effective_date < cutoff_date:
return None # 跳过旧价格
5.3 parse_effective_date 实现
遍历行中所有单元格,找到含 Effective 的格,取其右侧一格的值转为 datetime。
六、表头解析(parse_header)
列映射关键词对照:
| 关键字 | 映射字段 |
|--------|---------|
| DEST | 目的港 |
| +45K / +45 | 45KG |
| +100K / +100 | 100KG |
| +300K / +300 | 300KG |
| +500K / +500 | 500KG |
| +1000K / +1000 | 1000KG |
| 航班 | 频次 |
| 备注 | Remark |
七、数据解析规则
7.1 价格解析(parse_price)
TACT/Nil/NIL/-/// 空白 →None- 其他 →
float(str),保留小数,禁止 int()
7.2 频次解析(parse_frequency)
1.3.4.6→D1346(去除.和,后加 D 前缀)daily→Daily- 其他保留原值
7.3 多目的地解析(extract_multi_dest)
/分隔 → 拆分- 空格分隔 → 拆分
- 无分隔连续三字码
DXBDWC→ 正则提取[A-Z]{3}拆分
7.4 数据行跳过条件
- 目的港列空、
#、ZONE - 含
中转点运费/表内/燃油/战争/Effective - 所有 5 个重量段价格全为空的行
八、Sheet 11 特殊规则(MU 日本线)
核心问题:MU 日本线表头为 +100K, +500K, +1000K, +2000K(无 +300K)。
检测条件:'500' in col_map and '300' not in col_map
映射规则: | 源列 | → 标准字段 | |------|-----------| | col4 (+45K) | 45KG | | col5 (+100K) | 100KG | | col6 (+500K) | 300KG(用500K的值) | | col7 (+1000K) | 500KG(用1000K的值) | | col8 (+2000K) | 1000KG |
九、Sheet 7 QT 规则
结构:3 个数据块(硬编码行列范围),每批次需对照源文件修正。
blocks = [
{'data_start': 8, 'data_end': 38, 'routing': 'LGG-MAD-BOG', 'date': datetime(2026, 5, 19), 'freq_col': 11, 'remark_col': 12},
{'data_start': 45, 'data_end': 76, 'routing': 'LAX', 'date': datetime(2026, 3, 24), 'freq_col': 10, 'remark_col': 12},
{'data_start': 81, 'data_end': 100, 'routing': 'LAX-MIA', 'date': datetime(2026, 3, 24), 'freq_col': 10, 'remark_col': 12},
]
特殊点:
- 无
+45K列,45KG 固定为 None - 价格列:col3=100KG, col4=300KG, col5=500KG, col6=1000KG
- 散托类型从 col0 文字判断:
托盘→托盘,散货→散货,托盘/散货→散货/托盘
十、Sheet 8 UC 规则
- DEST 在 col0(非 col1)
- Routing 在 col1
- 价格 col4-col8(标准位置)
- 频次 col9,备注 col11
- 逗号分隔多目的地:
ANF,ARI,IQQ,CCP
十一、全局航司列表
CARRIERS = {
'MU', 'CA', 'CK', 'CZ', 'ET', 'TK', 'K4', 'Y8', 'O3', 'KZ',
'CX', 'MH', 'GA', 'VN', 'CV', 'D0', 'QT', 'UC', 'JL', 'NH', 'HO', 'NZ', 'RH', '5Y',
'QF', 'KE'
}
⚠️ 添加新航司时:必须加入 CARRIERS 集合,否则 is_carrier_row() 无法识别。
十二、常见坑和修复记录
坑1:航司行跳过导致死循环
# ❌ 错误:i = k - 1 导致死循环
if is_carrier_row(data_row):
i = k - 1
# ✅ 正确:i = k 正常推进
if is_carrier_row(data_row):
i = k
break
坑2:CARRIERS 集合遗漏新航司
QF/KE 曾因不在 CARRIERS 集合中导致 Sheet 5 跳过。VN 也曾未收录(Sheet 10 新增越南航空)。
坑6:Sheet 配置航司列表未同步(0601新增)
症状:Sheet 9 的 CK 在 0601 批次已移除,但配置仍保留 规则:每批次必须对照源文件行数据,确认航司列表中每个航司确实存在;缺失的移除,新增的加入
坑3:生效日期只向后扫描
Sheet 5 的 MU Effective Date 在当前航司行,parse_effective_date 必须先在当前行查找。
坑4:生效日期过滤遗漏
必须在 build_row() 中统一过滤,早于 cutoff_date 的行返回 None。
坑5:int() 转换价格丢失小数
绝对禁止使用 int(),价格列必须保留原始 float。
十三、脚本模板
提取脚本模板位于项目:/Users/hantao/WorkBuddy/oone/extract_alllink.py
(实际使用时复制最新版本,更新源文件路径和 cutoff_date)
新批次时:
- 复制最新版本脚本
- 更新
file_path指向新源文件 - 更新
cutoff_date - 对照源文件修正 Sheet 配置
- 修正 Sheet 7 block 范围和日期
- 运行 → 验证 → 上传
十四、输出验证
from columns_24 import COL_24, validate_columns
df_result = pd.DataFrame(all_rows, columns=COL_24)
valid, msg = validate_columns(df_result.columns.tolist())
if not valid:
raise ValueError(f"列名校验失败: {msg}")
微信扫一扫