# main_router.py import os import pandas as pd from playwright.sync_api import sync_playwright # 导入抽离出去的各个网点模块 import site_shunxin import site_baishi # 定义网点及对应的初始登录 URL SITES_CONFIG = { "顺心": "https://sxne.sxjdfreight.com", "百世": "https://v5.800best.com", } def task_process_undelivered_data(site_name="顺心"): """全局模块:应到未到异常件比对引擎 (支持动态网点前缀)""" print(f"\n▶ 开始执行【{site_name} - 应到未到数据处理】任务...") download_dir = os.path.join(os.getcwd(), "downloads") # 动态拼接带网点前缀的文件路径 expected_path = os.path.join(download_dir, f"{site_name}-应到货物数据.xlsx") actual_path = os.path.join(download_dir, f"{site_name}-实到货物数据.xlsx") output_path = os.path.join(download_dir, f"{site_name}-应到未到货物数据.xlsx") if not os.path.exists(expected_path): print(f"❌ 错误:找不到【{site_name}-应到货物数据】主文档:{expected_path}") return if not os.path.exists(actual_path): print(f"❌ 错误:找不到【{site_name}-实到货物数据】主文档:{actual_path}") return try: print(">> 正在载入本地 Excel 文档...") df_expected = pd.read_excel(expected_path) df_actual = pd.read_excel(actual_path) if "运单号" not in df_expected.columns or "运单号" not in df_actual.columns: print("❌ 核心资产校验失败:数据源中缺失【运单号】字段,请检查导出配置。") return print(">> 正在启动多维数据集比对引擎...") # Left Anti-Join:在应到中找出不存在于实到里的运单号 df_undelivered = df_expected[~df_expected["运单号"].isin(df_actual["运单号"])] target_columns = ["班次号", "交接单号", "运单号"] available_columns = [ col for col in target_columns if col in df_undelivered.columns ] df_output = df_undelivered[available_columns] print(f">> 筛选完毕!共捕获到异常【应到未到】货物数据: {len(df_output)} 条。") df_output.to_excel(output_path, index=False) print(f"====================================================") print(f" 🎉 异常比采取流完成!独立数据已安全输出。") print(f" 📁 成果归档路径: {output_path}") print(f"====================================================") except Exception as e: print(f"❌ 数据处理引擎在执行连接和输出时发生致命异常: {e}") def run_multi_site_daemon(): """多网点自动化主控引擎""" with sync_playwright() as p: browser = p.chromium.launch(headless=False) context = browser.new_context(viewport={"width": 1920, "height": 1080}) pages_map = {} print("\n====================================================") print("【初始化阶段】正在构建多网点运行环境...") print("====================================================") for site_name, url in SITES_CONFIG.items(): 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("====================================================") input(">> 登录全部完成后,请在此处按下【回车键】正式接管中控台...") print("\n====================================================") print("【系统接管】正在执行各网点就绪前初始化动作...") print("====================================================") # 顺心环境净化 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() sx_page.wait_for_timeout(1000) print(" ✅ 【顺心】弹窗清理完毕,状态就绪!") except Exception as e: print(f" ⚠️ 【顺心】初始化或弹窗清理异常 (如无弹窗可忽略): {e}") # 百世环境检测与“打地鼠”清理引擎 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) # 最多循环 5 轮,每次尝试点掉视野内的所有垃圾弹窗 for round_idx in range(5): handled_any = False # 1. 清理【阅读完毕】(可能叠加出现多个) 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(): read_btns.nth(i).click() bs_page.wait_for_timeout(500) handled_any = True print(" -> 已点击【阅读完毕】") except Exception: pass # 2. 清理【配置检查 -> 关 闭】 try: close_config = bs_page.locator("button:has-text('关 闭')") if close_config.is_visible(): close_config.click() bs_page.wait_for_timeout(500) handled_any = True print(" -> 已关闭【配置检查】") except Exception: pass # 3. 清理【通知提示】 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 print(" -> 已关闭【通知提示】") except Exception: pass # 4. 清理【广告】(捕获具有 close-circle 图标的 SVG) 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 print(" -> 已关闭【广告弹窗】") except Exception: pass # 如果这一轮没有任何可见的弹窗被处理,说明页面已经干净了,跳出循环 if not handled_any: break bs_page.wait_for_timeout(1000) print(" ✅ 【百世】界面净化完毕,状态就绪!") except Exception as e: print(f" ⚠️ 【百世】初始化异常: {e}") while True: print("\n====================================================") print(" 物流数据多端提取总枢纽 ") print("====================================================") print(" 模块一:【顺心】数据处理流") print(" [1] 执行 - 应到货物数据下载") print(" [2] 执行 - 实到货物数据下载") print(" [3] 执行 - 应到未到数据清洗比对 (本地运算)") print("-" * 52) print(" 模块二:【百世】数据处理流") print(" [4] 执行 - 一键提取应到未到异常数据") print("-" * 52) print(" [0] 退出系统") print("====================================================") choice = input("请输入任务编号并回车: ") try: if choice == "1": pages_map["顺心"].bring_to_front() site_shunxin.shunxin_expected_download(pages_map["顺心"]) elif choice == "2": pages_map["顺心"].bring_to_front() site_shunxin.shunxin_actual_download(pages_map["顺心"]) elif choice == "3": task_process_undelivered_data("顺心") elif choice == "4": pages_map["百世"].bring_to_front() site_baishi.baishi_download_undelivered_data(pages_map["百世"]) elif choice == "0": print("\n准备退出程序,释放浏览器资源...") break else: print("\n⚠️ 无效输入,请重新选一下。") except Exception as e: print(f"❌ 调度执行异常: {e}") browser.close() print("系统已安全关闭。") if __name__ == "__main__": run_multi_site_daemon()