全球动态代理 · 静态住宅代理 · 极高质量 · 包月不限量 · 学员低价 · 联系如意进行免费测试 · 欢迎公司及学员采购 · 另有任何海外数据采集需求,随时联系 · 商务合作微信:Charleval
Automation / XPath Picker
定位辅助工具

RuyiPage XPath Picker

XPath Picker 是内置的浮窗定位工具,鼠标悬停即可高亮元素并生成 XPath/CSS 选择器代码,大幅提升定位效率。

核心 API

opts.enable_xpath_picker

返回: FirefoxOptions
opts.enable_xpath_picker(enabled=True)

在 FirefoxOptions 中启用 XPath Picker 浮窗。

参数说明
参数说明
enabledTrue 启用 / False 禁用。
常见坑
  • 需要在启动前配置,启动后无法动态开关。
相关示例

launch(xpath_picker=True)

返回: FirefoxPage
launch(xpath_picker=True)

启动时直接开启 XPath Picker,无需单独配置 opts。

参数说明
参数说明
xpath_pickerTrue 启用浮窗。
相关示例

快速上手

python 启用 XPath Picker
from ruyipage import launch

# 方式1:launch 快捷参数
page = launch(xpath_picker=True)
page.get("https://example.com")
# 鼠标悬停页面元素即可看到定位器浮窗
page.wait(30)  # 留时间手动操作
page.quit()

# 方式2:通过 FirefoxOptions
from ruyipage import FirefoxPage, FirefoxOptions
opts = FirefoxOptions()
opts.enable_xpath_picker(True)
page = FirefoxPage(opts)
page.get("https://example.com")
page.wait(30)
page.quit()

相关示例源码

4 个示例 ▶ 点击展开

XPath Picker 综合演示

examples/42_xpath_picker_complex_showcase.py

完整展示 XPath Picker 在复杂节点、iframe、嵌套 iframe 和 open shadow root 中的拾取与代码生成能力。

GitHub 仓库 查看仓库源码 opts.enable_xpath_pickerlaunch(xpath_picker=True)page.getpicker 自动生成代码链
  • 启用 XPath Picker 浮窗
  • 查看绝对 XPath 与相对 XPath
  • 自动生成 RuyiPage 定位代码
  • 处理 iframe 与 shadow root 嵌套结构

元素查找:CSS / XPath / 文本 / 属性 / 容器内定位

examples/02_element_finding.py

系统讲透单元素、多元素、文本、XPath 和属性定位的入门示例。

GitHub 仓库 查看仓库源码 page.elepage.elesele.eleele.textele.attrele.attrsele.tag
  • 通过 ID、class 和属性定位元素
  • 批量获取列表元素
  • 通过 XPath 和文本定位元素
  • 在父容器内继续查找子元素
  • 读取元素标签、属性和尺寸信息

源码文件:app/content/ruyipage_examples/02_element_finding.py · 仓库:02_element_finding.py

python 注释版
# =============================
# RuyiPage 示例注释版
# 标题: 元素查找:CSS / XPath / 文本 / 属性 / 容器内定位
# 说明: 系统讲透单元素、多元素、文本、XPath 和属性定位的入门示例。
# 你会学到:
#   1. 通过 ID、class 和属性定位元素
#   2. 批量获取列表元素
#   3. 通过 XPath 和文本定位元素
#   4. 在父容器内继续查找子元素
#   5. 读取元素标签、属性和尺寸信息
# 相关 API: page.ele, page.eles, ele.ele, ele.text, ele.attr, ele.attrs, ele.tag
# =============================

# -*- coding: utf-8 -*-
"""
示例2: 元素查找
测试功能:
- CSS选择器查找
- XPath查找
- 文本查找
- 属性查找
- 多元素查找
- 元素属性获取
"""

import os
import sys
import io

# 设置控制台输出编码为UTF-8(Windows兼容)
if sys.platform == 'win32':
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from ruyipage import FirefoxPage, FirefoxOptions

def test_element_finding():
    """测试元素查找功能"""
    print("=" * 60)
    print("测试2: 元素查找")
    print("=" * 60)

    opts = FirefoxOptions()
    opts.headless(False)
    page = FirefoxPage(opts)

    try:
        # 加载测试页面
        test_page = os.path.join(os.path.dirname(__file__), 'test_pages', 'test_page.html')
        test_url = 'file:///' + os.path.abspath(test_page).replace('\\', '/')
        page.get(test_url)
        page.wait(1)

        # 1. 通过ID查找
        print("\n1. 通过ID查找元素:")
        title = page.ele('#main-title')
        print(f"   标题文本: {title.text}")
        print(f"   标签名: {title.tag}")

        # 2. 通过class查找
        print("\n2. 通过class查找元素:")
        test_div = page.ele('.test-class')
        print(f"   第一个.test-class元素: {test_div.text}")

        # 3. 查找所有匹配元素
        print("\n3. 查找所有.test-class元素:")
        all_test = page.eles('.test-class')
        print(f"   找到 {len(all_test)} 个元素")
        for i, elem in enumerate(all_test, 1):
            print(f"   元素{i}: {elem.text}")

        # 4. 通过XPath查找
        print("\n4. 通过XPath查找:")
        link = page.ele('xpath://a[@id="test-link"]')
        print(f"   链接文本: {link.text}")
        print(f"   链接地址: {link.link}")

        # 5. 通过文本查找
        print("\n5. 通过文本查找:")
        btn = page.ele('text:点击我')
        print(f"   按钮ID: {btn.attr('id')}")

        # 6. 通过属性查找
        print("\n6. 通过属性查找:")
        test_div = page.ele('[data-test="value"]')
        print(f"   data-test属性的元素: {test_div.text}")
        print(f"   所有属性: {test_div.attrs}")

        # 7. 组合选择器
        print("\n7. 组合选择器:")
        section = page.ele('#form-section')
        input_elem = section.ele('input[type="text"]')
        print(f"   表单区域内的文本输入框: {input_elem.attr('placeholder')}")

        # 8. 获取元素属性
        print("\n8. 获取元素属性:")
        img = page.ele('#test-img')
        print(f"   图片alt: {img.attr('alt')}")
        print(f"   图片src: {img.src}")

        # 9. 元素状态检查
        print("\n9. 元素状态检查:")
        disabled_btn = page.ele('#disabled-btn')
        print(f"   禁用按钮是否可用: {disabled_btn.is_enabled}")
        print(f"   禁用按钮是否显示: {disabled_btn.is_displayed}")

        # 10. 元素尺寸和位置
        print("\n10. 元素尺寸和位置:")
        click_btn = page.ele('#click-btn')
        print(f"   按钮尺寸: {click_btn.size}")
        print(f"   按钮位置: {click_btn.location}")

        print("\n" + "=" * 60)
        print("✓ 所有元素查找测试通过!")
        print("=" * 60)

    except Exception as e:
        print(f"\n✗ 测试失败: {e}")
        import traceback
        traceback.print_exc()
    finally:
        page.wait(2)
        page.quit()

if __name__ == '__main__':
    test_element_finding()

iframe 操作:多种获取方式、上下文访问与 with_frame

examples/13_iframe.py

这是 iframe 专题的主示例,必须在文档中单列。

GitHub 仓库 查看仓库源码 page.get_framespage.get_framepage.with_frameiframe.eleiframe.run_jsiframe.tab_idiframe.is_cross_origin
  • 通过 locator 获取 iframe
  • 通过 index 获取 iframe
  • 通过 context_id 获取 iframe
  • 在 iframe 内查找元素并点击
  • 在 iframe 内执行 JS
  • 判断 iframe 是否跨域
  • 使用 with_frame() 临时进入上下文后返回主页面

源码文件:app/content/ruyipage_examples/13_iframe.py · 仓库:13_iframe.py

python 注释版
# =============================
# RuyiPage 示例注释版
# 标题: iframe 操作:多种获取方式、上下文访问与 with_frame
# 说明: 这是 iframe 专题的主示例,必须在文档中单列。
# 你会学到:
#   1. 通过 locator 获取 iframe
#   2. 通过 index 获取 iframe
#   3. 通过 context_id 获取 iframe
#   4. 在 iframe 内查找元素并点击
#   5. 在 iframe 内执行 JS
# 相关 API: page.get_frames, page.get_frame, page.with_frame, iframe.ele, iframe.run_js, iframe.tab_id, iframe.is_cross_origin
# =============================

# -*- coding: utf-8 -*-
"""示例13: iframe 操作(完整 + 复杂场景)

覆盖点:
1) 通过 locator/index/context_id 三种方式访问 iframe
2) 在 iframe 内元素查找、点击、JS 执行
3) 读取 iframe 列表和跨上下文稳定性
4) 使用 with_frame() 简化接口(新手友好)
"""

import os
import sys
import io

# 设置控制台输出编码为UTF-8(Windows兼容)
if sys.platform == "win32":
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from ruyipage import FirefoxPage, FirefoxOptions


def test_iframe():
    """测试iframe操作功能"""
    print("=" * 60)
    print("测试13: iframe操作")
    print("=" * 60)

    opts = FirefoxOptions()
    opts.headless(False)
    page = FirefoxPage(opts)

    try:
        # 加载测试页面
        test_page = os.path.join(
            os.path.dirname(__file__), "test_pages", "test_page.html"
        )
        test_url = "file:///" + os.path.abspath(test_page).replace("\\", "/")
        page.get(test_url)
        page.wait(1)

        # 滚动到iframe区域
        page.scroll.to_see(page.ele("#iframe-section"))
        page.wait(0.5)

        # 1. 获取iframe元素
        print("\n1. 获取iframe元素:")
        iframe_elem = page.ele("#test-iframe")
        print(f"   ✓ iframe元素已找到: {iframe_elem.tag}")

        # 1.1 获取所有 frame
        print("\n1.1 获取所有iframe:")
        frames = page.get_frames()
        print(f"   当前页面 frame 数量: {len(frames)}")

        # 2. 切换到iframe
        print("\n2. 切换到iframe:")
        iframe = page.get_frame("#test-iframe")
        print(f"   ✓ 已切换到iframe")

        # 2.1 通过 index 获取
        print("\n2.1 通过 index 获取iframe:")
        iframe_by_index = page.get_frame(index=0)
        print(f"   index=0 是否可用: {iframe_by_index is not None}")

        # 2.2 通过 context_id 获取
        print("\n2.2 通过 context_id 获取iframe:")
        iframe_by_ctx = page.get_frame(context_id=iframe.tab_id)
        print(f"   context_id 是否匹配: {iframe_by_ctx.tab_id == iframe.tab_id}")

        # 3. 在iframe中查找元素
        print("\n3. 在iframe中查找元素:")
        iframe_title = iframe.ele("tag:h1")
        if iframe_title:
            print(f"   iframe标题: {iframe_title.text}")
        else:
            print(f"   未找到iframe标题")

        # 3.1 iframe跨域判断
        print("\n3.1 iframe跨域判断:")
        print(f"   is_cross_origin: {iframe.is_cross_origin}")

        # 4. 在iframe中操作按钮
        print("\n4. 在iframe中操作按钮:")
        iframe_btn = iframe.ele("#iframe-btn")
        if iframe_btn:
            print(f"   找到iframe按钮: {iframe_btn.text}")
            iframe_btn.click_self()
            page.wait(1)
            print(f"   ✓ iframe按钮已点击")
        else:
            print(f"   未找到iframe按钮")

        # 5. 获取iframe内容
        print("\n5. 获取iframe内容:")
        iframe_html = iframe.html
        print(f"   iframe HTML长度: {len(iframe_html)} 字符")

        # 6. 在iframe中执行JS
        print("\n6. 在iframe中执行JS:")
        result = iframe.run_js("return document.body.innerHTML")
        print(f"   iframe body内容长度: {len(result)} 字符")

        # 6.1 iframe 内脚本修改 DOM
        print("\n6.1 iframe 内修改DOM并验证:")
        iframe.run_js(
            """
            const h = document.querySelector('h1');
            h.textContent = 'iframe内容-已修改';
            return h.textContent;
            """,
            as_expr=False,
        )
        changed_title = iframe.ele("tag:h1").text
        print(f"   修改后标题: {changed_title}")

        # 7. 切换回主页面
        print("\n7. 切换回主页面:")
        # 直接使用page对象即可,它始终指向主页面
        main_title = page.ele("#main-title")
        print(f"   主页面标题: {main_title.text}")

        # 7.1 验证主页面元素仍可操作
        click_btn = page.ele("#click-btn")
        click_btn.click_self()
        page.wait(0.4)
        click_result = page.ele("#click-result").text
        print(f"   主页面点击结果: {click_result}")

        # 8. 再次切换到iframe
        print("\n8. 再次切换到iframe:")
        iframe2 = page.get_frame("#test-iframe")
        iframe_title2 = iframe2.ele("tag:h1")
        if iframe_title2:
            print(f"   ✓ 再次访问iframe成功: {iframe_title2.text}")

        # 8.1 使用 with_frame 简化接口
        print("\n8.1 使用 with_frame() 访问iframe:")
        with page.with_frame("#test-iframe") as frame_ctx:
            frame_text = frame_ctx.ele("tag:h1").text
            print(f"   with_frame 读取标题: {frame_text}")

        # 8.2 with_frame 结束后仍在主页面上下文
        still_main = page.ele("#main-title").text
        print(f"   with_frame 退出后主页面标题: {still_main}")

        print("\n" + "=" * 60)
        print("✓ 所有iframe操作测试通过!")
        print("=" * 60)

    except Exception as e:
        print(f"\n✗ 测试失败: {e}")
        import traceback

        traceback.print_exc()
    finally:
        page.wait(2)
        page.quit()


if __name__ == "__main__":
    test_iframe()

Shadow DOM 与嵌套 iframe:open / closed shadow 全场景

examples/14_shadow_dom.py

这是 shadow DOM 与复杂边界专题的主示例,必须在文档中单列。

GitHub 仓库 查看仓库源码 ele.with_shadowshadow_root.elepage.with_frameframe.ele
  • 进入主页面 open shadow root
  • 进入主页面 closed shadow root
  • 在 iframe 内访问 open shadow
  • 在 iframe 内访问 closed shadow
  • 组合使用 with_frame 和 with_shadow
  • 处理复杂边界后恢复主页面上下文

源码文件:app/content/ruyipage_examples/14_shadow_dom.py · 仓库:14_shadow_dom.py

python 注释版
# =============================
# RuyiPage 示例注释版
# 标题: Shadow DOM 与嵌套 iframe:open / closed shadow 全场景
# 说明: 这是 shadow DOM 与复杂边界专题的主示例,必须在文档中单列。
# 你会学到:
#   1. 进入主页面 open shadow root
#   2. 进入主页面 closed shadow root
#   3. 在 iframe 内访问 open shadow
#   4. 在 iframe 内访问 closed shadow
#   5. 组合使用 with_frame 和 with_shadow
# 相关 API: ele.with_shadow, shadow_root.ele, page.with_frame, frame.ele
# =============================

# -*- coding: utf-8 -*-
"""示例14: Shadow DOM + 嵌套 iframe(open/closed 完整场景)

覆盖点:
1) 主页面 open shadow
2) 主页面 closed shadow(桥接函数)
3) 进入 iframe 后 open shadow
4) 进入 iframe 后 closed shadow(桥接函数)
5) with_frame / with_shadow 简洁 API
"""

import io
import os
import sys


if sys.platform == "win32":
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")


sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from ruyipage import FirefoxOptions, FirefoxPage


def test_shadow_dom():
    print("=" * 60)
    print("测试14: Shadow DOM + 嵌套iframe")
    print("=" * 60)

    opts = FirefoxOptions()
    opts.headless(False)
    page = FirefoxPage(opts)

    try:
        test_page = os.path.join(
            os.path.dirname(__file__), "test_pages", "complex_shadow_iframe.html"
        )
        test_url = "file:///" + os.path.abspath(test_page).replace("\\", "/")
        page.get(test_url)
        page.wait(1)

        # 1) 主页面 open shadow
        print("\n1. 主页面 open shadow:")
        host_open = page.ele("#host-open-shadow")
        with host_open.with_shadow("open") as open_root:
            text = open_root.ele("#host-open-text").text
            print(f"   open文本: {text}")

        # 2) 主页面 closed shadow
        print("\n2. 主页面 closed shadow:")
        host_closed = page.ele("#host-closed-shadow")
        with host_closed.with_shadow("closed") as closed_root:
            text = closed_root.ele("#host-closed-text").text
            print(f"   closed文本: {text}")

        # 3) 进入 iframe,测试 open/closed shadow
        print("\n3. 进入iframe并测试 shadow:")
        with page.with_frame("#outer-iframe") as frame:
            inner_title = frame.ele("#inner-title").text
            print(f"   iframe标题: {inner_title}")

            inner_open = frame.ele("#inner-open-host")
            with inner_open.with_shadow("open") as inner_open_root:
                open_text = inner_open_root.ele("#inner-open-text").text
                print(f"   iframe open文本: {open_text}")

            inner_closed = frame.ele("#inner-closed-host")
            with inner_closed.with_shadow("closed") as inner_closed_root:
                closed_text = inner_closed_root.ele("#inner-closed-text").text
                print(f"   iframe closed文本: {closed_text}")

        # 4) 退出 with_frame 后仍可访问主页面
        print("\n4. 退出iframe后主页面可访问:")
        host_title = page.ele("#host-title").text
        print(f"   主页面标题: {host_title}")

        print("\n" + "=" * 60)
        print("✓ Shadow DOM + 嵌套iframe 测试通过!")
        print("=" * 60)

    except Exception as e:
        print(f"\n✗ 测试失败: {e}")
        import traceback

        traceback.print_exc()
    finally:
        page.wait(1)
        page.quit()


if __name__ == "__main__":
    test_shadow_dom()