From bb9348d12b98002f8b13053876c0e74ce11b6f89 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Fri, 16 Jan 2026 15:20:05 +0800 Subject: [PATCH] Refactor DiscreteMaterialPlanExtractor to use logout function from auth module and update headless mode in main script --- main.py | 2 +- record.py | 2 +- utils/auth.py | 129 ++++++++++++++++++++++++++++++ utils/离散备料计划维护数据提取.py | 36 +-------- 4 files changed, 133 insertions(+), 36 deletions(-) create mode 100644 utils/auth.py diff --git a/main.py b/main.py index 6d2859f..c8224e0 100644 --- a/main.py +++ b/main.py @@ -10,7 +10,7 @@ def main(): extractor = DiscreteMaterialPlanExtractor( username="BLDpengqiangqiang", password="Cqbld123456.", - headless=False, + headless=True, verbose=True ) diff --git a/record.py b/record.py index 4c2be77..99d3e3f 100644 --- a/record.py +++ b/record.py @@ -1,7 +1,7 @@ import re import time from playwright.sync_api import Playwright, sync_playwright, expect, TimeoutError as PWTimeoutError -from login import login +from utils.auth import login def click_button_until_disappear(frame, button_name="保存提交", interval=5, max_attempts=None, max_duration=None): """ diff --git a/utils/auth.py b/utils/auth.py new file mode 100644 index 0000000..0b05f12 --- /dev/null +++ b/utils/auth.py @@ -0,0 +1,129 @@ +""" +认证模块 - 负责用友BIP系统的登录和退出操作 +""" +from playwright.sync_api import Playwright, Browser, BrowserContext, Page, Frame + + +def login( + playwright: Playwright, + username: str, + password: str, + url: str = "https://68.11.34.30:8082/yonbip/resources/uap/rbac/login/main/index.html", + headless: bool = False, + ignore_https_errors: bool = True, + verbose: bool = True +) -> tuple[Browser, BrowserContext, Page, Frame]: + """ + 登录用友BIP系统 + + 参数: + playwright: Playwright实例 + username: 用户名 + password: 密码 + url: 登录页面URL + headless: 是否使用无头模式 + ignore_https_errors: 是否忽略HTTPS错误 + verbose: 是否打印详细日志 + + 返回: + tuple: (browser, context, page, main_frame) + - browser: 浏览器实例 + - context: 浏览器上下文 + - page: 页面对象 + - main_frame: 登录后的主iframe (forwardFrame) + """ + import time + + # 启动浏览器 + browser = playwright.chromium.launch(headless=headless) + + # 创建上下文 + context = browser.new_context(ignore_https_errors=ignore_https_errors) + + # 创建页面 + page = context.new_page() + + # 导航到登录页面 + page.goto(url) + + # 提取主 iframe (forwardFrame) + main_frame = page.locator("#forwardFrame").content_frame + + # 填写用户名 + main_frame.get_by_role("textbox", name="用户名").fill(username) + + # 填写密码 + main_frame.get_by_role("textbox", name="密码").fill(password) + + # 点击登录按钮 + main_frame.get_by_role("button", name="登录").click() + + # 处理强制登录弹窗(判断是否存在) + confirm_btn = main_frame.get_by_role("button", name="确定") + if confirm_btn.count() > 0: + confirm_btn.click() + if verbose: + print("强制登录") + else: + if verbose: + print("正常登录") + + return browser, context, page, main_frame + + +def logout(main_frame: Frame, verbose: bool = True) -> None: + """ + 执行账号注销 + + 参数: + main_frame: 主 iframe 对象 (forwardFrame) + verbose: 是否打印详细日志 + """ + import time + + if verbose: + print("点击账号菜单按钮...") + + # 元素1:账号菜单按钮(logo 图标) + main_frame.get_by_role("img", name="logo").click() + + # 等待菜单出现 + time.sleep(1) + + if verbose: + print("点击退出登录按钮...") + + # 元素2:"退出登录"按钮 + main_frame.get_by_text("退出登录").click() + + # 等待确认框出现 + time.sleep(1) + + if verbose: + print("等待退出登录确认框...") + + # 元素3:退出登录确认框(判断是否出现) + try: + confirm_text = main_frame.get_by_text("退出确定要退出当前账号吗?") + if verbose: + print("找到确认框,点击确定按钮") + + # 元素4:确认按钮 + main_frame.get_by_role("button", name="确定(Y)").click() + except: + if verbose: + print("未找到确认框,可能已自动退出") + + time.sleep(2) # 等待注销完成 + + +def close_session(browser: Browser, context: BrowserContext) -> None: + """ + 关闭浏览器会话 + + 参数: + browser: 浏览器实例 + context: 浏览器上下文 + """ + context.close() + browser.close() diff --git a/utils/离散备料计划维护数据提取.py b/utils/离散备料计划维护数据提取.py index 914683c..a36a48d 100644 --- a/utils/离散备料计划维护数据提取.py +++ b/utils/离散备料计划维护数据提取.py @@ -6,6 +6,7 @@ import os import pandas as pd from playwright.sync_api import sync_playwright from utils.excel_converter import ExcelConverter +from utils.auth import login, logout class DiscreteMaterialPlanExtractor: @@ -186,8 +187,6 @@ class DiscreteMaterialPlanExtractor: Returns: 输出文件路径 """ - from login import login - with sync_playwright() as playwright: # 调用登录模块 browser, context, page, main_frame = login( @@ -236,7 +235,7 @@ class DiscreteMaterialPlanExtractor: # 执行账号注销 self._print("\n开始执行账号注销...") - self.logout(main_frame) + logout(main_frame, verbose=self.verbose) # 转换并合并文件 if downloaded_files: @@ -256,37 +255,6 @@ class DiscreteMaterialPlanExtractor: return output_file - def logout(self, main_frame): - """执行账号注销""" - # 元素1:账号菜单按钮(logo 图标) - self._print("点击账号菜单按钮...") - main_frame.get_by_role("img", name="logo").click() - - # 等待菜单出现 - import time - time.sleep(1) - - # 元素2:"退出登录"按钮 - self._print("点击退出登录按钮...") - main_frame.get_by_text("退出登录").click() - - # 等待确认框出现 - time.sleep(1) - - # 元素3:退出登录确认框(判断是否出现) - self._print("等待退出登录确认框...") - try: - confirm_text = main_frame.get_by_text("退出确定要退出当前账号吗?") - self._print("找到确认框,点击确定按钮") - - # 元素4:确认按钮 - main_frame.get_by_role("button", name="确定(Y)").click() - except: - self._print("未找到确认框,可能已自动退出") - - time.sleep(2) # 等待注销完成 - - def main(): """测试函数""" extractor = DiscreteMaterialPlanExtractor(