Auto-login Yunda and switch router to ready-guard polling

- Add yunda_login: probe the login page, fill credentials from
  config.yaml (yunda.username/password), submit; no-op if already
  logged in
- main_router: register per-site READY_SELECTORS and replace the
  blocking input() with a ready-guard poll loop; invoke Yunda
  auto-login up front; simplify site-init cleanup
- site_yunda: drop the custom frame probes in favor of native
  frame_locator("section iframe")
- Skip handover rows already marked 已绑定; abort the export harvest
  when no tasks were submitted
- Fix NameError from undefined username/password fallback

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-06-20 21:33:09 +08:00
parent e8b789e906
commit a67b64f8f8
2 changed files with 261 additions and 232 deletions

View File

@@ -16,7 +16,17 @@ SITES_CONFIG = {
"顺心": "https://sxne.sxjdfreight.com",
"百世": "https://v5.800best.com",
"中通": "https://ws.zto56.com/",
"韵达": "https://ky-sso.yunda56.com", # 预设韵达快运大运系统入口
"韵达": "https://ky-sso.yunda56.com",
}
# ====================================================================
# 🛡️ 网点特征注册表:定义每个网点登录成功、成功进入工作台的标志性控件
# ====================================================================
READY_SELECTORS = {
"顺心": 'h1:has-text("盟商门户网")',
"百世": 'h1[title="百世快运"]',
"中通": '.logo:has-text("网点版")',
"韵达": '.el-menu-item:has-text("首页")',
}
@@ -70,7 +80,7 @@ def task_process_undelivered_data(site_name="顺心"):
def run_multi_site_daemon():
"""多网点自动化主控引擎"""
"""多网点自动化主控引擎 (状态机卫语句驱动版)"""
# 1. 读取配置文件
debug_mode = False
@@ -99,25 +109,56 @@ def run_multi_site_daemon():
pages_map = {}
print("\n====================================================")
print("初始化阶段】正在构建多网点运行环境...")
print("唤醒阶段】正在构建多网点并行运行环境...")
print("====================================================")
for site_name, url in active_sites.items():
print(f">> 正在打开{site_name}】页面: {url}")
print(f">> 正在启动{site_name}】页面: {url}")
page = context.new_page()
page.goto(url)
pages_map[site_name] = page
page.wait_for_timeout(1000)
print("\n====================================================")
print("⚠️ 【等待人工介入】")
print("请在弹出的浏览器中,人工完成已开启网点的登录!")
print("【状态自检】启动前置智能接管机制...")
print("====================================================")
input(">> 登录全部完成后,请在此处按下【回车键】正式接管中控台...")
# 针对支持纯代码自动登录的站点,在此处前置注入登录事件
if "韵达" in pages_map:
try:
pages_map["韵达"].bring_to_front()
site_yunda.yunda_login(pages_map["韵达"])
except Exception as e:
print(f" ⚠️ 韵达前置自动登录模块发生波动: {e}")
# ====================================================================
# 🛡️ 就绪卫语句轮询器 (Ready Guard Polling)
# 无需死板的输入回车,全自动识别状态并无缝放行
# ====================================================================
ready_status = {site: False for site in active_sites.keys()}
print("\n>> 正在静默轮询全网点就绪状态 (自动免密/手工登录均可激活)...")
while not all(ready_status.values()):
for site_name, page in pages_map.items():
if not ready_status[site_name]:
try:
# 0.5秒轻量级探针,避免阻塞主循环
if page.locator(READY_SELECTORS[site_name]).is_visible(
timeout=500
):
ready_status[site_name] = True
print(f" 🎉 【{site_name}】探测到主页特征,状态已就绪!")
except Exception:
pass
pending_sites = [s for s, ready in ready_status.items() if not ready]
if pending_sites:
print(
f" ⏳ 等待以下网点登录验证: [{', '.join(pending_sites)}] ... (请在浏览器中操作)"
)
page.wait_for_timeout(3000) # 挂起 3 秒后执行下一轮盘点
print("\n====================================================")
print("系统接管】正在执行各网点就绪前初始化动作...")
print("接管阶段】所有活跃网点均已就绪,正在执行环境净化...")
print("====================================================")
# 顺心环境净化
@@ -125,78 +166,53 @@ def run_multi_site_daemon():
try:
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()
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 as e:
print(f" ⚠️ 【顺心】初始化波动: {e}")
except Exception:
pass # 环境可能很干净没有弹窗,无视报错
# 百世环境打地鼠
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(" 🎉 登录成功!系统已接管百世浏览器。")
bs_page.wait_for_timeout(2000)
for round_idx in range(5):
print(">> 正在处理【百世】阅读完毕与关闭按钮...")
for round_idx in range(4):
handled_any = False
try:
read_btns = bs_page.locator("button:has-text('阅读完毕')")
if read_btns.count() > 0:
for i in range(read_btns.count()):
if read_btns.nth(i).is_visible():
if read_btns.nth(i).is_visible(timeout=500):
read_btns.nth(i).click()
handled_any = True
except:
pass
try:
if bs_page.locator("button:has-text('关 闭')").is_visible():
if bs_page.locator("button:has-text('关 闭')").is_visible(
timeout=500
):
bs_page.locator("button:has-text('关 闭')").click()
handled_any = True
except:
pass
if not handled_any:
break
bs_page.wait_for_timeout(1000)
bs_page.wait_for_timeout(800)
print(" ✅ 【百世】界面净化完毕!")
except Exception as e:
print(f" ⚠️ 【百世】初始化异常: {e}")
except Exception:
pass
# 中通环境检测
if "中通" in pages_map:
try:
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}")
print(" ✅ 【中通】状态就绪!")
# 韵达环境检测
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}")
print(" ✅ 【韵达】工作区状态就绪!")
def is_site_ready(site_name):
if site_name not in pages_map: