跳到主要内容

🔦 页面或元素内查找

✅️️ 页面或元素内查找

页面对象和元素对象都拥有ele()eles()方法,用于获取其内部指定子元素。

📌 ele()

用于查找其内部第一个符合条件的元素。

SessionPageChromiumPage获取元素的方法是一致的,但前者返回的元素对象为SessionElement,后者是ChromiumElement

参数名称类型默认值说明
locatorstr
Tuple[str, str]
必填元素的定位信息。可以是查询字符串,或 loc 元组
indexint1获取第几个匹配的元素,从1开始,可输入负数表示从后面开始数
timeoutfloatNone等待元素出现的超时时间(秒),为None使用页面对象设置
返回类型说明
SessionElements 模式下返回静态元素对象
ChromiumElementd 模式下返回找到的第一个符合条件的浏览器元素对象
ChromiumFrame当结果是框架元素时
NoneElement未找到符合条件的元素时返回
说明
  • loc 元组是指 selenium 定位符,例:(By.ID, '****')。下同。
  • ele('****', index=2)eles('****')[1]结果一样,不过前者会快很多。

示例:

from DrissionPage import SessionPage

page = SessionPage()

# 在页面内查找元素
ele1 = page.ele('#one')

# 在元素内查找后代元素
ele2 = ele1.ele('第二行')


📌 eles()

此方法与ele()相似,但返回的是匹配到的所有元素组成的列表。

页面对象和元素对象都可调用这个方法。

参数名称类型默认值说明
locatorstr
Tuple[str, str]
必填元素的定位信息,可以是查询字符串,或 loc 元组
timeoutfloatNone等待元素出现的超时时间(秒),为None使用页面对象设置
返回类型说明
SessionElementsLists 模式下返回静态元素对象组成的列表
ChromiumElementsListd 模式下返回浏览器元素对象组成的列表

示例:

# 获取页面内的所有p元素
p_eles = tab.eles('tag:p')

# 获取ele1元素内的所有p元素
p_eles = ele1.eles('tag:p')

# 打印第一个p元素的文本
print(p_eles[0])

📌 get_frame()

<iframe><frame>也可以用ele()查找到,生成的对象是ChromiumFrame而不是ChromiumElement

但不建议用ele()获取<iframe>元素,因为 IDE 无法正确提示后续操作。

建议用get_frame()方法获取,页面对象和元素对象都有这个方法。

使用方法与ele()一致,可以用定位符查找。还增加了用序号、id、name 属性定位元素的功能。

参数名称类型默认值说明
loc_ind_elestr
int
ChromiumFrame
必填定位符
<iframe>元素序号(从1开始,负数表示倒数)
ChromiumFrame对象
id属性内容
name属性内容
timeoutfloatNone超时时间(秒),为None时使用页面超时时间
返回类型说明
ChromiumFrame<frame><iframe>元素对象
NoneElement找不到时返回NoneElement

示例:

# 在标签页中获取第一个iframe元素
iframe = tab.get_frame(1)

# 在元素中获取id为`theFrame`的<iframe>元素对象
iframe = ele.get_frame('#theFrame')

📌 get_frames()

此方法用于获取页面中多个符合条件的<frame><iframe>对象。

元素对象无此方法。

提醒

获取所有<iframe>会很慢,而且浪费资源,非必要别用。

参数名称类型默认值说明
locatorstr
Tuple[str, str]
None定位符,为None时返回所有
timeoutfloatNone超时时间(秒),为None时使用页面超时时间
返回类型说明
ChromiumElementsList<frame><iframe>元素对象组成的列表

✅️️ 静态方式查找

静态元素即 s 模式的SessionElement元素对象,是纯文本构造的,因此用它处理速度非常快。
对于复杂的页面,要在成百上千个元素中采集数据时,转换为静态元素可把速度提升几个数量级。
作者曾在实践的时候,用同一套逻辑,仅仅把元素转换为静态,就把一个要 30 秒才完成的页面,加速到零点几秒完成。
我们甚至可以把整个页面转换为静态元素,再在其中提取信息。
当然,这种元素不能进行点击等交互。
s_ele()可在把查找到的动态元素转换为静态元素输出,或者获取元素或页面本身的静态元素副本。

注意

如果需要获取多条数据,不要反复使用s_ele(),只要在容器元素调用一次获取其静态副本,再在其中执行获取多个元素。

📌 s_ele()

页面对象和元素对象都拥有此方法,用于查找第一个匹配条件的元素,获取其静态版本。

参数名称类型默认值说明
locatorstr
Tuple[str, str]
None元素的定位信息,可以是查询字符串,或 loc 元组,为None时获取调用者本身的静态版本
indexint1获取第几个匹配的元素,从1开始,可输入负数表示从后面开始数
timeoutfloatNone查找元素超时时间(秒),为None与页面等待时间一致
返回类型说明
SessionElement返回查找到的第一个符合条件的元素对象的静态版本
NoneElement限时内未找到符合条件的元素时返回NoneElement对象
注意

页面对象和元素对象的s_ele()方法不能搜索到在<iframe>里的元素,页面对象的静态版本也不能搜索<iframe>里的元素。 要使用<iframe>里元素的静态版本,可先获取该元素,再转换。而使用ChromiumFrame对象,则可以直接用s_ele()查找元素,这在后面章节再讲述。

Tips

从一个ChromiumElement元素获取到的SessionElement版本,依然能够使用相对定位方法定位祖先或兄弟元素。

from DrissionPage import Chromium

tab = Chromium().latest_tab

# 在页面中查找元素,获取其静态版本
ele1 = tab.s_ele('search text')

# 在动态元素中查找元素,获取其静态版本
ele = tab.ele('search text')
ele2 = ele.s_ele()

# 获取页面元素的静态副本(不传入参数)
s_page = tab.s_ele()

# 获取动态元素的静态副本
s_ele = ele.s_ele()

# 在静态副本中查询下级元素(因为已经是静态元素,用ele()查找结果也是静态)
ele3 = s_page.ele('search text')
ele4 = s_ele.ele('search text')

📌 s_eles()

此方法与s_ele()相似,但返回的是匹配到的所有元素组成的列表,或属性值组成的列表。

参数名称类型默认值说明
locatorstr
Tuple[str, str]
必填元素的定位信息,可以是查询字符串,或 loc 元组
timeoutfloatNone查找元素超时时间(秒),为None与页面等待时间一致
返回类型说明
SessionElementsList返回找到的所有元素的SessionElement版本组成的列表

示例:

from DrissionPage import Chromium

tab = Chromium().latest_tab
for ele in tab.s_eles('search text'):
print(ele.text)

✅️ 获取页面焦点元素

使用页面对象的active_ele属性获取页面上焦点所在元素。

ele = tab.active_ele

✅️️ 查找<iframe>中的元素

📌 在页面下跨级查找

与 selenium 不同,本库可以直接查找同域<iframe>里面的元素。
而且无视层级,可以直接获取到多层<iframe>里的元素。无需切入切出,大大简化了程序逻辑,使用更便捷。
但同域的<iframe>才能这样查找。

假设在页面中有个两级<iframe>,其中有个元素<div id='abc'></div>,可以这样获取:

tab = Chromium().latest_tab
ele = tab('#abc')

获取前后无需切入切出,也不影响获取页面上其它元素。

如果用 selenium,要这样写:

driver = webdriver.Chrome()
driver.switch_to.frame(0)
driver.switch_to.frame(0)
ele = driver.find_element(By.ID, 'abc')
driver.switch_to.default_content()

显然比较繁琐,而且切入到<iframe>后无法对<iframe>外的元素进行操作。

注意
  • 跨级查找只是页面对象支持,元素对象不能直接查找内部 iframe 里的元素。
  • 跨级查找只能用于与主框架同域名的<iframe>,不同域名的请用下面的方法。

📌 在 iframe 元素内查找

对于跨域的<iframe>,我们无法通过页面直接查找里面的元素,可以先获取到<iframe>元素,再在其下查找。

当然,非跨域<iframe>也可以这样操作。

假设一个<iframe>的 id 为 'iframe1',要在其中查找一个 id 为'abc'的元素:

tab = Chromium().latest_tab
iframe = tab('#iframe1')
ele = iframe('#abc')

这个<iframe>元素是一个页面对象,因此可以继续在其下进行跨<iframe>查找(相对这个<iframe>不跨域的)。


✅️️ ShadowRoot内查找

本库把 shadow-root 也作为元素对象看待,是为ShadowRoot对象。 该对象可与普通元素一样查找下级元素和 DOM 内相对定位。
ShadowRoot对象进行相对定位时,把它看作其父对象内部的第一个对象,其余定位逻辑与普通对象一致。

用元素对象的shadow_root属性可获取ShadowRoot对象。

注意

如果ShadowRoot元素的下级元素中有其它ShadowRoot元素,那这些下级ShadowRoot 元素内部是无法直接通过定位语句查找到的,只能先定位到其父元素,再用shadow-root属性获取。

# 获取一个 shadow-root 元素
sr_ele = page.ele('#app').shadow_root

# 在该元素下查找下级元素
ele1 = sr_ele.ele('tag:div')

# 用相对定位获取其它元素
ele1 = sr_ele.parent(2)
ele1 = sr_ele.next('tag:div', 1)
ele1 = sr_ele.after('tag:div', 1)
eles = sr_ele.nexts('tag:div')

# 定位下级元素中的 shadow+-root 元素
sr_ele2 = sr_ele.ele('tag:div').shadow_root

由于 shadow-root 不能跨级查找,链式操作非常常见,所以设计了一个简写:sr,功能和shadow_root 一样,都是获取元素内部的ShadowRoot

多级 shadow-root 链式操作示例:

以下这段代码,可以打印浏览器历史第一页,可见是通过多级 shadow-root 来获取的。

from DrissionPage import Chromium

tab = Chromium().latest_tab
tab.get('chrome://history/')

items = tab('#history-app').sr('#history').sr.eles('t:history-item')
for i in items:
print(i.sr('#item-container').text.replace('\n', ''))

✅️️ 同时匹配多个定位符

所有页面或元素对象都有find()方法,可接收多个定位符,同时查找多个(批)不同定位符的元素。

dict方法返回每个定位符结果。

说明

first_eleTrue时,如果一个定位符没有被执行过查找,它返回的结果为None

参数名称类型默认值说明
locatorsList[str]
Tuple[str]
str
tuple
必填定位符组成的列表
any_oneboolTrue是否任何一个定位符找到结果即返回
first_eleboolTrue每个定位符获取第一个元素还是所有元素
timeoutfloatNone超时时间(秒),为None使用该对象默认设置
说明

以下所说的 “定位符”,是strtuple类型的。 “元素对象”,是ChromiumElement(d 模式)或SessionElement(s 模式)类型的,没有找到时是NoneElement类型的。 “元素对象组成的列表” 是ChromiumElementsList(d 模式)或SessionElementsList(s 模式)类型的。 any_one参数为True时,以tuple方式返回找到目标的定位符和结果,为False时以dict方法返回每个定位符结果。

返回类型any_one参数取值说明
tuple(定位符, 元素对象)Truefirst_eleTrue时,返回第一个有结果的定位符找到的第一个元素对象
tuple(定位符, 元素对象组成的列表)Truefirst_eleFalse时,返回第一个有结果的定位符找到的所有元素对象
tuple(None, None)True所有定位符都没有找到元素,返回(None, None)
dict{定位符: 元素对象}Falsefirst_eleTrue时,每个定位符返回第一个元素,找不到时为NoneElement
dict{定位符: 元素对象组成的列表}Falsefirst_eleFalse时,每个定位符返回所有结果元素组成的列表

示例:

from DrissionPage import Chromium

tab = Chromium().latest_tab
tab.get('https://www.baidu.com')
res = tab.find(('#kw', '#su'))
print(res)