diff --git a/.gitignore b/.gitignore index aa03247..1dcd263 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ downloads/ .env .env.local +# Local secrets / credentials +config.yaml + # Playwright .playwright/ ms-playwright/ diff --git a/config.example.yaml b/config.example.yaml new file mode 100644 index 0000000..d19f712 --- /dev/null +++ b/config.example.yaml @@ -0,0 +1,4 @@ +# config.example.yaml +# 复制本文件为 config.yaml 并填入真实凭据后使用 +baishi: + password: "YOUR_PASSWORD_HERE" diff --git a/main_router.py b/main_router.py index 6b8c999..201dfdd 100644 --- a/main_router.py +++ b/main_router.py @@ -16,7 +16,7 @@ SITES_CONFIG = { def task_process_undelivered_data(site_name="顺心"): - """全局模块:应到未到异常件比对引擎 (支持动态网点前缀)""" + """全局模块:应到未到异常件比对引擎 (本地离线比对)""" print(f"\n▶ 开始执行【{site_name} - 应到未到数据处理】任务...") download_dir = os.path.join(os.getcwd(), "downloads") @@ -118,27 +118,35 @@ def run_multi_site_daemon(): sx_page.get_by_role("button", name="不再询问").click() sx_page.wait_for_timeout(1000) print(" ✅ 【顺心】弹窗清理完毕,状态就绪!") - except Exception as e: - print(f" ⚠️ 【顺心】初始化或弹窗清理异常 (如无弹窗可忽略): {e}") + print(f" ⚠️ 【顺心】初始化异常 (无弹窗可忽略): {e}") - # 未来如果要加【百世】的弹窗清理,可以直接在这里依葫芦画瓢加上 - # try: - # bs_page = pages_map["百世"] - # bs_page.bring_to_front() - # ... + # 百世环境检测 + try: + bs_page = pages_map["百世"] + bs_page.bring_to_front() + print(">> 正在处理【百世】网点初始状态...") + + bs_page.wait_for_selector('h1[title="百世快运"]', timeout=30000) + print(" 🎉 登录成功!系统已接管百世浏览器。") + print(" ✅ 【百世】状态就绪!") + except Exception as e: + print(f" ⚠️ 【百世】初始化异常: {e}") while True: - print("\n==============================") - print(" 物流数据多端提取总枢纽 ") - print("==============================") - print("1. [顺心] - 执行【应到货物数据下载】") - print("2. [顺心] - 执行【实到货物数据下载】") - print("3. [百世] - 执行【应到货物数据下载】") - print("4. [百世] - 执行【实到货物数据下载】") - print("5. [全局] - 执行【应到未到数据清洗比对】") - print("0. 退出系统") - print("==============================") + print("\n====================================================") + print(" 物流数据多端提取总枢纽 ") + print("====================================================") + print(" 模块一:【顺心】数据处理流") + print(" [1] 执行 - 应到货物数据下载") + print(" [2] 执行 - 实到货物数据下载") + print(" [3] 执行 - 应到未到数据清洗比对 (本地运算)") + print("-" * 52) + print(" 模块二:【百世】数据处理流") + print(" [4] 执行 - 一键提取应到未到异常数据") + print("-" * 52) + print(" [0] 退出系统") + print("====================================================") choice = input("请输入任务编号并回车: ") @@ -150,16 +158,10 @@ def run_multi_site_daemon(): pages_map["顺心"].bring_to_front() site_shunxin.shunxin_actual_download(pages_map["顺心"]) elif choice == "3": - pages_map["百世"].bring_to_front() - site_baishi.baishi_expected_download(pages_map["百世"]) + task_process_undelivered_data("顺心") elif choice == "4": pages_map["百世"].bring_to_front() - site_baishi.baishi_actual_download(pages_map["百世"]) - elif choice == "5": - site_name = input("请输入要比对的网点名称 (默认: 顺心): ").strip() - if not site_name: - site_name = "顺心" - task_process_undelivered_data(site_name) + site_baishi.baishi_download_undelivered_data(pages_map["百世"]) elif choice == "0": print("\n准备退出程序,释放浏览器资源...") break @@ -168,7 +170,6 @@ def run_multi_site_daemon(): except Exception as e: print(f"❌ 调度执行异常: {e}") - # 退出循环后关闭浏览器 browser.close() print("系统已安全关闭。") diff --git a/site_baishi.py b/site_baishi.py index 016574d..4e8aed8 100644 --- a/site_baishi.py +++ b/site_baishi.py @@ -1,15 +1,82 @@ # site_baishi.py - -def baishi_expected_download(page): - """百世:应到货物数据下载""" - print("\n▶ 开始执行【百世 - 应到货物数据下载】任务...") - print("🚧 逻辑开发中 (pass)...") - pass +import os +import yaml +from playwright.sync_api import sync_playwright -def baishi_actual_download(page): - """百世:实到货物数据下载""" - print("\n▶ 开始执行【百世 - 实到货物数据下载】任务...") - print("🚧 逻辑开发中 (pass)...") - pass +def baishi_download_undelivered_data(page): + """百世:一键提取应到未到(当日未扫)数据""" + print("\n▶ 开始执行【百世 - 一键提取应到未到数据】任务...") + + download_dir = os.path.join(os.getcwd(), "downloads") + if not os.path.exists(download_dir): + os.makedirs(download_dir) + + try: + # 1. 导航与页面加载 + print(">> 正在进入【扫描综合查询】界面...") + page.locator("div.nav-level1", has_text="基础服务").click() + page.locator("li a", has_text="扫描综合查询").click() + + # 验证表格主界面加载完毕 + page.get_by_role("tab", name="实时扫描率").wait_for(state="visible") + print("✅ 扫描综合查询界面加载完毕") + + # 2. 精准定位并点击【到/接件扫描 -> 当日 -> 未扫】的数字控件 + print(">> 正在解析表格,提取当日到件未扫明细...") + # 表头结构复杂,精准定位第一行数据的第 13 列(索引 12) + target_cell = page.locator(".ant-table-tbody > tr").first.locator("td").nth(12) + target_cell.locator("a").click() + + # 等待下方弹出的明细表格区域加载完毕 + detail_section = page.locator(".m-query-all-scanRateDetail") + detail_section.wait_for(state="visible") + page.wait_for_timeout(1000) + + # 3. 触发导出设置模态框 + print(">> 正在呼出导出配置面板...") + # 锁定在明细区域内的导出按钮,防止误点主表的导出 + detail_section.locator(".export-wrap a[title='导出']").click() + + # 验证模态框弹出 + page.locator(".ant-modal-title", has_text="导出设置").wait_for(state="visible") + + # 4. 加载 YAML 配置并输入密码 + print(">> 正在读取本地配置文件并进行授权验证...") + password = "" + try: + with open("config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + password = config.get("baishi", {}).get("password", "") + except Exception as e: + print(f" ⚠️ 读取 config.yaml 失败,请确保文件存在且格式正确: {e}") + return + + page.get_by_placeholder("请输入登录密码").fill(password) + + # 5. 执行最终下载 + print(">> 验证就绪,正在触发下载流...") + with page.expect_download() as download_info: + # 精准锁定模态框底部的“导 出”大按钮 + page.locator(".ant-modal-footer").get_by_role( + "button", name="导 出" + ).click() + + download = download_info.value + save_path = os.path.join(download_dir, "百世-应到未到货物数据.xlsx") + + # 如果之前已经有同名文件,覆盖保存 + if os.path.exists(save_path): + os.remove(save_path) + + download.save_as(save_path) + print(f"====================================================") + print(f" 🎉 恭喜!数据提取成功!") + print(f" ⬇️ 文件已落盘: {save_path}") + print(f"====================================================") + + print("\n🎉 【百世 - 应到未到数据提取】全流程测试完毕!") + + except Exception as e: + print(f"\n❌ 任务执行过程中发生异常: {e}")