Integrate Yunda site module and rewire router menu numbering

- Add site_yunda.py: Yunda expected-arrival download (进站交接单查询)
  with Layui date-range setup, row double-click export, a retry state
  machine for the offline-export dialog, and a shared poll/download/
  merge engine; actual-arrival is a placeholder
- Wire Yunda into main_router: site URL, login detection, menu items,
  and read yunda.query_days from config.yaml
- Rework the hub menu: drop the standalone Shunxin local-compare entry,
  renumber modules (百世 3, 中通 4/5, 韵达 6/7), keep global compare [9]
- Streamline site-init cleanup and log wording

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-06-20 18:20:46 +08:00
parent eb9bbe9b70
commit 194fbc7cda
2 changed files with 471 additions and 66 deletions

View File

@@ -9,12 +9,14 @@ from playwright.sync_api import sync_playwright
import site_shunxin
import site_baishi
import site_zto
import site_yunda
# 定义网点及对应的初始登录 URL
SITES_CONFIG = {
"顺心": "https://sxne.sxjdfreight.com",
"百世": "https://v5.800best.com",
"中通": "https://ws.zto56.com/",
"韵达": "https://ky-sso.yunda56.com", # 预设韵达快运大运系统入口
}
@@ -82,10 +84,10 @@ def run_multi_site_daemon():
except Exception as e:
print(f"⚠️ 读取 config.yaml 异常,将使用全量模式启动: {e}")
# 动态确定需要启动的站点
# 动态确定需要挂载启动的网页
active_sites = {}
if debug_mode and debug_target in SITES_CONFIG:
print(f"\n🛠️ 【调试模式激活】当前仅挂载并启目标站点: [{debug_target}]")
print(f"\n🛠️ 【调试模式激活】当前中控台仅挂载并启目标站点: [{debug_target}]")
active_sites = {debug_target: SITES_CONFIG[debug_target]}
else:
active_sites = SITES_CONFIG
@@ -109,7 +111,7 @@ def run_multi_site_daemon():
print("\n====================================================")
print("⚠️ 【等待人工介入】")
print("请在弹出的浏览器中,人工完成已加载网点的登录!")
print("请在弹出的浏览器中,人工完成已开启网点的登录!")
print("====================================================")
input(">> 登录全部完成后,请在此处按下【回车键】正式接管中控台...")
@@ -124,32 +126,26 @@ def run_multi_site_daemon():
sx_page = pages_map["顺心"]
sx_page.bring_to_front()
print(">> 正在处理【顺心】网点初始状态...")
sx_page.wait_for_selector('h1:has-text("盟商门户网")', timeout=30000)
print(" 🎉 登录成功!系统已接管顺心浏览器。")
sx_page.wait_for_timeout(1000)
sx_page.locator("a").nth(4).click()
sx_page.wait_for_timeout(1000)
sx_page.get_by_role("button", name="Close").click()
sx_page.wait_for_timeout(1000)
sx_page.get_by_role("button", name="不再询问").click()
sx_page.wait_for_timeout(1000)
print(" ✅ 【顺心】弹窗清理完毕,状态就绪!")
print(" ✅ 【顺心】环境准备就绪!")
except Exception as e:
print(f" ⚠️ 【顺心】初始化或弹窗清理异常 (如无弹窗可忽略): {e}")
print(f" ⚠️ 【顺心】初始化波动: {e}")
# 百世环境检测与“打地鼠”清理引擎
# 百世环境打地鼠
if "百世" in pages_map:
try:
bs_page = pages_map["百世"]
bs_page.bring_to_front()
print("\n>> 正在处理【百世】网点初始状态...")
bs_page.wait_for_selector('h1[title="百世快运"]', timeout=30000)
print(" 🎉 登录成功!系统已接管百世浏览器。")
print(" >> 启动无序弹窗清理机制 (打地鼠模式)...")
bs_page.wait_for_timeout(2000)
for round_idx in range(5):
@@ -160,45 +156,19 @@ def run_multi_site_daemon():
for i in range(read_btns.count()):
if read_btns.nth(i).is_visible():
read_btns.nth(i).click()
bs_page.wait_for_timeout(500)
handled_any = True
except Exception:
except:
pass
try:
close_config = bs_page.locator("button:has-text('关 闭')")
if close_config.is_visible():
close_config.click()
bs_page.wait_for_timeout(500)
if bs_page.locator("button:has-text('关 闭')").is_visible():
bs_page.locator("button:has-text('关 闭')").click()
handled_any = True
except Exception:
except:
pass
try:
notice_close = bs_page.locator(
"a.ant-notification-notice-close"
)
if notice_close.is_visible():
notice_close.click()
bs_page.wait_for_timeout(500)
handled_any = True
except Exception:
pass
try:
ad_close = bs_page.locator("svg[data-icon='close-circle']")
if ad_close.is_visible():
ad_close.click()
bs_page.wait_for_timeout(500)
handled_any = True
except Exception:
pass
if not handled_any:
break
bs_page.wait_for_timeout(1000)
print(" ✅ 【百世】界面净化完毕,状态就绪!")
print(" ✅ 【百世】界面净化完毕!")
except Exception as e:
print(f" ⚠️ 【百世】初始化异常: {e}")
@@ -208,19 +178,29 @@ def run_multi_site_daemon():
zto_page = pages_map["中通"]
zto_page.bring_to_front()
print("\n>> 正在处理【中通】网点初始状态...")
zto_page.wait_for_selector('.logo:has-text("网点版")', timeout=30000)
print(" 🎉 登录成功!系统已接管中通浏览器。")
print(" ✅ 【中通】状态就绪!")
except Exception as e:
print(f" ⚠️ 【中通】初始化异常: {e}")
# 路由拦截器
# 韵达环境检测
if "韵达" in pages_map:
try:
yd_page = pages_map["韵达"]
yd_page.bring_to_front()
print("\n>> 正在处理【韵达】网点初始状态...")
yd_page.wait_for_selector(
'.el-menu-item:has-text("首页")', timeout=30000
)
print(" 🎉 登录成功!系统已接管韵达快运浏览器。")
print(" ✅ 【韵达】工作区状态就绪!")
except Exception as e:
print(f" ⚠️ 【韵达】初始化异常: {e}")
def is_site_ready(site_name):
if site_name not in pages_map:
print(
f"\n🚫 【拒绝执行】当前处于单站点调试模式,或【{site_name}】未加载,无法执行此操作!"
)
print(f"\n🚫 【安全拦截】当前处于局部调试,[{site_name}] 未挂载加载!")
return False
return True
@@ -228,22 +208,25 @@ def run_multi_site_daemon():
print("\n====================================================")
print(" 物流数据多端提取总枢纽 ")
if debug_mode:
print(f" [ 🛠️ 调试模式已激活 : {debug_target} ]")
print(f" [ 🛠️ 调试模式独立聚焦 : {debug_target} ]")
print("====================================================")
print(" 模块一:【顺心】数据处理流")
print(" [1] 执行 - 应到货物数据下载")
print(" [2] 执行 - 实到货物数据下载")
print(" [3] 执行 - 应到未到数据清洗比对 (本地运算)")
print("-" * 52)
print(" 模块二:【百世】数据处理流")
print(" [4] 执行 - 一键提取应到未到异常数据")
print(" [3] 执行 - 一键提取应到未到异常数据")
print("-" * 52)
print(" 模块三:【中通】数据处理流")
print(" [5] 执行 - 应到货物数据下载")
print(" [6] 执行 - 实到货物数据下载")
print(" [4] 执行 - 应到货物数据下载")
print(" [5] 执行 - 实到货物数据下载")
print("-" * 52)
print(" 全局数据引擎")
print(" [9] 执行 - 离线异常数据清洗比对 (Left Anti-Join)")
print(" 模块四:【韵达】数据处理流")
print(" [6] 执行 - 应到货物数据下载")
print(" [7] 执行 - 实到货物数据下载 (待开发)")
print("-" * 52)
print(" 全局离线数据引擎")
print(" [9] 执行 - 异常数据清洗比对 (Left Anti-Join)")
print("-" * 52)
print(" [0] 退出系统")
print("====================================================")
@@ -257,33 +240,39 @@ def run_multi_site_daemon():
elif choice == "2" and is_site_ready("顺心"):
pages_map["顺心"].bring_to_front()
site_shunxin.shunxin_actual_download(pages_map["顺心"])
elif choice == "3" and is_site_ready("顺心"):
task_process_undelivered_data("顺心")
elif choice == "4" and is_site_ready("百世"):
elif choice == "3" and is_site_ready("百世"):
pages_map["百世"].bring_to_front()
site_baishi.baishi_download_undelivered_data(pages_map["百世"])
elif choice == "5" and is_site_ready("中通"):
elif choice == "4" and is_site_ready("中通"):
pages_map["中通"].bring_to_front()
site_zto.zto_expected_download(pages_map["中通"])
elif choice == "6" and is_site_ready("中通"):
elif choice == "5" and is_site_ready("中通"):
pages_map["中通"].bring_to_front()
site_zto.zto_actual_download(pages_map["中通"])
elif choice == "6" and is_site_ready("韵达"):
pages_map["韵达"].bring_to_front()
site_yunda.yunda_expected_download(pages_map["韵达"])
elif choice == "7" and is_site_ready("韵达"):
pages_map["韵达"].bring_to_front()
site_yunda.yunda_actual_download(pages_map["韵达"])
elif choice == "9":
site_name = input("请输入要比对的网点名称 (如 顺心/中通): ").strip()
site_name = input(
"请输入要比对的网点名称 (如 顺心/中通/韵达): "
).strip()
if not site_name:
site_name = "顺心"
task_process_undelivered_data(site_name)
elif choice == "0":
print("\n准备退出程序,释放浏览器资源...")
print("\n正在释放浏览器并安全登出系统...")
break
else:
if choice not in ["1", "2", "3", "4", "5", "6", "9", "0"]:
print("\n⚠️ 无效输入,请重新选一下")
if choice not in ["1", "2", "3", "4", "5", "6", "7", "9", "0"]:
print("\n⚠️ 无效输入,请查证后回车")
except Exception as e:
print(f"❌ 调度执行异常: {e}")
print(f"❌ 调度枢纽异常: {e}")
browser.close()
print("系统已安全关闭")
print("中控守护进程安全退出")
if __name__ == "__main__":