查找元素(一)

一、基本用法

所有页面对象和元素对象(包括<iframe>和 shadow-root),都可以在自己内部查找元素。元素对象还能以自己为基准,相对定位其它元素。定位元素大致有以下几种方法,将在后续小节中详细说明。

  • 在页面或元素内查找子元素
  • 根据 DOM 结构相对定位
  • 根据视觉位置相对定位

所有的查找元素方法,都可以使用DrissionPage自创的查找语法、xpath、css selector和 selenium 的定位符元组,去查找元素。假设有这样一个页面:

<html>
<body>
<div id="one">
    <p class="p_cls" name="row1">第一行</p>
    <p class="p_cls" name="row2">第二行</p>
    <p class="p_cls">第三行</p>
</div>
<div id="two">
    helloworld
</div>
</body>
</html>

用页面对象去获取其中的元素:

div1 = tab.ele('#one')  # 获取 id 为 one 的元素
p1 = tab.ele('@name=row1')  # 获取 name 属性为 row1 的元素
div2 = tab.ele('helloworld')  # 获取包含"hellworld"文本的元素
div_list = tab.eles('tag:div')  # 获取所有div元素

也可以获取到一个元素,然后在它里面或周围查找元素:

div1 = tab.ele('#one')  # 获取到一个元素div1
p_list = div1.eles('tag:p')  # 在div1内查找所有p元素
div2 = div1.next()  # 获取div1后面一个元素

案例如下:

from DrissionPage import SessionPage

# 创建页面对象,SessionPage 是用于创建和管理页面会话的类
page = SessionPage()

# 使用页面对象访问指定的 URL,这里是 Gitee 的 Explore 页面
page.get("https://gitee.com/explore/all")

# 在页面中查找所有 <h3> 元素,t:h3 是选择器,t 表示标签,h3 是标签名
items = page.eles("t:h3")

# 遍历所有找到的 <h3> 元素,排除最后一个元素
for item in items[:-1]:
    # 获取当前 <h3> 元素下的 <a> 标签元素,'tag:a' 是选择器,tag 表示标签,a 是标签名
    lnk = item('tag:a')
    # 输出 <a> 标签的文本内容和链接地址
    print(lnk.text, lnk.link)

输出如下:

广州中科云飞科技创新有限公司/InnoFlight-MSDK https://gitee.com/qw1357802/innoflight-msdk
沉默王二/paicoding https://gitee.com/itwanger/paicoding
深圳高通半导体有限公司/GT-HMI Builder https://gitee.com/genitop/GT-HMI-Builder
舒登登/PclCSharp https://gitee.com/shudengdeng/pcl-csharp
Ascend/cann-hccl https://gitee.com/ascend/cann-hccl
Cambricon/mlu-ops https://gitee.com/cambricon/mlu-ops
Cambricon/cnindex https://gitee.com/cambricon/cnindex
godo/godoos https://gitee.com/ruitao_admin/godoos
秦派软件/AtomUI https://gitee.com/pulsarware/atomui
dromara/dax-pay https://gitee.com/dromara/dax-pay
DENGCHOW/XhngGPU https://gitee.com/dengchow/XhngGPU
Vue.js/core https://gitee.com/vuejs/core
裴云飞/桃夭 https://gitee.com/zhongte/taoyao
Ericple/log4a https://gitee.com/ericple/log4a
deepflowio/deepflow https://gitee.com/deepflowio/deepflow

二、定位语法

下面介绍DrissionPage 自创的查找元素语法。

  • 查找语法能用于指明以哪种方式去查找指定元素,定位语法简洁明了,熟练使用可大幅提高程序可读性。
  • 所有涉及获取元素的操作都可以使用定位语法,如ele()actions.move_to()wait.eles_loaded()get_frame()等等。
  • 查找语法用于简化代码,提高可读性,但并不覆盖所有复杂场景。很复杂的场景可直接用 xpath 查找。
案例页面:
<html>
<body>
<div id="one">
    <p class="p_cls" id="row1" data="a">第一行</p>
    <p class="p_cls" id="row2" data="b">第二行</p>
    <p class="p_cls">第三行</p>
</div>
<div id="two">
    第二个div
</div>
</body>
</html>

2.1.基本概念

元素属性包括以下三种:

写法说明示例
@tag() 标签名 <div id="one">中的div
@**** 标签体中的属性 <div id="one">中的id,写作'@id'
@text() 元素文本 <p class="p_cls">第三行</p>中的'第三行'
查找语法就是按需要对这三种属性进行组合,达到查找指定元素的目的。说明
  • @tag()@text()后面加上'()',是为了避免和普通属性冲突。
示例说明:
tab.ele('@id=one')  # 获取第一个id为one的元素
tab.ele('@tag()=div')  # 获取第一个div元素
tab.ele('@text()=第一行')  # 获取第一个文本为“第一行”的元素

2.2.基本逻辑

DrissionPage 查找元素的语法可以帮助你通过各种属性组合来精确地定位 HTML 元素。以下是常用的查找语法和方法:

 2.2.1.单属性匹配符 @

用法: @属性名=属性值
说明: 查找具有指定属性名和属性值的元素。

ele = tab.ele('@id=one') # 查找 id 属性为 'one' 的元素2. 多属性匹配符 @@

2.2.2.多属性与匹配符 @@

用法: @@属性1=值1@@属性2=值2
说明: 查找同时满足多个属性值的元素。

ele = tab.ele('@@class=p_cls@@text()=第二行') # 查找 class 为 'p_cls' 且文本为 '第二行' 的元素

2.2.3.多属性或匹配符 @|

用法: @|属性1=值1@|属性2=值2
说明: 查找满足任一属性条件的元素。

eles = tab.eles('@|id=row1@|id=row2') # 查找 id 为 'row1' 或 'row2' 的元素

2.2.4.否定匹配符 @!

用法: @!属性名=属性值 或 @!属性名
说明: 查找不满足指定条件的元素。

ele = tab.ele('@!id=row1') # 查找 id 不等于 'row1' 的元素
ele = tab.ele('@!class') # 查找没有 class 属性的元素

2.2.5.混合使用

@@@|不能同时出现的查找语句中,即一个查找语句只能是与关系或者或关系。

@!则可与两者混合使用。混用时,与还是或关系视@@还是@|而定。

说明
  • 当语句中有多个tag()时,如果全部都没有被@!修饰,它们是与关系;如有任一个被@!修饰,它们是或关系。 tag()与其他属性之间是与关系。
# 匹配class等于p_cls且id不等于row1的元素
tab.ele('@@class=p_cls@!id=row1')

# 匹配class等于p_cls或id不等于row1的元素
tab.ele('@|class=p_cls@!id=row1')

2.3.匹配模式

匹配模式指某个查询中匹配条件的方式,有精确匹配、模糊匹配、匹配开头、匹配结尾四种。

注意

  • tag()属性无论用哪种匹配模式,都会视作=。

2.3.1.精确匹配 =

表示精确匹配,匹配完全符合的文本或属性。

ele = tab.ele('@id=row1') # 获取id属性为'row1'的元素

2.3.2.模糊匹配 :

表示模糊匹配,匹配含有指定字符串的文本或属性。

ele = tab.ele('@id:ow') # 获取id属性包含'ow'的元素

2.3.3.匹配开头 ^

表示匹配开头,匹配开头为指定字符串的文本或属性。

ele = tab.ele('@id^row') # 获取id属性以'row'开头的元素

2.3.4.匹配结尾 $

表示匹配结尾,匹配结尾为指定字符串的文本或属性。

ele = tab.ele('@id$w1') # 获取id属性以'w1'结尾的元素

2.4.常用语法

基于上述基本逻辑,本库提供了一些更已于使用和阅读的语法。

2.4.1.id 匹配符 #

用于匹配id属性,只在语句最前面且单独使用时生效。相当于单属性查找@id=****。可与匹配模式配合使用。

ele = tab.ele('#one') # 查找id为one的元素
ele = tab.ele('#=one') # 和上面一行一致
ele = tab.ele('#:ne') # 查找id属性包含ne的元素
ele = tab.ele('#^on') # 查找id属性以on开头的元素
ele = tab.ele('#$ne') # 查找id属性以ne结尾的元素

2.4.2.class 匹配符 .

用于匹配class属性,只在语句最前面且单独使用时生效,相当于单属性查找@class=****。可配合匹配模式使用。

说明

  • 在面对多个 class 的元素时,DrissionPage 与 selenium 处理方式不一样,无需将空格替换成'.'。 而是将整个 class 视作普通字符串,空格视作普通字符对待,会比较直观。
ele = tab.ele('.p_cls') # 查找class属性为p_cls的元素
ele = tab.ele('.=p_cls') # 与上一行一致
ele = tab.ele('.:_cls') # 查找class属性包含_cls的元素
ele = tab.ele('.^p_') # 查找class属性以p_开头的元素
ele = tab.ele('.$_cls') # 查找class属性以_cls结尾的元素

2.4.3.文本匹配符 text

用于匹配元素文本。只在语句最前面且单独使用时生效,相当于单属性查找@text()=****。可配合匹配模式使用。

  • 如果元素内有多个直接的文本节点,精确查找时可匹配所有文本节点拼成的字符串,模糊查找时可匹配每个文本节点。
  • 如果查找语句没有任何本节介绍的匹配符,默认模糊匹配文本。即ele('第三行')相当于ele('text:第三行')。

注意

  • 如果要匹配的文本包含特殊字符(如'&nbsp;'、'&gt;'),需将其转换为十六进制形式,详见《语法速查表》一节。
  • &nbsp; 是一种 HTML 实体,用于表示不间断空格(non-breaking space)。它的作用是在网页中插入一个空格符号,该空格不会被浏览器自动移除或换行。
ele = tab.ele('text=第二行') # 查找文本为“第二行”的元素
ele = tab.ele('text:第二') # 查找文本包含“第二”的元素
ele = tab.ele('第二') # 与上一行一致
ele = tab.ele('第\u00A0二') # 匹配包含&nbsp;文本的元素,需将&nbsp;转为\u00A0

若要查找的文本包含text: ,可下面这样写,即第一个text: 为关键字,第二个是要查找的内容:

ele2 = tab.ele('text:text:')

2.4.4.类型匹配符 tag

用于匹配某类型元素。只在语句最前面且单独使用时生效,相当于单属性查找@tag()=****。

可与单属性查找或多属性配合使用。tag:与tag=效果一致,没有tag^和tag$语法。

ele = tab.ele('tag:div') # 查找第一个div元素
ele = tab.ele('tag:p@class=p_cls') # 与单属性查找配合使用
ele = tab.ele('tag:p@@class=p_cls@@text()=第二行') # 与多属性查找配合使用

注意

  • tag:div@text():abc 和 tag:div@@text():abc 是有区别的,前者只在div的直接文本节点搜索,后者搜索div的整个内部。

2.4.5.css selector 匹配符 css

表示用 css selector 方式查找元素。只在语句最前面且单独使用时生效。

css:与css=效果一致,没有css^和css$语法。

ele = tab.ele('css:.div') # 查找 div 元素
ele = tab.ele('css:>div') # 查找 div 子元素元素,这个写法是本库特有,原生不支持

2.4.6.xpath 匹配符 xpath

表示用 xpath 方式查找元素。只在语句最前面且单独使用时生效。

xpath:与xpath=效果一致,没有xpath^和xpath$语法。

说明:

  • 元素对象的ele()支持完整的 xpath 语法,如能使用 xpath 直接获取元素属性(字符串类型)。
ele2 = ele1.ele('xpath:.//div') # 查找后代中第一个 div 元素
ele2 = ele1.ele('xpath://div') # 和上面一行一样,查找元素的后代时,// 前面的 . 可以省略
ele_class_str = ele1.ele('xpath://div/@class') # 使用xpath获取div元素的class属性(页面元素无此功能)

说明

  • 查找元素的后代时,selenium 原生代码要求 xpath 前面必须加.,否则会变成在全个页面中查找。 作者觉得这个设计是画蛇添足,既然已经通过元素查找了,自然应该只查找这个元素内部的元素。 所以,用 xpath 在元素下查找时,最前面//或/前面的.可以省略。

2.4.7.selenium 的 loc 元组

查找方法能直接接收 selenium 原生定位元组进行查找,便于项目迁移。

from DrissionPage.common import By

# 查找id为one的元素
loc1 = (By.ID, 'one')
ele = tab.ele(loc1)

# 按 xpath 查找
loc2 = (By.XPATH, '//p[@class="p_cls"]')
ele = tab.ele(loc2)

三、页面或元素内查找

3.1.页面或元素内查找

在页面自动化中,ele()eles() 方法用于从页面或元素内部查找指定的子元素。这些方法允许您根据需要进行精确的元素定位。以下是如何在页面对象和元素对象中使用这些方法:

3.1.1. ele() 方法

  • 功能: 用于查找第一个匹配的子元素。如果存在多个匹配元素,只会返回第一个。
  • 使用场景: 适用于当您只需要获取单个子元素时。
示例:
# 从页面对象中查找第一个id为'login'的元素
login_button = page.ele('#login')

# 从元素对象中查找第一个class为'button'的子元素
submit_button = parent_div.ele('.button'

3.1.2. eles() 方法

  • 功能: 用于查找所有匹配的子元素,并返回一个包含所有匹配元素的列表。
  • 使用场景: 适用于当您需要处理多个匹配元素时。
示例:
# 从页面对象中查找所有class为'item'的元素
items = page.eles('.item')

# 从元素对象中查找所有class为'child'的子元素
children = parent_div.eles('.child')

3.1.3.应用示例

选择器示例:

  • ID 选择器: #id
  • Class 选择器: .class
  • 属性选择器: [attribute=value]
  • 文本选择器: text:内容
  • Tag 选择器: tag:element
假设页面有如下 HTML 结构:
<html>
<body>
<div id="main">
    <button class="btn" id="start">Start</button>
    <button class="btn" id="stop">Stop</button>
</div>
</body>
</html>
  • 查找页面内的第一个按钮:
start_button = page.ele('#start')
  • 查找main div 内的所有按钮:
main_div = page.ele('#main')
buttons = main_div.eles('.btn')

3.2.静态方式查找

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

3.2.1.s_ele()

页面对象和元素对象都拥有此方法,用于查找第一个匹配条件的元素,获取其静态版本。页面对象和元素对象的s_ele()方法参数名称稍有不同,但用法一样。

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://gitee.com/explore/all")

# 将动态元素转换为静态元素
info = page.s_ele('.section')

# 输出静态元素的(标签,文本信息)
print(info.tag, info.text)

# 关闭浏览器
page.quit()

3.2.2.s_eles()

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

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://gitee.com/explore/all")

# 将动态元素转换为静态元素,返回的是匹配到的所有元素组成的列表,或属性值组成的列表。
items = page.s_eles('xpath://h3/a')

# 遍历所有元素组成的列表,分别获取文本和链接
for item in items:
    # 输出 <a> 标签的文本内容和链接地址
    print(item.text, item.link)

# 关闭浏览器
page.quit()

输出如下:

Lucene.Jin/Lucene Server https://gitee.com/jinjiG/lucene-server
devlive-community/InfoSphere https://gitee.com/devlive-community/infosphere
dotNET China/MiniAuth https://gitee.com/dotnetchina/MiniAuth
三鲤/金鱼Scheme https://gitee.com/LiiiLabs/goldfish
广联达科技股份有限公司/GDMPLab https://gitee.com/glodon/gdmplab
Dream Num/univer https://gitee.com/dream-num/univer
广州中科云飞科技创新有限公司/InnoFlight-MSDK https://gitee.com/qw1357802/innoflight-msdk
沉默王二/paicoding https://gitee.com/itwanger/paicoding
深圳高通半导体有限公司/GT-HMI Builder https://gitee.com/genitop/GT-HMI-Builder
舒登登/PclCSharp https://gitee.com/shudengdeng/pcl-csharp
Ascend/cann-hccl https://gitee.com/ascend/cann-hccl
Cambricon/mlu-ops https://gitee.com/cambricon/mlu-ops
Cambricon/cnindex https://gitee.com/cambricon/cnindex
godo/godoos https://gitee.com/ruitao_admin/godoos
秦派软件/AtomUI https://gitee.com/pulsarware/atomui

3.3.获取页面焦点元素

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

ele = tab.active_ele

以百度搜索页面为例进行演示:

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开指定页面
page.get("https://www.baidu.com")

# 输入内容到搜索框
search_box = page.ele("#kw").input("DrissionPage")

# 获取当前页面上的焦点元素
focus_element = page.active_ele

# 输出焦点元素的属性
print("焦点元素的 HTML 内容:", focus_element.html)

# 关闭浏览器
page.quit()

3.4.<iframe>中查找

3.4.1.查找<iframe>元素

<iframe>和<frame>也可以用ele()查找到,生成的对象是ChromiumFrame而不是ChromiumElement。但不建议用ele()获取<iframe>元素,因为 IDE 无法正确提示后续操作。建议用 Page 对象的get_frame()方法获取。使用方法与ele()一致,可以用定位符查找。还增加了用序号、id、name 属性定位元素的功能。示例:

iframe = page.get_frame(1)  # 获取页面中第一个iframe元素
iframe = page.get_frame('#theFrame')  # 获取页面id为theFrame的iframe元素对象

通过126邮箱演示:

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.126.com/")

# 通过xpath定位iframe
iframe = page.get_frame('xpath://div[@id="loginDiv"]/iframe')

# 定位邮箱输入框输入邮箱
page.ele("@name=email").input("Auguses@126.com")
# 输入密码
page.ele("@name=password").input("Qqweasd2543")

# 点击登录
page.ele("@id=dologin").click()

# 关闭浏览器
page.quit()

3.4.2.在页面下跨级查找

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

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

page = ChromiumPage()
ele = page('#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>外的元素进行操作。

通过126邮箱由于邮箱和密码输入框在ifame标签中,输入完成后在点击“会员”,不需要跟selenium的切换回到上一级,代码如下:
from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.126.com/")

# 通过xpath定位iframe
iframe = page.get_frame('xpath://div[@id="loginDiv"]/iframe')

# 定位邮箱输入框输入邮箱
email_box = page.ele("@name=email")
email_box.clear()
email_box.input("Auguses@126.com")

# 输入密码
page.ele("@name=password").input("Qqweasd2543")

# 点击登录
page.ele("@id=dologin").click()

# 点击会员,和selenium不同的是,不需要进行切换出iframe,即可选择选择
page.ele("@href=https://v.mail.163.com/?utm_source=126loginnav").click()

# 关闭浏览器
# page.quit()

3.4.3.在 iframe 元素下查找

本库把<iframe>看作一个特殊元素/页面对象看待,可以实现同时操作多个<iframe>,而无需来回切换。

对于跨域名的<iframe>,我们无法通过页面直接查找里面的元素,可以先获取到<iframe>元素,再在其下查找。当然,非跨域<iframe> 也可以这样操作。

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

page = ChromiumPage()
iframe = page('#iframe1')
ele = iframe('#abc')

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

126邮箱案例如下:

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.126.com/")

# 通过xpath定位iframe,这个<iframe>元素是一个页面对象可以继续在其下进行跨<iframe>查找
iframe = page('xpath://div[@id="loginDiv"]/iframe')

# <iframe>元素是一个页面对象,在里面继续定位邮箱输入框
email_box = iframe("@name=email")
email_box.clear()
email_box.input("Auguses@126.com")

# 输入密码
iframe("@name=password").input("Qqweasd2543")

# 点击登录
iframe("@id=dologin").click()

# 点击会员,和selenium不同的是,不需要进行切换出iframe,即可选择选择
page.ele("@href=https://v.mail.163.com/?utm_source=126loginnav").click()

# 关闭浏览器
# page.quit()

​3.5.ShadowRoot中查找

shadow-root是什么?

  • Shadow Root是Web组件技术中的一个重要概念,‌它属于Shadow DOM技术的一部分。‌Shadow DOM提供了一种封装样式和DOM结构的方法,‌通过创建隔离的DOM树,‌可以避免样式和脚本冲突,‌有助于开发可重用、‌封装良好的组件。‌Shadow Root允许开发者在不影响主文档DOM结构的情况下,‌添加额外的DOM结构和样式,‌从而实现组件的内部细节与外部隔离,‌提高代码的可维护性和重用性。‌在测试和自动化脚本中,‌可以通过适当的方法访问和操作Shadow DOM内的元素,‌确保了即使在复杂的页面结构中也能精确地定位和操作元素。‌
  • Shadow Root可以通过Element.createShadowRoot()方法创建,‌并附加到一个元素节点上作为shadow-host。‌这种技术使得开发者能够在不干扰主文档DOM结构的同时,‌对组件的内部进行详细的控制和定制。‌通过Shadow DOM,‌开发者可以更好地控制组件的外观和行为,‌同时保持代码的清晰和可维护性3。‌
  • 总的来说,‌Shadow Root是Web开发中一个强大的工具,‌它通过提供隔离的DOM树和样式封装,‌使得开发者能够创建更加模块化和可重用的Web组件,‌同时也有助于提高测试和自动化的效率。‌

本库把 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 ChromiumPage

page = ChromiumPage()
page.get('chrome://history/')

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

四、相对定位

相对定位是以一个已获取的元素为基准,在 DOM 树中获取相对于该元素的其它节点的技术。这种方法分为基于 DOM 和基于视觉两种方式。

4.1.基于 DOM 相对定位

以下方法可以以某元素为基准,在 DOM 中按照条件获取其直接子节点、同级节点、祖先元素、文档前后节点。这里说的是“节点”,不是“元素”。因为相对定位可以获取除元素外的其它节点,包括文本、注释节点。

4.1.1.获取父级元素

⑴.方法:parent()
  • parent() 方法用于获取当前元素的某一级父元素,可以通过层级数或定位符筛选特定的父元素。

参数:

  • level_or_loc:可为整数或字符串,指定获取第几级父元素,或通过定位符筛选祖先元素。
  • index:当 level_or_loc 为定位符时,指定返回第几个匹配的祖先元素。

返回类型:

  • ChromiumElement、SessionElement、NoneElement
案例:
# 获取 ele1 的第二层父元素
ele2 = ele1.parent(2)

# 获取 ele1 父元素中 id 为 id1 的元素
ele2 = ele1.parent('#id1')

说明: 在这个例子中,ele1.parent(2) 会获取 ele1 的第二级父元素,即从 ele1 开始向上追溯两层的元素。而 ele1.parent('#id1') 则会获取 ele1 的祖先元素中 idid1 的元素。

⑵.完整案例

通过百度搜索页面演示:

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位搜索框
search_box = page.ele("#kw")

# 获取 search_box 的父元素
parent_element = search_box.parent()
print("获取 search_box 的父元素:", parent_element)

# 获取search_box指定父级元素,例如 id=form 的父元素
parent_form = search_box.parent("@id=form")
print("获取id=form的父元素:", parent_form)

输出如下:

获取 search_box 的父元素: <ChromiumElement span class='bg s_ipt_wr new-pmd iptfocus quickdelete-wrap'>
获取id=form的父元素: <ChromiumElement form id='form' name='f' action='/s' class='fm  has-soutu'>

4.1.2.获取直接子节点

⑴.方法:child()

child() 方法返回当前元素的一个直接子节点,可以指定查询条件和第几个节点。

参数:

  • locator:字符串或元组,指定筛选子节点的查询条件。
  • index:整数,指定返回第几个匹配的子节点,可以为负数表示倒数第几个。
  • ele_only:布尔值,指定是否只查找元素节点。

返回类型:

  • str、ChromiumElement、SessionElement、NoneElement
# 获取 ele1 的第一个子元素
ele2 = ele1.child()

# 获取 ele1 的第三个 div 子元素
ele2 = ele1.child('tag:div', 3)

说明: ele1.child() 获取的是 ele1 的第一个直接子元素,而 ele1.child('tag:div', 3) 则是获取第三个 div 类型的子元素。

⑵.方法:children()

children() 方法返回当前元素的所有符合条件的直接子节点组成的列表。

# 获取 ele1 的所有子元素
ele2 = ele1.children()

# 获取 ele1 的所有 div 子元素
divs = ele1.children('tag:div')

说明: 这个方法可以一次性获取某个元素的所有符合条件的子元素。例如,ele1.children('tag:div') 会返回所有 div 类型的子元素。

⑶.完整案例
通过百度搜索页面,左上角超链接功能演示,页面如下:
from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位百度搜索页面左上角超链接
hyperlink = page.ele("@id=s-top-left")

# 获取第一个直接子节点
child_element = hyperlink.child()
print("获取第一个直接子节点:", child_element)

# 获取 hyperlink 的所有子元素
children_element = hyperlink.children()
print("获取 hyperlink 的所有子元素:", children_element)

# 获取 hyperlink 的所有 a 子元素
children_element_all_a = hyperlink.children("tag:a")
print("获取 hyperlink 的所有 a 子元素", children_element_all_a)

输出如下:

获取第一个直接子节点: <ChromiumElement a href='http://news.baidu.com' target='_blank' class='mnav c-font-normal c-color-t'>
获取 hyperlink 的所有子元素: [<ChromiumElement a href='http://news.baidu.com' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://www.hao123.com?src=from_pc' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='http://map.baidu.com' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='http://tieba.baidu.com/' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://haokan.baidu.com/?sfrom=baidu-top' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='http://image.baidu.com/' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://pan.baidu.com?from=1026962h' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://wenku.baidu.com/?fr=bdpcindex' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://chat.baidu.com/search?isShowHello=1&pd=csaitab&setype=csaitab&extParams=%7B%22enter_type%22%3A%22home_tab%22%7D' target='_blank' id='csaitab' class='mnav c-font-normal c-color-t'>, <ChromiumElement div class='mnav s-top-more-btn'>]
获取 hyperlink 的所有 a 子元素 [<ChromiumElement a href='http://news.baidu.com' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://www.hao123.com?src=from_pc' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='http://map.baidu.com' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='http://tieba.baidu.com/' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://haokan.baidu.com/?sfrom=baidu-top' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='http://image.baidu.com/' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://pan.baidu.com?from=1026962h' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://wenku.baidu.com/?fr=bdpcindex' target='_blank' class='mnav c-font-normal c-color-t'>, <ChromiumElement a href='https://chat.baidu.com/search?isShowHello=1&pd=csaitab&setype=csaitab&extParams=%7B%22enter_type%22%3A%22home_tab%22%7D' target='_blank' id='csaitab' class='mnav c-font-normal c-color-t'>]

4.1.3.获取同级节点

⑴.方法:next()

next() 方法返回当前元素后面的某一个同级节点。

参数:

  • locator:指定筛选条件
  • index:指定第几个符合条件的同级节点
  • ele_only:是否只查找元素节点

返回类型:

  • str、ChromiumElement、SessionElement、NoneElement
# 获取 ele1 后面第一个兄弟元素
ele2 = ele1.next()

# 获取 ele1 后面第 3 个 div 兄弟元素
ele2 = ele1.next('tag:div', 3)

说明: 通过 ele1.next() 可以获取到 ele1 后面的第一个兄弟元素,而 ele1.next('tag:div', 3) 则是获取第三个 div 类型的兄弟元素。

⑵.方法:prev()

prev() 方法与 next() 类似,但它返回的是当前元素前面的某一个同级节点。

# 获取 ele1 前面第一个兄弟元素
ele2 = ele1.prev()

# 获取 ele1 前面第 3 个 div 兄弟元素
ele2 = ele1.prev(3, 'tag:div')

说明: prev() 用于查找元素前面的同级节点。这个例子中,ele1.prev(3, 'tag:div') 将会返回 ele1 前面第 3 个 div 类型的兄弟元素。

⑶.完整案例

代码如下:

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位百度搜索页面左上角超链接
hyperlink = page.ele("@id=s-top-left")

# 获取 hyperlink 后面第一个兄弟元素
ele1 = hyperlink.next()
print("获取 hyperlink 后面第一个兄弟元素", ele1)

# 获取 hyperlink 后面第 3 个 div 兄弟元素
ele2 = hyperlink.next("tag:div", 3)
print("获取 hyperlink 后面第 3 个 div 兄弟元素", ele2)

# 获取 hyperlink 前面第一个兄弟元素
ele3 = hyperlink.prev()
print("获取 hyperlink 前面第一个兄弟元素", ele3)

# 获取 hyperlink 前面第 2 个 div 兄弟元素
ele4 = hyperlink.prev('tag:div', 2)
print("获取 hyperlink 前面第 2 个 div 兄弟元素", ele4)

输出如下:

获取 hyperlink 后面第一个兄弟元素 <ChromiumElement div id='u1' class='s-top-right s-isindex-wrap'>
获取 hyperlink 后面第 3 个 div 兄弟元素 <ChromiumElement div id='s_wrap' class='s-isindex-wrap'>
获取 hyperlink 前面第一个兄弟元素 <ChromiumElement div id='u'>
获取 hyperlink 前面第 2 个 div 兄弟元素 <ChromiumElement div id='s_top_wrap' class='s-top-wrap s-isindex-wrap '>

4.1.4.在文档中查找节点

⑴.方法:after()

after() 方法返回当前元素后面整个文档中的某一个节点,不限于同级。

# 获取 ele1 后面第 3 个元素
ele2 = ele1.after(index=3)

# 获取 ele1 后面第 3 个 div 元素
ele2 = ele1.after('tag:div', 3)

说明: 这个方法适用于需要跨越多个节点查找的情况,例如 ele1.after('tag:div', 3) 查找到的可能是 ele1 后面的第三个 div 元素,无论其层级如何。

⑵.方法:before()

before() 方法与 after() 类似,但它返回的是当前元素前面整个文档中的某一个节点。

# 获取 ele1 前面第 3 个元素
ele2 = ele1.before(3)

# 获取 ele1 前面第 3 个 div 元素
ele2 = ele1.before('tag:div', 3)

说明: 同样地,before() 方法用于查找文档中当前元素之前的节点,示例中的 ele1.before('tag:div', 3) 将会返回 ele1 前面第 3 个 div 元素。

⑶.完整案例

完整代码如下:

from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位百度搜索页面左上角超链接
hyperlink = page.ele("@id=s-top-left")

# 获取 hyperlink 后面第 3 个元素
ele1 = hyperlink.after(index=3)
print("获取 hyperlink 后面第 3 个元素", ele1)

# 获取 hyperlink 后面第 3 个 div 元素
ele2 = hyperlink.after('tag:div', 3)
print("获取 hyperlink 后面第 3 个 div 元素", ele2)

# 获取 hyperlink 前面第 3 个元素
ele3 = hyperlink.before(3)
print("获取 hyperlink 前面第 3 个元素", ele3)

# 获取 hyperlink 前面第 3 个 div 元素
ele4 = hyperlink.before('tag:div', 3)
print("获取 hyperlink 前面第 3 个 div 元素", ele4)

输出如下:

获取 hyperlink 后面第 3 个元素 <ChromiumElement a class='s-top-login-btn c-btn c-btn-primary c-btn-mini lb
            btn-fixed' style='position:relative;overflow: visible;' id='s-top-loginbtn' href='https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5' name='tj_login' onclick='return false;'>
获取 hyperlink 后面第 3 个 div 元素 <ChromiumElement div class='s-user-setting-pfmenu'>
获取 hyperlink 前面第 3 个元素 <ChromiumElement i class='c-icon c-icon-triangle-down'>
获取 hyperlink 前面第 3 个 div 元素 <ChromiumElement div class='s-center-box'>

4.2.基于视觉相对定位

下面方法可以以某元素为基准,向不同方向或指定偏移量获取元素。只有浏览器模式支持这类定位方式。只能获取可见的元素(不论是否在视口内),不能获取被遮挡的

4.2.1. east()

用于获取一个在当前元素右边的元素。

  • 可以通过 loc_or_pixel 参数指定定位符或距离(像素),并可通过 index 参数指定获取第几个元素。
  • loc_or_pixel参数可用定位符指定筛选条件,定位符只支持str格式,且不支持 xpath 和 css 方式。
  • index参数可指定获取第几个结果。如果loc_or_pixelNone,获取第若干个元素。
  • loc_or_pixelint格式时,直接获取元素右边这个距离的元素,此时index参数无效。距离从右边框开始计算。

参数:

参数名称类型默认值说明
loc_or_pixel str
int
None 定位符或距离(像素)
index int 1 第几个,从1开始,loc_or_pixelint格式时无效

返回值:

返回类型说明
ChromiumElement 找到的元素对象
NoneElement 未获取到结果时
假设你要获取一个搜索结果标题的右边的元素:定位百度搜索框右侧的元素
from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位百度搜索框
search_box = page.ele('#kw')
print(search_box)

# 获取 search_box 右边的第一个元素
ele1 = search_box.east()
print("获取search_box 右边的第一个元素:", ele1) 
# 获取 search_box 右边距离 200 像素的元素 
ele2 = search_box.east(200) 
print("获取 search_box 右边距离 200 像素的元素:", ele2)

输出如下:

<ChromiumElement input id='kw' name='wd' class='s_ipt' value='' maxlength='255' autocomplete='off'>
获取search_box 右边的第一个元素: <ChromiumElement input type='submit' id='su' value='百度一下' class='bg s_btn'>
获取 search_box 右边距离 200 像素的元素: <ChromiumElement div id='head_wrapper' class='head_wrapper s-isindex-wrap nologin'>

4.2.2.west()

用于获取一个在当前元素左边的元素。可以通过 loc_or_pixel 参数指定定位符或距离(像素),并可通过 index 参数指定获取第几个元素。

  • loc_or_pixel参数可用定位符指定筛选条件,定位符只支持str格式,且不支持 xpath 和 css 方式。
  • index参数可指定获取第几个结果。如果loc_or_pixelNone,获取第若干个元素。
  • loc_or_pixelint格式时,直接获取元素下边这个距离的元素,此时index参数无效。距离从下边框开始计算。
参数:
参数名称类型默认值说明
loc_or_pixel str
int
None 定位符或距离(像素)
index int 1 第几个,从1开始,loc_or_pixelint格式时无效
 
返回值:
返回类型说明
ChromiumElement 找到的元素对象
NoneElement 未获取到结果时
from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位“百度搜索框”
ele1 = page.ele('#kw')
print(ele1)

# 获取 button 右边的第一个元素
ele1 = ele.west()
print("获取 ele1 左边的第一个元素:", ele1)

# 获取 button 左边距离 200 像素的元素
ele2 = ele.west(200)
print("获取 ele1 左边距离 200 像素的元素:", ele2)

输出:

<ChromiumElement input id='kw' name='wd' class='s_ipt' value='' maxlength='255' autocomplete='off'>
获取 ele1 左边的第一个元素: <ChromiumElement div id='head_wrapper' class='head_wrapper s-isindex-wrap nologin'>
获取 ele1 左边距离 200 像素的元素: <ChromiumElement div id='head_wrapper' class='head_wrapper s-isindex-wrap nologin'>

4.2.3. south()

用于获取一个在当前元素下边的元素。可以通过 loc_or_pixel 参数指定定位符或距离(像素),并可通过 index 参数指定获取第几个元素。

  • loc_or_pixel参数可用定位符指定筛选条件,定位符只支持str格式,且不支持 xpath 和 css 方式。
  • index参数可指定获取第几个结果。如果loc_or_pixelNone,获取第若干个元素。
  • loc_or_pixelint格式时,直接获取元素上边这个距离的元素,此时index参数无效。距离从上边框开始计算
参数:
参数名称类型默认值说明
loc_or_pixel str
int
None 定位符或距离(像素)
index int 1 第几个,从1开始,loc_or_pixelint格式时无效
返回值:
返回类型说明
ChromiumElement 找到的元素对象
NoneElement 未获取到结果时
# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位百度搜索页面左上角超链接
hyperlink = page.ele("@id=s-top-left")

# 获取 hyperlink 下边的第一个元素
ele1 = hyperlink.south()
print("获取 ele1 下边的第一个元素:", ele1)

# 获取 hyperlink 下边距离 200 像素的元素
ele2 = hyperlink.south(200)
print("获取 ele1 下边距离 200 像素的元素:", ele2)

输出

获取 hyperlink 下边的第一个元素: <ChromiumElement div id='head_wrapper' class='head_wrapper s-isindex-wrap nologin'>
获取 hyperlink 下边距离 200 像素的元素: <ChromiumElement a class='text-color' href='http://ir.baidu.com' target='_blank'>

4.2.4. north()

用于获取一个在当前元素上边的元素。可以通过 loc_or_pixel 参数指定定位符或距离(像素),并可通过 index 参数指定获取第几个元素。

  • loc_or_pixel参数可用定位符指定筛选条件,定位符只支持str格式,且不支持 xpath 和 css 方式。
  • index参数可指定获取第几个结果。如果loc_or_pixelNone,获取第若干个元素。
  • loc_or_pixelint格式时,直接获取元素上边这个距离的元素,此时index参数无效。距离从上边框开始计算。
参数:
参数名称类型默认值说明
loc_or_pixel str
int
None 定位符或距离(像素)
index int 1 第几个,从1开始,loc_or_pixelint格式时无效
 
返回值:
返回类型说明
ChromiumElement 找到的元素对象
NoneElement 未获取到结果时
案例如下:
from DrissionPage import ChromiumPage

# 初始化 ChromiumPage
page = ChromiumPage()

# 打开百度首页
page.get("https://www.baidu.com")

# 定位百度搜索框
search_box = page.ele('#kw')
print(search_box)

# 获取 search_box 上边的第一个元素
ele1 = search_box.north()
print("获取 search_box 上边的第一个元素:", ele1)

# 获取 search_box 上边距离 150 像素的元素
ele2 = search_box.north(150)
print("获取 search_box 上边距离 150 像素的元素:", ele2)

如果不存在,则显示None,输出如下:

<ChromiumElement input id='kw' name='wd' class='s_ipt' value='' maxlength='255' autocomplete='off'>
获取 search_box 上边的第一个元素: <ChromiumElement div id='lg' class='s-p-top'>
获取 search_box 上边距离 150 像素的元素: None

4.2.5.offset()

用于获取相对于当前元素左上角指定偏移量的一个元素。offset_xoffset_y 分别表示横坐标和纵坐标的偏移量。

参数:

参数名称类型默认值说明
offset_x int 必填 横坐标偏移量(像素),向右为正
offset_y int 必填 纵坐标偏移量(像素),向下为正
返回值:
返回类型说明
ChromiumElement 找到的元素对象
NoneElement 未获取到结果时

示例:假设你要获取相对于搜索结果标题左上角偏移 50 像素向右和 100 像素向下的元素:

# 假设 ele1 是当前的搜索结果标题元素
ele1 = driver.find_element_by_id('result-title')

# 获取相对于 ele1 左上角偏移 50 像素向右和 100 像素向下的元素
offset_element = ele1.offset(50, 100)

4.2.6. over()

用于获取覆盖在当前元素上最上层的元素。可以通过 timeout 参数设置等待元素出现的超时时间。

参数:

参数名称类型默认值说明
timeout float None 等待元素出现的超时时间(秒),为None使用页面timeout设置值

返回值:

返回类型说明
ChromiumElement 找到的元素对象
NoneElement 未获取到结果时

示例:假设你要获取覆盖在搜索结果标题上最上层的元素:

# 假设 ele1 是当前的搜索结果标题元素
ele1 = driver.find_element_by_id('result-title')

# 获取覆盖在 ele1 上的最上层元素,等待最多 5 秒
top_element = ele1.over(timeout=5)

五、行为模式

5.1.等待元素

在网页自动化测试中,由于网络延迟或页面中JavaScript执行时间的不确定性,经常需要等待元素加载到DOM中才能对其进行操作。DrissionPage提供了两种等待方式:内置等待主动等待,以确保元素在操作前已经完全加载并可用。

5.1.1.内置等待

内置等待是指在查找元素时自动等待元素加载到DOM中,等待时间可以根据需要设置。

作用:

  • 通过内置等待机制,自动延迟操作,直至元素加载完成,从而减少因元素尚未加载而导致的错误或异常。
  • 内置等待的默认时间与页面的超时时间一致,但可以在每次查找时单独设置等待时间,以适应不同的需求。

用法:

from DrissionPage import ChromiumPage

# 页面初始化时设置查找元素超时时间为 15 秒
page = ChromiumPage(timeout=15)
page.get("https://www.baidu.com")

# 设置查找元素超时时间为 5 秒
page.set.timeouts(5)

# 使用页面超时时间(5 秒)查找元素
ele1 = page.ele("#kw")
ele1.input("演唱会")

# 为这次查找页面独立设置等待时间(1 秒)
page.ele("#su", timeout=1).click()

5.1.2.主动等待

页面对象的wait.eles_loaded()方法,可主动等待指定元素加载到 DOM。

from DrissionPage import ChromiumPage

page = ChromiumPage()
# 打开页面
page.get("https://www.baidu.com")

# 等待指定的元素加载完成, 返回的是true或者false
outcome = page.wait.eles_loaded("#kw", 15)
print(outcome)

5.2.链式写法

因为元素对象本身又可以查找对象,所有可实现多级链式操作,可使程序更简洁。

ele = tab.ele('#s_fm').ele('#su')

其中ele()可省略,简化写成:

ele = tab('#s_fm')('#su')
完整案例如下:
from DrissionPage import ChromiumPage

page = ChromiumPage()
# 打开页面
page.get("https://www.baidu.com")

# 使用链式写法找到百度搜索页面左上角,点击调转到新闻页面
page('@id=s-top-left')('@href=http://news.baidu.com').click()

5.3.找不到元素时

5.3.1.默认情况

默认情况下,找不到元素时不会立即抛出异常,而是返回一个NoneElement对象。这个对象用if判断表现为False,调用其功能会抛出ElementNotFoundError异常。

这样可以用if判断是否找到元素,也可以用try去捕获异常。查找多个元素找不到时,返回空的list

from DrissionPage import ChromiumPage
from DrissionPage.errors import ElementNotFoundError

page = ChromiumPage()
# 打开页面
page.get("https://www.baidu.com")

# 定位不存在的元素
ele = page.ele("#ki")

# 异常捕获
try:
    ele.click()
except ElementNotFoundError as e:
    print("元素没有找到:", e)

输出如下:

元素没有找到: 
没有找到元素。
method: ele()
args: {'locator': '#ki', 'index': 1}

5.3.2.立即抛出异常

如果想在找不到元素时立刻抛出异常,可以用以下方法设置。此设置为全局有效,在项目开始时设置一次即可。查找多个元素找不到时,依然返回空的list

设置全局变量:如果需要在找不到元素时立即抛出异常,可以在项目开始时设置全局变量:

from DrissionPage.common import Settings

Settings.raise_when_ele_not_found = True

示例:设置全局变量后,即可立即抛出异常,

from DrissionPage import ChromiumPage
from DrissionPage.common import Settings

Settings.raise_when_ele_not_found = True

page = ChromiumPage(timeout=1)
page.get('https://www.baidu.com')
ele = page('#abcd')  # 这个元素不存在

抛出异常如下:

5.3.3.设置默认返回值

设置默认返回值:如果不希望在元素找不到时抛出异常,可以设置一个默认返回值,我这里是官方案例自己编写案例均是有问题存在bug

示例:比如说,遍历页面上一个列表中多个对象,但其中有些元素可能缺失某个子元素,可以这样写: 

from DrissionPage import ChromiumPage

page = ChromiumPage()
page.set.NoneElement_value('没找到')
for li in page.eles('t:li'):
    name = li('.name').text
    age = li('.age').text
    phone = li('.phone').text

假如某个子元素不存在,不会抛出异常,而是返回'没找到'这个字符串。

posted @ 2019-08-02 15:16  酒剑仙*  阅读(532)  评论(0)    收藏  举报