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

RuyiPage 元素定位

元素定位是脚本稳定性的分水岭。掌握 ele/eles 定位、属性读取和容器内二次查找,数据提取和交互就有了基础。

核心 API

其他元素方法

API说明
ele.click() / ele.click_self()点击元素
ele.input(text, clear=False)向输入框输入文字
ele.html元素的 outerHTML
ele.inner_html元素的 innerHTML
ele.tag元素标签名(如 div、a、input)
ele.rect元素的位置和尺寸
ele.screenshot(path=None)元素级截图

定位优先级建议

  • 优先用稳定属性:css:#id、css:[data-testid='xxx']。
  • 其次用标签名:tag:h1、tag:input。
  • 再次用文本:text:登录、text:提交。
  • 最后用 XPath:xpath://div[@class='result']。
  • 容器内二次查找优于全局重复查询。

快速上手

python 元素定位与数据提取
from ruyipage import launch

page = launch()
try:
    page.get("https://example.com")

    # 按标签名定位
    h1 = page.ele("tag:h1")
    print(f"标题: {h1.text}")

    # 按 CSS 选择器定位
    link = page.ele("css:a")
    print(f"链接: {link.attr('href')}")

    # 按文本定位
    more = page.ele("text:More information")
    if more:
        print(f"找到: {more.text}")
finally:
    page.quit()

容器内二次查找

python 在搜索结果容器内提取数据
# 先找到容器,再在内部查找子元素
items = page.eles("css:#b_results > li.b_algo")
for item in items:
    title = item.ele("css:h2 a")    # 在 item 内部查找
    desc = item.ele("css:.b_caption p")
    if title:
        print(f"{title.text} -> {title.attr('href')}")
    if desc:
        print(f"  {desc.text}")

相关示例源码

3 个示例 ▶ 点击展开

元素查找: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()

元素交互:点击、输入、选择、悬停、表单提交

examples/03_element_interaction.py

围绕元素对象的高层交互,覆盖输入、点击、选择和状态读取。

GitHub 仓库 查看仓库源码 click_selfinputclearvalueselect.by_valuedouble_clickright_clickhover
  • 点击按钮并读取页面反馈
  • 填写文本、邮箱、密码和数字输入框
  • 清空后重新输入
  • 切换复选框和单选框
  • 在原生模式与兼容模式下操作 select
  • 执行双击、右击和悬停

源码文件:app/content/ruyipage_examples/03_element_interaction.py · 仓库:03_element_interaction.py

python 注释版
# =============================
# RuyiPage 示例注释版
# 标题: 元素交互:点击、输入、选择、悬停、表单提交
# 说明: 围绕元素对象的高层交互,覆盖输入、点击、选择和状态读取。
# 你会学到:
#   1. 点击按钮并读取页面反馈
#   2. 填写文本、邮箱、密码和数字输入框
#   3. 清空后重新输入
#   4. 切换复选框和单选框
#   5. 在原生模式与兼容模式下操作 select
# 相关 API: click_self, input, clear, value, select.by_value, double_click, right_click, hover
# =============================

# -*- coding: utf-8 -*-
"""
示例3: 元素交互
测试功能:
- 点击元素
- 输入文本
- 清空输入
- 双击、右键点击
- 鼠标悬停
- 拖拽
"""

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_interaction():
    """测试元素交互功能"""
    print("=" * 60)
    print("测试3: 元素交互")
    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. 点击按钮
        print("\n1. 点击按钮:")
        click_btn = page.ele("#click-btn")
        click_btn.click_self()
        page.wait(0.5)
        result = page.ele("#click-result").text
        print(f"   点击结果: {result}")

        # 再点击几次
        click_btn.click_self()
        click_btn.click_self()
        page.wait(0.5)
        result = page.ele("#click-result").text
        print(f"   多次点击后: {result}")

        # 2. 输入文本
        print("\n2. 输入文本:")
        text_input = page.ele("#text-input")
        text_input.input("Hello RuyiPage!")
        page.wait(0.5)
        print(f"   输入的值: {text_input.value}")

        # 3. 清空并重新输入
        print("\n3. 清空并重新输入:")
        text_input.clear()
        text_input.input("新的文本内容")
        print(f"   新的值: {text_input.value}")

        # 4. 输入到其他类型的输入框
        print("\n4. 输入到不同类型的输入框:")
        page.ele("#email-input").input("[email protected]")
        page.ele("#password-input").input("password123")
        page.ele("#number-input").input("42")
        page.ele("#textarea").input("这是多行文本\n第二行\n第三行")
        print(f"   ✓ 所有输入框填写完成")

        # 5. 复选框操作
        print("\n5. 复选框操作:")
        checkbox1 = page.ele("#checkbox1")
        checkbox2 = page.ele("#checkbox2")
        print(f"   checkbox1初始状态: {checkbox1.is_checked}")
        checkbox1.click_self()
        page.wait(0.3)
        print(f"   checkbox1点击后: {checkbox1.is_checked}")
        checkbox2.click_self()
        page.wait(0.3)
        print(f"   checkbox2点击后: {checkbox2.is_checked}")

        # 6. 单选框操作
        print("\n6. 单选框操作:")
        radio1 = page.ele("#radio1")
        radio2 = page.ele("#radio2")
        radio1.click_self()
        page.wait(0.3)
        print(f"   radio1选中: {radio1.is_checked}")
        radio2.click_self()
        page.wait(0.3)
        print(f"   radio2选中: {radio2.is_checked}")
        print(f"   radio1现在: {radio1.is_checked}")

        # 7. 下拉选择
        print("\n7. 下拉选择:")
        select = page.ele("#select-single")
        # 教学建议:优先 native_only,失败再切 compat。
        select_ok = select.select.by_value("opt2", mode="native_only")
        if not select_ok:
            print("   native_only 失败,切换到 compat 模式保底...")
            select_ok = select.select.by_value("opt2", mode="compat")
        page.wait(0.5)
        print(f"   选中的值: {select.value}")
        selected = select.select.selected_option
        print(f"   选中的文本: {selected['text']}")
        print(f"   原生选择结果: {select_ok}")

        # 8. 双击
        print("\n8. 双击按钮:")
        dbl_btn = page.ele("#double-click-btn")
        dbl_btn.double_click()
        page.wait(0.5)
        result = page.ele("#click-result").text
        print(f"   双击结果: {result}")

        # 9. 右键点击
        print("\n9. 右键点击:")
        right_btn = page.ele("#right-click-btn")
        right_btn.right_click()
        page.wait(0.5)
        result = page.ele("#click-result").text
        print(f"   右键点击结果: {result}")

        # 10. 鼠标悬停
        print("\n10. 鼠标悬停:")
        hover_target = page.ele("#hover-target")
        hover_target.hover()
        page.wait(0.5)
        hover_result = page.ele("#hover-result").text
        print(f"   悬停结果: {hover_result}")

        # 11. 提交表单
        print("\n11. 提交表单:")
        submit_btn = page.ele("#submit-btn")
        submit_btn.click_self()
        page.wait(0.5)
        form_result = page.ele("#form-result").text
        print(f"   表单结果: {form_result[:50]}...")

        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_interaction()

原生 Select 选择:只测 native_only 模式与事件诊断

examples/36_native_bidi_select.py

专门帮助排查 select 的焦点、键盘与 trusted change 路径问题。

GitHub 仓库 查看仓库源码 select.by_valueselect.selected_optionclick_selfpage.actions.key_downpage.actions.key_uppage.run_js
  • 检查 select 初始状态
  • 聚焦后通过键盘切换选项
  • 强制只走 native_only 模式
  • 读取 changeCount 和 trustedChange 诊断信息

源码文件:app/content/ruyipage_examples/36_native_bidi_select.py · 仓库:36_native_bidi_select.py

python 注释版
# =============================
# RuyiPage 示例注释版
# 标题: 原生 Select 选择:只测 native_only 模式与事件诊断
# 说明: 专门帮助排查 select 的焦点、键盘与 trusted change 路径问题。
# 你会学到:
#   1. 检查 select 初始状态
#   2. 聚焦后通过键盘切换选项
#   3. 强制只走 native_only 模式
#   4. 读取 changeCount 和 trustedChange 诊断信息
# 相关 API: select.by_value, select.selected_option, click_self, page.actions.key_down, page.actions.key_up, page.run_js
# =============================

# -*- coding: utf-8 -*-
"""
示例36: 原生 BiDi Select 检测(仅原生)

目标:
1) 只测试 native_only(不允许 JS 保底)
2) 输出分步诊断信息,帮助定位焦点/键盘路径问题
"""

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, Keys


def _state(page, select):
    s = page.run_js("return window.nativeBidiSelectState")
    return {
        "value": select.value,
        "selected_option": select.select.selected_option,
        "focused": s.get("focused"),
        "trusted_change": s.get("trustedChange"),
        "change_count": s.get("changeCount"),
        "events": s.get("events", []),
    }


def test_native_bidi_select():
    print("=" * 60)
    print("测试36: 原生 BiDi Select(仅原生)")
    print("=" * 60)

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

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

        select = page.ele("#single-select")

        print("\n1. 初始状态:")
        st = _state(page, select)
        print(f"   value: {st['value']}")
        print(f"   selected_option: {st['selected_option']}")
        print(f"   focused: {st['focused']}")

        print("\n2. 手动焦点探测(原生 click + 一步键盘):")
        select.click_self()
        page.wait(0.1)
        page.actions.key_down(Keys.DOWN).key_up(Keys.DOWN).perform()
        page.wait(0.1)
        st_probe = _state(page, select)
        print(f"   probe value: {st_probe['value']}")
        print(f"   probe focused: {st_probe['focused']}")
        print(f"   probe changeCount: {st_probe['change_count']}")

        print("\n3. 使用 selector native_only 选择 opt2:")
        ok = select.select.by_value("opt2", mode="native_only")
        page.wait(0.3)
        st = _state(page, select)
        print(f"   native_only结果: {ok}")
        print(f"   value: {st['value']}")
        print(f"   selected_option: {st['selected_option']}")
        print(f"   focused: {st['focused']}")
        print(f"   trustedChange: {st['trusted_change']}")
        print(f"   changeCount: {st['change_count']}")

        print("\n4. 页面事件日志:")
        for line in st["events"]:
            print(f"   {line}")

        if not ok or select.value != "opt2":
            raise RuntimeError("native_only 未成功切换到 opt2")

        print("\n" + "=" * 60)
        print("✓ 原生 BiDi Select 测试通过!")
        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_native_bidi_select()