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 上传可选**。claw-lite 没有 `upload_wps` 或上传失败时,不得挡住 `out/rate.xlsx`。
三、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, 1) # ← 每批次修改,0706批次=05-01
if effective_date < cutoff_date:
return None # 跳过旧价格
⚠️ cutoff_date 设置原则:
- 一般设为2个月前左右,保留近期有效价格
- 0706批次:2026-05-01(保留5月+,过滤4月及更早)
- 0622批次:2026-06-14
- 过滤过激会导致部分航司(如 CX/GA/VN/KZ/RH)丢失,需根据源文件实际日期分布调整
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, 6, 27), 'freq_col': None, 'remark_col': 12},
{'data_start': 45, 'data_end': 76, 'routing': 'LAX', 'date': datetime(2026, 6, 27), 'freq_col': 10, 'remark_col': 12},
{'data_start': 81, 'data_end': 100, 'routing': 'LAX-MIA', 'date': datetime(2026, 6, 27), 'freq_col': 10, 'remark_col': 12},
]
特殊点:
- 无 +45K 列,45KG 固定为 None
- 价格列:col3=100KG, col4=300KG, col5=500KG, col6=1000KG
- 散托类型从 col0 文字判断:托盘→托盘, 散货→散货, 托盘/散货→散货/托盘
- ⚠️ 坑7(0706修复):Block 1 表头只有 航班号(col11) 没有 航班(频次) 列,freq_col 必须设为 None;Block 2&3 有 航班(col10) 和 航班号(col11)。旧脚本误将 block1 的 col11(航班号) 当频次使用。
- ⚠️ Block 2&3 可能无价格:0706 批次 block2&3 全部价格为 /,产出 0 行。属正常情况。
十、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。
十三、脚本模板
提取脚本模板位于项目:workspace/templates/alllink/extract_alllink_0817.py
脚本必须从环境变量 CLAW_SRC / CLAW_OUT 或 job 相对路径读写,禁止写本机绝对路径。
新批次时:
1. 复制最新版本脚本
2. 更新 file_path 指向新源文件
3. 更新 cutoff_date
4. 对照源文件修正 Sheet 配置
5. 修正 Sheet 7 block 范围和日期
6. 运行 → 验证 → 上传
十四、输出验证
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}")