顺心站点支持双账号(双归属地)下载与融合
- main_router: 顺心在同一窗口开两个标签页登录两个归属地账号;就绪轮询、 初始弹窗、菜单 [1][2]、自动化测试均改为按 page 列表处理 - site_shunxin: download 入口改为接收 page 列表;新增 shunxin_belonging 读归属地、shunxin_merge_final 融合两账号数据;impl 加 out_tag 参数化 各账号产物文件名;两账号同归属地时去重校验中止以防数据翻倍 - expected_undelivered: 零改动(融合后产物仍为同名文件) - 更新 CLAUDE.md / README.md 文档说明 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
161
site_shunxin.py
161
site_shunxin.py
@@ -71,19 +71,109 @@ def _close_tab(page, tab_name):
|
||||
print(f" ⚠️ 关闭标签页【{tab_name.strip()}】时出错: {e}")
|
||||
|
||||
|
||||
def shunxin_expected_download(page):
|
||||
"""顺心:应到货物数据下载(内部含异常兜底重试,路由层无感)。"""
|
||||
def _sanitize_for_filename(name):
|
||||
"""剔除 Windows 文件名非法字符,避免归属地名含特殊字符导致落盘失败。"""
|
||||
return re.sub(r'[\\/:*?"<>|]', "", str(name)).strip()
|
||||
|
||||
return with_retry(
|
||||
"顺心",
|
||||
"应到",
|
||||
lambda: shunxin_expected_download_impl(page),
|
||||
lambda: shunxin_reset(page),
|
||||
|
||||
def shunxin_belonging(page):
|
||||
"""读取顺心当前账号的归属网点名(仅在首页可见,须在导航离开首页前调用)。
|
||||
|
||||
取首页「切换网点」下拉框选中项的 title(形如「【SX】重庆巴南龙海大道店」),
|
||||
去掉【XX】前缀得到归属地(如「重庆巴南龙海大道店」),并做文件名安全处理。
|
||||
读取失败时抛异常,交由上层处理。
|
||||
"""
|
||||
item = page.locator(".site___3o7nH .ant-select-selection-item").first
|
||||
title = (item.get_attribute("title") or item.inner_text() or "").strip()
|
||||
if not title:
|
||||
raise RuntimeError("未能读取顺心归属网点(首页「切换网点」控件为空)")
|
||||
tag = re.sub(r"^【[^】]*】", "", title).strip() or title
|
||||
return _sanitize_for_filename(tag)
|
||||
|
||||
|
||||
def shunxin_merge_final(kind, tags):
|
||||
"""把各归属地的中间产物融合成统一的「顺心-{kind}货物数据.xlsx」。
|
||||
|
||||
kind ∈ {"应到","实到"};tags 为各账号归属地列表。逐个读取
|
||||
「顺心-{tag}-{kind}货物数据.xlsx」(缺失则跳过,容错空数据账号),pd.concat
|
||||
后写出统一文件,并删除中间带 tag 的文件;全部缺失则仅提示、不产出。
|
||||
"""
|
||||
final_name = f"顺心-{kind}货物数据.xlsx"
|
||||
final_path = os.path.join(DOWNLOAD_DIR, final_name)
|
||||
|
||||
frames = []
|
||||
mid_paths = []
|
||||
for tag in tags:
|
||||
mid_name = f"顺心-{tag}-{kind}货物数据.xlsx"
|
||||
mid_path = os.path.join(DOWNLOAD_DIR, mid_name)
|
||||
if not os.path.exists(mid_path):
|
||||
print(f" ℹ️ 归属【{tag}】无{kind}中间文件(可能本次无数据),跳过。")
|
||||
continue
|
||||
mid_paths.append(mid_path)
|
||||
try:
|
||||
df = pd.read_excel(mid_path, dtype=str)
|
||||
if not df.empty:
|
||||
frames.append(df)
|
||||
except Exception as e:
|
||||
print(f" ⚠️ 读取中间文件 {mid_name} 失败: {e}")
|
||||
|
||||
if not frames:
|
||||
print(f">> ⚠️ 所有归属地均无{kind}数据,未生成 {final_name}。")
|
||||
return
|
||||
|
||||
combined = pd.concat(frames, ignore_index=True)
|
||||
combined.to_excel(final_path, index=False)
|
||||
print("====================================================")
|
||||
print(
|
||||
f" {kind}数据融合完成(共 {len(combined)} 行),输出: downloads/{final_name}"
|
||||
)
|
||||
print("====================================================")
|
||||
|
||||
for mid_path in mid_paths:
|
||||
try:
|
||||
os.remove(mid_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def shunxin_expected_download_impl(page):
|
||||
"""顺心:应到货物数据下载(单次执行,无重试;供自动化测试探测原始结果用)。"""
|
||||
def shunxin_expected_download(pages):
|
||||
"""顺心:应到货物数据下载(双账号/双归属地,内部含异常兜底重试与数据融合)。
|
||||
|
||||
pages 为该站点的 page 列表(双账号在同一窗口的各一个标签页)。
|
||||
先在首页读取各账号归属地并去重校验(两账号登同一归属地则中止,防数据翻倍),
|
||||
再顺序对各账号跑一遍下载(impl 用归属地作输出文件后缀),最后融合成统一的
|
||||
「顺心-应到货物数据.xlsx」。路由层只需传入 page 列表,对双账号无感。
|
||||
"""
|
||||
tags = []
|
||||
for idx, pg in enumerate(pages, start=1):
|
||||
tag = shunxin_belonging(pg)
|
||||
print(f">> 【顺心】账号{idx} 归属网点:{tag}")
|
||||
tags.append(tag)
|
||||
|
||||
if len(set(tags)) != len(tags):
|
||||
raise RuntimeError(
|
||||
f"顺心两个账号归属地相同({tags}),疑似登录了同一账号,已中止以防数据翻倍。"
|
||||
)
|
||||
|
||||
for idx, (pg, tag) in enumerate(zip(pages, tags), start=1):
|
||||
pg.bring_to_front()
|
||||
print(f"\n========== 顺心 · 账号{idx}({tag})应到数据下载 ==========")
|
||||
with_retry(
|
||||
f"顺心-{tag}",
|
||||
"应到",
|
||||
lambda p=pg, t=tag: shunxin_expected_download_impl(p, out_tag=t),
|
||||
lambda p=pg: shunxin_reset(p),
|
||||
)
|
||||
|
||||
shunxin_merge_final("应到", tags)
|
||||
|
||||
|
||||
def shunxin_expected_download_impl(page, out_tag=""):
|
||||
"""顺心:应到货物数据下载(单次执行,无重试;供自动化测试探测原始结果用)。
|
||||
|
||||
out_tag 为归属地标签时,合并产物命名为「顺心-{out_tag}-应到货物数据.xlsx」,
|
||||
作为双账号融合前的各账号中间文件;为空时退化为「顺心-应到货物数据.xlsx」。
|
||||
"""
|
||||
print("\n▶ 开始执行【顺心 - 应到货物数据下载】任务...")
|
||||
|
||||
# 初始化并创建下载目录
|
||||
@@ -344,7 +434,10 @@ def shunxin_expected_download_impl(page):
|
||||
|
||||
if all_data_frames:
|
||||
combined_df = pd.concat(all_data_frames, ignore_index=True)
|
||||
final_output_path = os.path.join(download_dir, "顺心-应到货物数据.xlsx")
|
||||
suffix = f"-{out_tag}" if out_tag else ""
|
||||
final_output_path = os.path.join(
|
||||
download_dir, f"顺心{suffix}-应到货物数据.xlsx"
|
||||
)
|
||||
combined_df.to_excel(final_output_path, index=False)
|
||||
print(f"====================================================")
|
||||
print(f" 合并完成,输出文件: {final_output_path}")
|
||||
@@ -364,19 +457,42 @@ def shunxin_expected_download_impl(page):
|
||||
return False
|
||||
|
||||
|
||||
def shunxin_actual_download(page):
|
||||
"""顺心:实到货物数据下载(内部含异常兜底重试,路由层无感)。"""
|
||||
def shunxin_actual_download(pages):
|
||||
"""顺心:实到货物数据下载(双账号/双归属地,内部含异常兜底重试与数据融合)。
|
||||
|
||||
return with_retry(
|
||||
"顺心",
|
||||
"实到",
|
||||
lambda: shunxin_actual_download_impl(page),
|
||||
lambda: shunxin_reset(page),
|
||||
)
|
||||
与 shunxin_expected_download 同构:读归属地 → 去重校验 → 顺序各账号下载 →
|
||||
融合成统一的「顺心-实到货物数据.xlsx」。
|
||||
"""
|
||||
tags = []
|
||||
for idx, pg in enumerate(pages, start=1):
|
||||
tag = shunxin_belonging(pg)
|
||||
print(f">> 【顺心】账号{idx} 归属网点:{tag}")
|
||||
tags.append(tag)
|
||||
|
||||
if len(set(tags)) != len(tags):
|
||||
raise RuntimeError(
|
||||
f"顺心两个账号归属地相同({tags}),疑似登录了同一账号,已中止以防数据翻倍。"
|
||||
)
|
||||
|
||||
for idx, (pg, tag) in enumerate(zip(pages, tags), start=1):
|
||||
pg.bring_to_front()
|
||||
print(f"\n========== 顺心 · 账号{idx}({tag})实到数据下载 ==========")
|
||||
with_retry(
|
||||
f"顺心-{tag}",
|
||||
"实到",
|
||||
lambda p=pg, t=tag: shunxin_actual_download_impl(p, out_tag=t),
|
||||
lambda p=pg: shunxin_reset(p),
|
||||
)
|
||||
|
||||
shunxin_merge_final("实到", tags)
|
||||
|
||||
|
||||
def shunxin_actual_download_impl(page):
|
||||
"""顺心:实到货物数据下载(单次执行,无重试;供自动化测试探测原始结果用)。"""
|
||||
def shunxin_actual_download_impl(page, out_tag=""):
|
||||
"""顺心:实到货物数据下载(单次执行,无重试;供自动化测试探测原始结果用)。
|
||||
|
||||
out_tag 为归属地标签时,合并产物命名为「顺心-{out_tag}-实到货物数据.xlsx」,
|
||||
作为双账号融合前的各账号中间文件;为空时退化为「顺心-实到货物数据.xlsx」。
|
||||
"""
|
||||
print("\n▶ 开始执行【顺心 - 实到货物数据下载】任务...")
|
||||
|
||||
download_dir = DOWNLOAD_DIR
|
||||
@@ -608,7 +724,10 @@ def shunxin_actual_download_impl(page):
|
||||
|
||||
if all_data_frames:
|
||||
combined_df = pd.concat(all_data_frames, ignore_index=True)
|
||||
final_output_path = os.path.join(download_dir, "顺心-实到货物数据.xlsx")
|
||||
suffix = f"-{out_tag}" if out_tag else ""
|
||||
final_output_path = os.path.join(
|
||||
download_dir, f"顺心{suffix}-实到货物数据.xlsx"
|
||||
)
|
||||
combined_df.to_excel(final_output_path, index=False)
|
||||
print(f"====================================================")
|
||||
print(f" 合并完成,输出文件: {final_output_path}")
|
||||
|
||||
Reference in New Issue
Block a user