page.ele
返回: FirefoxElement(未找到返回 NoneElement)page.ele(locator)查找第一个匹配元素。支持 css:/xpath:/tag:/text:/attr: 等前缀。
参数说明
| 参数 | 说明 |
|---|---|
| locator | 定位器字符串,前缀决定匹配方式。 |
常见坑
- NoneElement 不会抛异常,但 .text/.click() 会静默失败,注意判空。
相关示例
元素定位是脚本稳定性的分水岭。掌握 ele/eles 定位、属性读取和容器内二次查找,数据提取和交互就有了基础。
page.ele(locator)查找第一个匹配元素。支持 css:/xpath:/tag:/text:/attr: 等前缀。
| 参数 | 说明 |
|---|---|
| locator | 定位器字符串,前缀决定匹配方式。 |
page.eles(locator)查找所有匹配元素,返回列表。适合批量提取和遍历。
| 参数 | 说明 |
|---|---|
| locator | 与 ele() 相同的定位器。 |
ele.text获取元素的 textContent 文本。
ele.attr(name)获取元素属性值。
| 参数 | 说明 |
|---|---|
| name | 属性名,如 href、class、value、data-id。 |
ele.ele(locator) / ele.eles(locator)在元素内部继续查找子元素。避免全局重复查询,效率更高。
| 参数 | 说明 |
|---|---|
| locator | 与 page.ele() 相同。 |
| 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) | 元素级截图 |
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()# 先找到容器,再在内部查找子元素
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}")系统讲透单元素、多元素、文本、XPath 和属性定位的入门示例。
源码文件:app/content/ruyipage_examples/02_element_finding.py · 仓库:02_element_finding.py
# =============================
# 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()
围绕元素对象的高层交互,覆盖输入、点击、选择和状态读取。
源码文件:app/content/ruyipage_examples/03_element_interaction.py · 仓库:03_element_interaction.py
# =============================
# 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 的焦点、键盘与 trusted change 路径问题。
源码文件:app/content/ruyipage_examples/36_native_bidi_select.py · 仓库:36_native_bidi_select.py
# =============================
# 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()