ChromiumPage(二)

一、点击元素

click()和click.left()

这两个方法作用是一样的,用于左键点击元素。可选择模拟点击或 js 点击。

参数:

数名称类型默认值说明
by_js bool False 指定点击行为方式。
None时,如不被遮挡,用模拟点击,否则用 js 点击
True时直接用 js 点击;
False时强制模拟点击,被遮挡也会进行点击
timeout float 1.5 模拟点击的超时时间,等待元素可见、可用、进入视口
wait_stop bool True 点击前是否等待元素停止运动

返回值:

返回值说明
False by_jsFalse,且元素不可用、不可见时,返回False
True 除以上情况,其余情况都返回True
# 对ele元素进行模拟点击,如判断被遮挡也会点击
ele.click()

# 用js方式点击ele元素,无视遮罩层
ele.click(by_js=True)

# 如元素不被遮挡,用模拟点击,否则用js点击
ele.click(by_js=None)

说明:

  • 默认情况下,by_jsNone,优先用模拟方式点击,如遇遮挡、元素不可用、不可见、无法自动进入视口,等待直到超时后自动改用 js 方式点击。
  • by_jsFalse,程序会强制使用模拟点击,即使被遮挡也会点击元素位置。如果元素不可见、不可用,会返回False。如元素无法自动滚动到视口,会改用 js 点击。
  • by_jsTrue时,则可无视任何遮挡,只要元素在 DOM 内,就能点击得到,但元素是否响应点击视网页所用架构而定。

可以根据需要灵活地对元素进行操作。在模拟点击前,程序会先尝试把元素滚动到视口中。

默认情况下,如无法进行模拟点击(元素无法进入视口、不可用、隐藏)时,左键单击会返回False。但也可以通过全局设置使其抛出异常:

from DrissionPage.common import Settings

Settings.raise_click_failed = True
ele.click()  # 如无法点击则抛出异常

二、输入内容

2.1.clear()

此方法用于清空元素文本,可选择模拟按键或 js 方式。模拟按键方式会自动输入ctrl-a-del组合键来清除文本框,js 方式则直接把元素value属性设置为''。

参数名称类型默认值说明
by_js bool False 是否用 js 方式清空

返回:None

示例:

ele.clear()

2.2.input()

此方法用于向元素输入文本或组合键,也可用于输入文件路径到上传控件。可选择输入前是否清空元素。

参数名称类型默认值说明
vals Any False 文本值或按键组合
对文件上传控件时输入路径字符串或其组成的列表
clear bool False 输入前是否清空文本框
by_js bool False 是否用 js 方式输入,为True时不能输入组合键


返回:None

Tips

  • 有些文本框可以接收回车代替点击按钮,可以直接在文本末尾加上'\n'。
  • 会自动把非str数据转换为str。

示例:

# 输入文本
ele.input('Hello world!')

# 输入文本并回车
ele.input('Hello world!\n')

2.3.输入组合键

使用组合键或要传入特殊按键前,先要导入按键类Keys。

from DrissionPage.common import Keys

然后将组合键放在一个tuple中传入input()即可。

ele.input((Keys.CTRL, 'a', Keys.DEL)) # ctrl+a+del

Keys内置了 5 个常用组合键,分别为CTRL_A、CTRL_C、CTRL_X、CTRL_V、CTRL_Z、CTRL_Y。

ele.input(Keys.CTRL_A) # 全选

2.4.focus()

此方法用于使元素获取焦点。无参数和返回值

2.5.完整案例

from DrissionPage.common import Keys
from DrissionPage import ChromiumPage

page = ChromiumPage()
page.get("https://www.baidu.com")

# 输入文本并回车
search_box = page("#kw")
# 使元素获取焦点
search_box.focus()
search_box.input("hello world!\n")

# 输入文本并回车,通过回车键实现
# search_box.input(("zs", Keys.ENTER))

三、拖拽和悬停

3.1.drag()

此方法用于拖拽元素到相对于当前的一个新位置,可以设置速度。

参数名称类型默认值说明
offset_x int 0 x 轴偏移量,向下向右为正
offset_y int 0 y 轴偏移量,向下向右为正
duration float 0.5 用时,单位秒,传入0即瞬间到达

返回:None

示例:

# 拖动当前元素到距离50*50的位置,用时1秒
ele.drag(50, 50, 1)

3.2.drag_to()

此方法用于拖拽元素到另一个元素上或一个坐标上。

参数名称类型默认值说明
ele_or_loc ChromiumElement
Tuple[int, int]
必填 另一个元素对象或坐标元组
duration float 0.5 用时,单位秒,传入0即瞬间到达

返回:None

示例:

# 把 ele1 拖拽到 ele2 上
ele1 = page.ele('#div1')
ele2 = page.ele('#div2')
ele1.drag_to(ele2)

# 把 ele1 拖拽到网页 50, 50 的位置
ele1.drag_to((50, 50))

3.3.hover()

此方法用于模拟鼠标悬停在元素上,可接受偏移量,偏移量相对于元素左上角坐标。不传入offset_x和offset_y值时悬停在元素中点。

参数名称类型默认值说明
offset_x int None 相对元素左上角坐标的 x 轴偏移量,向下向右为正
offset_y int None 相对元素左上角坐标的 y 轴偏移量,向下向右为正

返回:None

示例1:

# 悬停在元素右上方 50*50 的位置
ele.hover(50, -50)

# 悬停在元素上中部,x 相对左上角向右偏移50,y 保持在元素中点
ele.hover(offset_x=50)

# 悬停在元素中点
ele.hover()

示例2:

from DrissionPage import ChromiumPage

page = ChromiumPage()
# 设置浏览器最大化
page.set.window.max()

page.get("https://www.baidu.com")

# 定位设置按钮
ele = page("#s-usersetting-top")
print(ele.html)
# 设置悬停
ele.hover()

效果如下:

四、下拉选择框处理

我们通常会遇到两种下拉框,一种使用的是html的标签select,另一种是使用input标签做的假下拉框,后者我们通常的处理方式与其他的元素类似,点击或使用JS等。而对于前者,DrissionPage给了有力的支持,新建select.html页面

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>下拉选择框练习</title>
    </head>
    <body>
        <script>
        function oc(){
            alert(document.f1.t1.value());
        }
        </script>
        <form>
        搜索引擎:
        <select id="s1Id">
            <option></option>
            <option value="o1" id="id1">谷歌搜索</option>
            <option value="o2" id="id2">必应搜索</option>
            <option value="o3" id="id3">搜狗搜索</option>
            <option value="o4" id="id3">百度搜索</option>
        </select>
        </form>
    </body>
</html>

4.1.select()和select.by_text()

这两个方法功能一样,用于按文本选择列表项。如为多选列表,可多选。

参数名称类型默认值说明
text str
list
tuple
必填 作为选择条件的文本,传入listtuple可选择多项
timeout float None 超时时间,为None默认使用页面超时时间
返回类型说明
bool 是否选择成功

示例:

from DrissionPage import ChromiumPage
import os


# 文件路径生成
file_path = 'file:///' + os.path.abspath('select.html')

page = ChromiumPage()
# 设置浏览器最大化
page.set.window.max()

# 打开页面
page.get(file_path)

# 定位<select>元素
select_element = page("#s1Id")
# 选择显示文本为'搜狗搜索'的<option>
select_element.select("搜狗搜索")

4.2.select.by_value()

此方法用于按value属性选择列表项。如为多选列表,可多选。

参数名称类型默认值说明
locator str
list
tuple
必填 定位符,传入listtuple可选择多项
timeout float None 超时时间,为None默认使用页面超时时间
返回类型说明
bool 是否选择成功

示例:

from DrissionPage import ChromiumPage
import os


# 文件路径生成
file_path = 'file:///' + os.path.abspath('select.html')

page = ChromiumPage()
# 设置浏览器最大化
page.set.window.max()

# 打开页面
page.get(file_path)

# ***************通过文本选择*******************
# 定位<select>元素
# select_element = page("#s1Id")
# # 选择显示文本为'搜狗搜索'的<option>
# select_element.select("搜狗搜索")

# ***************通过value属性选择*******************
# 定位<select>元素
select_element = page("#s1Id")
# 选择显示文本为'搜狗搜索'的<option>
select_element.select.by_value("o4")

4.3.select.by_index()

此方法用于按序号选择列表项,从1开始。如为多选列表,可多选。

参数名称类型默认值说明
index int
list
tuple
必填 选择第几项,传入listtuple可选择多项
timeout float None 超时时间,为None默认使用页面超时时间
返回类型说明
bool 是否选择成功

示例:

from DrissionPage import ChromiumPage
import os

# 文件路径生成
file_path = 'file:///' + os.path.abspath('select.html')

page = ChromiumPage()
# 设置浏览器最大化
page.set.window.max()

# 打开页面
page.get(file_path)

# ***************通过文本选择*******************
# 定位<select>元素
# select_element = page("#s1Id")
# # 选择显示文本为'搜狗搜索'的<option>
# select_element.select("搜狗搜索")

# ***************通过value属性选择*******************
# 定位<select>元素
# select_element = page("#s1Id")
# 选择显示文本为'搜狗搜索'的<option>
# select_element.select.by_value("o4")

# ***************通过索引选择*******************
# 定位<select>元素
select_element = page("#s1Id")
select_element.select.by_index(3)  # 选择第三个<option>(索引从1开始)

五、设置元素等待

在自动化过程中,经常遇到网络环境不稳定,页面 js 运行时间也难以确定的情况。如果总是用sleep(),显得不太优雅,等待多了浪费时间,等待不够会导致报错。因此,程序能够智能等待是非常重要的,DrissionPage 内置了一些等待方法,可以提高程序稳定性和效率。它们藏在页面对象和元素对象的wait属性里。等待方法均有timeout参数,可自行设得超时时间,也可以设置超时后返回False还是抛出异常。

​5.1.wait.load_start()

此方法用于等待页面进入加载状态。

我们经常会通过点击元素进入下一个网页,并立刻获取新页面的元素。但若跳转前的页面拥有和跳转后页面相同定位符的元素,会导致过早获取元素,跳转后失效的问题。使用此方法,会阻塞程序,等待页面开始加载后再继续,从而避免上述问题。我们通常只需等待页面加载开始,程序会自动等待加载结束。

注意
  • get()已内置等待加载开始,后无须跟wait.load_start()
参数名称类型默认值说明
timeout float
None
True
None 超时时间,为NoneTure时使用页面timeout设置
为数字时等待相应时间
raise_err bool None 等待失败时是否报错,为None时根据Settings设置
返回类型说明
bool 等待结束时是否进入加载状态

示例:

ele.click()  # 点击某个元素
page.wait.load_start()  # 等待页面进入加载状态
# 执行在新页面的操作
print(page.title)

5.2.wait.doc_loaded()

用于等待页面文档加载完成。一般来说都无需开发者使用,程序大部分动作都会自动等待加载完成再执行。

注意

  • 此功能仅用于等待页面主 document 加载,不能用于等待 js 加载的变化。
  • 除非load_mode为None,get()方法已内置等待加载完成,后面无须添加等待。
名称类型默认值说明
timeout float
None
True
None 超时时间,为NoneTure时使用页面timeout设置
为数字时等待相应时间
raise_err bool None 等待失败时是否报错,为None时根据Settings设置
返回类型说明
bool 等待结束时是否完成加载完成

5.3.wait.eles_loaded()

此方法用于等待元素被加载到 DOM,可等待全部或任意一个加载。有时一个元素的正常出现是下一步操作的前提,用此方法可以防止一些元素加载速度慢于程序动作速度导致的误操作。

参数名称类型默认值说明
locator str
Tuple[str, str]
list
必填 要等待的元素,定位符
timeout float None 超时时间,为None时使用页面timeout设置
any_one bool False 是否等待到一个就返回
raise_err bool None 等待失败时是否报错,为None时根据Settings设置
返回类型说明
bool 是否等待成功

示例:

ele1.click()  # 点击某个元素
page.wait.eles_loaded('#div1')  # 等待 id 为 div1 的元素加载
ele2.click()  # div1 加载完成后再执行下一步操作

5.4.wait.ele_displayed()

此方法用于等待一个元素变成显示状态。

  • 如果当前 DOM 中查找不到指定元素,则会自动等待元素加载,再等待它显示。
  • 元素隐藏是指元素在 DOM 内,但处于隐藏状态(即使在视口内且不被遮挡)。
  • 父元素隐藏时子元素也是隐藏的。
参数名称类型默认值说明
loc_or_ele str
Tuple[str, str]
ChromiumElement
必填 要等待的元素,可以是元素或定位符
timeout float None 超时时间,为None时使用页面timeout设置
raise_err bool None 等待失败时是否报错,为None时根据Settings设置
返回类型说明
bool 是否等待成功

示例:

# 等待 id 为 div1 的元素显示,超时使用页面设置
page.wait.ele_displayed('#div1')

# 等待 id 为 div1 的元素显示,设置超时3秒
page.wait.ele_displayed('#div1', timeout=3)

# 等待已获取到的元素被显示
ele = page.ele('#div1')
page.wait.ele_displayed(ele)

5.5.wait()

此方法用于等待若干秒。

  • scope为None时,效果与time.sleep()没有区别,等待指定秒数。
  • scope不为None时,获取两个参数之间的一个随机值,等待这个数值的秒数。
参数名称类型默认值说明
second float 必填 要等待的秒数,scope不为None时表示随机数范围起始值
scope float None 随机数范围结束值

返回:None

示例:

ele.wait(1)  # 强制等待1秒

ele.wait(3.5, 8.5)  # 获取3.5至8.5之间的一个随机数,等待这个数值的秒数

六、文件上传

上传文件有两种方式:

  • 拦截文件输入框,自动填入路径
  • 找到<input>元素,填入文件路径

创建upfile.html文件,代码如下:

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>upload_file</title>
<link href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
  <div class="row-fluid">
    <div class="span6 well">
    <h3>upload_file</h3>
      <input type="file" name="file" />
    </div>
  </div>
</body>
<script src="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.js"></scrip>
</html>

6.1.自然的交互

传统自动化工具的文件上传,需要开发者在 DOM 里找到文件上传控件,然后用元素对象的input()方法填入路径。有些上传控件是临时加载的,有些藏得很深,找起来费时费力。DrissionPage提供一种自然的文件上传方式,无需在 DOM 里找控件,只要自然地点击触发文件选择框,程序就能主动截获,并填写设定好的路径,开发更省事。

6.1.1.click.to_upload()

浏览器元素对象拥有此方法,用于上传文件到网页。

参数名称类型默认值说明
file_paths str
Path
list
tuple
必填 文件路径,如果上传框支持多文件,可传入列表或字符串,字符串时多个文件用\n分隔
by_js bool False 是否用 js 方式点击,逻辑与click()一致

返回:None

示例1

from DrissionPage import ChromiumPage

page = ChromiumPage()
ele = page('#uploadButton')
ele.click.to_upload(r'C:\text.txt')

示例2:通过上面准备的HTML实现的上传文件框实现

from DrissionPage import ChromiumPage
import os

# 文件路径生成
file_path = 'file:///' + os.path.abspath('upfile.html')

page = ChromiumPage()
# 设置浏览器最大化
page.set.window.max()

# 打开页面
page.get(file_path)

# 定位文件输入框
ele = page("@name=file")
# 上传文件
ele.click.to_upload(r"D:\jenkins.war")

6.1.2.手动方式

上面的方法使用默认点击方式触发上传,假如页面要求其它触发方式,可自行手动写上传逻辑。

步骤:

  • 设置要上传的文件路径,多路径传入list、tuple或以\n分隔的字符串
  • 点击会触发文件选择框的按钮
  • 调用等待录入语句,确保输入完整

示例1:

# 设置要上传的文件路径
page.set.upload_files('demo.txt')
# 点击触发文件选择框按钮
btn_ele.click()
# 等待路径填入
page.wait.upload_paths_inputted()

点击按钮后,文本选择框被拦截不会弹出,但可以看到文件路径已经传入其中。由于此动作是异步输入,需显式等待输入完成才进行下一步操作。

示例2:

from DrissionPage import ChromiumPage
import os

# 文件路径生成
file_path = 'file:///' + os.path.abspath('upfile.html')

page = ChromiumPage()
# 设置浏览器最大化
page.set.window.max()

# 打开页面
page.get(file_path)

# 设置要上传的文件路径
page.set.upload_files(r"D:\jenkins.war")

# 定位文件输入框
page("@name=file").click()
# 等待路径填入
page.wait.upload_paths_inputted()

6.1.3.注意事项

如果您要操作的上传控件在一个异域的<iframe>,那必需用这个<iframe>对象来设置上传路径,而不能用页面对象设置。

❌ 错误做法:

page.set.upload_paths('demo.txt')
page.get_frame(1).ele('@type=file').click()
page.wait.upload_paths_inputted()

⭕ 正确做法:

iframe = page.get_frame(1)
iframe.set.upload_paths('demo.txt')
iframe.ele('@type=file').click()
iframe.wait.upload_paths_inputted()

如果<iframe>和主页面是同域的,则用域名对象和<iframe>对象设置均可。

6.2.传统方式

传统方式,需要开发者在 DOM 里找到文件上传控件,然后用元素对象的input()方法填入路径。文件上传控件是type属性为'file'的<input>元素进行输入,把文件路径输入到元素即可,用法与输入文本一致。稍有不同的是,无论clear参数是什么,都会清空原控件内容。如果控件支持多文件上传,多个路径用list、tuple或以\n分隔的字符串传入。

upload = page('tag:input@type=file')

# 传入一个路径
upload.input('D:\\test1.txt')

# 传入多个路径,方式 1
paths = 'D:\\test1.txt\nD:\\test2.txt'
upload.input(paths)

# 传入多个路径,方式 2
paths = ['D:\\test1.txt', 'D:\\test2.txt']
upload.input(paths)

如果<input>元素很好找,这种方式是很简便的。有些<input>是临时加载的,或者经过修饰隐藏很深,找起来很费劲。万一有些上传是用 js 控制的,这种方式未必能奏效。

from DrissionPage import ChromiumPage
import os

# 文件路径生成
file_path = 'file:///' + os.path.abspath('upfile.html')

page = ChromiumPage()
# 设置浏览器最大化
page.set.window.max()

# 打开页面
page.get(file_path)

# 设置要上传的文件路径
page.set.upload_files(r"D:\jenkins.war")

# 定位文件输入框
page("@name=file").click()
# 等待路径填入
page.wait.upload_paths_inputted()

 

posted @ 2019-11-05 14:29  酒剑仙*  阅读(504)  评论(0)    收藏  举报