From d75cacee2c5fd4fcc76ad3f91eb97ead006cc772 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Fri, 16 Jan 2026 08:46:02 +0800 Subject: [PATCH] Add locator helper module and enhance main script for element interaction --- .gitignore | 3 +- locator_helper.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++ main.py | 55 ++++++++++++++- 3 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 locator_helper.py diff --git a/.gitignore b/.gitignore index cfbbf06..6e21798 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ temp tmpclaude-* *.log *workspace* -*.png \ No newline at end of file +*.png +data/ diff --git a/locator_helper.py b/locator_helper.py new file mode 100644 index 0000000..4ddeab4 --- /dev/null +++ b/locator_helper.py @@ -0,0 +1,171 @@ +""" +元素定位辅助工具 - 用于快速验证定位是否有效 +""" +from playwright.sync_api import Page, Frame, Locator + + +def debug_locator(frame: Frame, locator: Locator, timeout: int = 5000): + """ + 调试定位器 - 检查定位是否有效并显示详细信息 + + 参数: + frame: 页面或iframe对象 + locator: 定位器对象 + timeout: 超时时间(毫秒) + + 返回: + bool: 定位是否成功 + """ + print(f"\n验证定位: {locator}") + print("=" * 50) + + try: + # 检查数量 + count = locator.count() + print(f"元素数量: {count}") + + if count == 0: + print("✗ 未找到任何匹配元素") + return False + + # 检查第一个元素是否可见 + first_visible = locator.first.is_visible(timeout=timeout) + print(f"第一个元素可见: {first_visible}") + + # 获取文本内容 + for i in range(min(3, count)): # 最多显示3个 + element = locator.nth(i) + try: + if element.is_visible(timeout=1000): + text = element.inner_text(timeout=1000) + print(f" 元素{i + 1}文本: {text[:100] if len(text) > 100 else text}") + else: + print(f" 元素{i + 1}: 存在但不可见") + except: + print(f" 元素{i + 1}: 无法获取信息") + + print("=" * 50) + return True + + except Exception as e: + print(f"✗ 验证失败: {e}") + print("=" * 50) + return False + + +def try_multiple_locators(frame: Frame, selectors: list[str], timeout: int = 5000) -> Locator: + """ + 尝试多个选择器,返回第一个有效的定位器 + + 参数: + frame: 页面或iframe对象 + selectors: 选择器列表 + timeout: 超时时间(毫秒) + + 返回: + 第一个有效的 Locator,如果没有则返回 None + """ + print(f"\n尝试 {len(selectors)} 个定位方式...") + print("-" * 50) + + for i, selector in enumerate(selectors): + print(f"[{i + 1}] 尝试: {selector}") + try: + locator = frame.locator(selector) + count = locator.count() + visible_count = sum(1 for j in range(count) if locator.nth(j).is_visible(timeout=1000)) + + print(f" 找到 {count} 个元素,其中 {visible_count} 个可见") + + if visible_count > 0: + print(f" ✓ 使用此定位器") + print("-" * 50) + return locator + except Exception as e: + print(f" ✗ 失败: {e}") + + print("-" * 50) + return None + + +def interactive_locate(frame: Frame): + """ + 交互式定位调试 - 进入交互模式测试定位表达式 + """ + print("\n进入交互式定位调试模式") + print("输入定位表达式,输入 'q' 或 'quit' 退出") + print("-" * 50) + + while True: + try: + selector = input("\n>>> ") + selector = selector.strip() + + if selector.lower() in ('q', 'quit'): + break + + if not selector: + continue + + debug_locator(frame, frame.locator(selector)) + + except KeyboardInterrupt: + break + except Exception as e: + print(f"错误: {e}") + + print("退出调试模式") + + +# 示例使用代码(单独运行此文件时的演示) +if __name__ == "__main__": + from playwright.sync_api import sync_playwright + import re + + with sync_playwright() as pw: + browser = pw.chromium.launch(headless=False) + context = browser.new_context(ignore_https_errors=True) + page = context.new_page() + + # 登录 + page.goto("https://68.11.34.30:8082/yonbip/resources/uap/rbac/login/main/index.html") + main_frame = page.locator("#forwardFrame").content_frame + main_frame.get_by_role("textbox", name="用户名").fill("BLDpengqiangqiang") + main_frame.get_by_role("textbox", name="密码").fill("Cqbld123456.") + 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() + + # 循环切换 Inspector 和交互式调试 + print("\n" + "=" * 60) + print("元素定位调试工具") + print("=" * 60) + print("循环模式:") + print(" 1. Inspector 窗口 - 使用浏览器录制/选择元素") + print(" 2. 交互式调试 - 验证定位表达式") + print(" 输入 'q' 或 'quit' 退出程序\n") + + while True: + # 1. 打开 Inspector 窗口 + print("\n【打开 Inspector 窗口】") + print("请在 Inspector 中获取元素定位器,然后关闭 Inspector 继续...") + page.pause() + + # 2. 进入交互式定位调试 + print("\n【进入交互式定位调试】") + interactive_locate(main_frame) + + # 询问是否继续 + choice = input("\n是否继续下一轮调试?(y/n/q): ").strip().lower() + if choice in ('n', 'q', 'quit'): + print("退出程序") + break + elif choice in ('y', ''): # 默认继续 + continue + else: + print("未知选项,退出程序") + break + + context.close() + browser.close() diff --git a/main.py b/main.py index ba7da4f..cd698b4 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,9 @@ """ from playwright.sync_api import sync_playwright from login import login - +from time import sleep +import re +import time def main(): with sync_playwright() as playwright: # 调用登录模块 @@ -16,8 +18,57 @@ def main(): ) # 登录成功后可以进行后续操作 - print("登录成功,可以进行后续操作...") + # 点击打开“菜单” + main_frame.locator("i").first.click() + #page.pause() + # 点击打开“菜单” + with page.expect_popup() as page1_info: + main_frame.get_by_title("离散备料计划维护", exact=True).first.click() + page1 = page1_info.value + + main_frame=page1.locator("#forwardFrame").content_frame + inner_frame_locator = main_frame.locator("#mainiframe") + inner_frame_locator.wait_for(state="visible", timeout=15000) + inner_frame = inner_frame_locator.content_frame + + # 点击图标按钮 + inner_frame.locator(".search-name-wrapper > .iconfont").click() + inner_frame.get_by_text("订单号查询").click() + textbox = inner_frame.get_by_role("textbox", name="来源生产订单号") + textbox.fill("SC70202510110003,SC70202510110004") + inner_frame.get_by_role("tab", name="全部").click() + inner_frame.locator("#rc_select_0").fill("5000") + #发送回车键 + inner_frame.locator("#rc_select_0").press("Enter") + inner_frame.locator(".search-component-searchBtn").click() + print("查询完成,等待加载结果...") + # 等待加载完成 + loading_locator = inner_frame.locator("div").filter(has_text="加载中").nth(1) + try: + loading_locator.wait_for(state="visible", timeout=3000) + loading_locator.wait_for(state="hidden", timeout=0) # 无限等待,直到消失 + except TimeoutError: + # 加载很快完成,或者没有出现加载提示 + pass + print("加载完成,开始选择数据...") + inner_frame.get_by_role("row", name="序号").get_by_label("").check() + + inner_frame.get_by_role("button", name="更多").hover() + inner_frame.get_by_text("输出").click() + input_box = inner_frame.locator("div").filter(has_text=re.compile(r"^行数阈值$")).locator("input[type='text']") + input_box.fill("300000") + # 等待下载事件 + with page1.expect_download() as download_info: + inner_frame.get_by_role("button", name="确定(Y)").click() + + # 获取下载对象 + download = download_info.value + + # 指定保存路径和文件名 + download.save_as("D:/python/playwrite/data/导出文件.xlsx") + + page1.pause() input("按回车退出...") # 关闭浏览器