顺心站点支持双账号(双归属地)下载与融合

- 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:
Misaka
2026-07-15 22:36:58 +08:00
parent 75abbdf14c
commit 55e9e9e931
4 changed files with 230 additions and 55 deletions

View File

@@ -125,18 +125,38 @@ def run_automation_test(pages_map):
},
}
# 构建测试计划:[(站点, 流程中文名, 流程函数), ...]
# 构建测试计划:[(站点, 流程中文名, 流程函数, 绑定page, 归属标签), ...]
# 顺心为双账号:两个 page 各自读归属地后跑一遍交叉序列;其余站点单 page。
plan = []
for site_name, flows in flow_table.items():
if site_name == "顺心":
if "顺心" not in pages_map:
continue
for sx_idx, sx_page in enumerate(pages_map["顺心"], start=1):
try:
tag = site_shunxin.shunxin_belonging(sx_page)
except Exception:
tag = f"账号{sx_idx}" # 读不到归属地时用序号占位,不阻断测试
for flow_key in CROSS_TEST_SEQUENCE:
label, func = flows[flow_key]
plan.append((f"顺心·{tag}", label, func, sx_page, tag))
continue
if site_name not in pages_map:
continue
bound_page = pages_map[site_name]
for flow_key in CROSS_TEST_SEQUENCE:
label, func = flows[flow_key]
plan.append((site_name, label, func))
plan.append((site_name, label, func, bound_page, ""))
# 百世:单流程,跑一次即可
if "百世" in pages_map:
plan.append(
("百世", "应到未到", site_baishi.baishi_download_undelivered_data_impl)
(
"百世",
"应到未到",
site_baishi.baishi_download_undelivered_data_impl,
pages_map["百世"],
"",
)
)
if not plan:
@@ -150,7 +170,7 @@ def run_automation_test(pages_map):
print("====================================================")
results = [] # [(站点, 流程, 状态, 耗时秒, 错误信息)]
for idx, (site_name, label, func) in enumerate(plan, start=1):
for idx, (site_name, label, func, bound_page, out_tag) in enumerate(plan, start=1):
print("\n----------------------------------------------------")
print(f"[步骤 {idx}/{total}] 站点【{site_name}】流程【{label}")
print("----------------------------------------------------")
@@ -162,9 +182,9 @@ def run_automation_test(pages_map):
# 安能Electron 应用,无 Playwright page函数不收 page 参数
ret = func()
else:
page = pages_map[site_name]
page.bring_to_front()
ret = func(page)
bound_page.bring_to_front()
# 顺心 _impl 带 out_tag归属地其余站点 _impl 仅收 page
ret = func(bound_page, out_tag=out_tag) if out_tag else func(bound_page)
if ret is False:
status = "FAIL"
err = "流程返回失败状态"
@@ -252,10 +272,21 @@ def run_multi_site_daemon():
print("====================================================")
for site_name, url in active_sites.items():
print(f">> 正在启动【{site_name}】页面: {url}")
page = context.new_page()
page.goto(url)
pages_map[site_name] = page
if site_name == "顺心":
# 顺心:两个归属地账号在同一窗口各开一个标签页(顺心站点支持
# 同浏览器双账号并存pages_map["顺心"] 存为 page 列表。
sx_pages = []
for acct in range(1, 3):
print(f">> 正在启动【顺心】账号{acct}标签页: {url}")
sx_page = context.new_page()
sx_page.goto(url)
sx_pages.append(sx_page)
pages_map["顺心"] = sx_pages
else:
print(f">> 正在启动【{site_name}】页面: {url}")
page = context.new_page()
page.goto(url)
pages_map[site_name] = page
# 安能:以调试模式启动 Electron 应用(非 Playwright 网页)
anneng_proc = None
@@ -296,6 +327,12 @@ def run_multi_site_daemon():
if site_name == "安能":
# 安能走 CDP 判断主页是否就绪(连不上返回 False不抛异常
ok = site_anneng.anneng_ready()
elif site_name == "顺心":
# 顺心双账号:两个 page 都进主页才算就绪
ok = all(
pg.locator(READY_SELECTORS["顺心"]).is_visible(timeout=500)
for pg in pages_map["顺心"]
)
else:
# 0.5 秒轻量探测,避免阻塞主循环
ok = (
@@ -321,20 +358,20 @@ def run_multi_site_daemon():
print("【准备】所有站点已就绪,正在清理初始弹窗...")
print("====================================================")
# 顺心:处理初始弹窗
# 顺心:处理初始弹窗(双账号两个 page 各处理一遍)
if "顺心" in pages_map:
try:
sx_page = pages_map["顺心"]
sx_page.bring_to_front()
print(">> 正在处理【顺心】弹窗与遮罩...")
sx_page.locator("a").nth(4).click(timeout=2000)
sx_page.wait_for_timeout(500)
sx_page.get_by_role("button", name="Close").click(timeout=2000)
sx_page.wait_for_timeout(500)
sx_page.get_by_role("button", name="不再询问").click(timeout=2000)
print(" ✅ 【顺心】初始弹窗处理完成。")
except Exception:
pass # 环境可能很干净没有弹窗,无视报错
for acct, sx_page in enumerate(pages_map["顺心"], start=1):
try:
sx_page.bring_to_front()
print(f">> 正在处理【顺心】账号{acct}弹窗与遮罩...")
sx_page.locator("a").nth(4).click(timeout=2000)
sx_page.wait_for_timeout(500)
sx_page.get_by_role("button", name="Close").click(timeout=2000)
sx_page.wait_for_timeout(500)
sx_page.get_by_role("button", name="不再询问").click(timeout=2000)
print(f" ✅ 【顺心】账号{acct}初始弹窗处理完成。")
except Exception:
pass # 环境可能很干净没有弹窗,无视报错
# 百世:循环关闭初始弹窗
if "百世" in pages_map:
@@ -423,13 +460,9 @@ def run_multi_site_daemon():
try:
if choice == "1" and is_site_ready("顺心"):
page = pages_map["顺心"]
page.bring_to_front()
site_shunxin.shunxin_expected_download(page)
site_shunxin.shunxin_expected_download(pages_map["顺心"])
elif choice == "2" and is_site_ready("顺心"):
page = pages_map["顺心"]
page.bring_to_front()
site_shunxin.shunxin_actual_download(page)
site_shunxin.shunxin_actual_download(pages_map["顺心"])
elif choice == "3" and is_site_ready("百世"):
page = pages_map["百世"]
page.bring_to_front()