等待界面元素出现
在我们进行网页操作的时候, 有的元素内容不是可以立即出现的, 可能会等待一段时间。
比如 我们的股票搜索示例页面, 搜索一个股票名称, 我们点击搜索后, 浏览器需要把这个搜索请求发送给服务器, 服务器进行处理后,再把搜索结果返回给我们。
所以,从点击搜索到得到结果,需要一定的时间,
只是通常 服务器的处理比较快,我们感觉好像是立即出现了搜索结果。
搜索的每个结果 对应的界面元素 其ID 分别是数字 1, 2 ,3, 4 。。。
我们可以先用如下代码 将 第一个搜索结果里面的文本内容 打印出来
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('https://www.byhy.net/_files/stock1.html')
element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')
# 返回页面 ID为1 的元素
element = wd.find_element(By.ID,'1')
# 打印该元素的文字内容
print(element.text)
如果大家去运行一下,就会发现有如下异常抛出
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="1"]"}
NoSuchElementException
的意思就是在当前的网页上 找不到该元素, 就是找不到 id 为 1 的元素。
为什么呢?
因为我们的代码执行的速度比 网站响应的速度 快。
网站还没有来得及 返回搜索结果,我们就执行了如下代码
element = wd.find_element(By.ID, '1')
在那短暂的瞬间, 网页上是没有用 id为1的元素的 (因为还没有搜索结果呢)。自然就会报告错误 id为1 的元素不存在了。
那么怎么解决这个问题呢?
可以想到, 点击搜索后, 用sleep 来 等待几秒钟, 等百度服务器返回结果后,再去选择 id 为1 的元素, 就像下面这样
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('https://www.byhy.net/_files/stock1.html')
element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')
# 等待 1 秒
from time import sleep
sleep(1)
element = wd.find_element(By.ID,'1')
print(element.text)
大家可以运行一下,基本是可以的,不会再报错了。
但是这样的方法 有个很大的问题,就是:设置等待多长时间合适呢?
Selenium提供了一个更合理的解决方案,是这样的:
当发现元素没有找到的时候, 并不立即返回 找不到元素的错误。
而是周期性(每隔半秒钟)重新寻找该元素,直到该元素找到,
或者超出指定最大等待时长,这时才 抛出异常(如果是 find_elements
之类的方法, 则是返回空列表)。
Selenium 的 Webdriver 对象 有个方法叫 implicitly_wait
,可以称之为 隐式等待
,或者 全局等待
。
该方法接受一个参数, 用来指定 最大等待时长。
如果我们 加入如下代码
wd.implicitly_wait(10)
那么后续所有的 find_element
或者 find_elements
之类的方法调用 都会采用上面的策略:
如果找不到元素, 每隔 半秒钟 再去界面上查看一次, 直到找到该元素, 或者 过了10秒 最大时长。
这样,我们的百度搜索的例子的最终代码如下
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.implicitly_wait(10)
wd.get('https://www.byhy.net/_files/stock1.html')
element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')
# 返回页面 ID为1 的元素
element = wd.find_element(By.ID,'1')
print(element.text)
大家再运行一下,可以发现不会有错误了。
那么是不是有了 implicitwait
, 可以彻底不用sleep了呢?
不是的,有的时候我们等待元素出现,仍然需要sleep。
选择到元素之后,我们的代码会返回元素对应的 WebElement对象,通过这个对象,我们就可以 操控
元素了。
操控元素通常包括
-
点击元素
-
在元素中输入字符串,通常是对输入框这样的元素
-
获取元素包含的信息,比如文本内容,元素的属性
6、点击元素
点击元素
非常简单,就是调用元素WebElement对象的 click方法。前面我们已经学过。
这里我们要补充讲解一点。
当我们调用 WebElement 对象的 click 方法去点击 元素的时候, 浏览器接收到自动化命令,点击的是该元素的 中心点
位置 。
例如,对于下面的这样一个元素
我们要点击 添加客户 这个按钮,既可以点击 右边对应的 绿色框子总的button 元素 ,也可以点击红色框子中的span元素 。
因为这两个元素的中心点都是 button 内部,都是有效点击区域
7、输入框
输入字符串
也非常简单,就是调用元素WebElement对象的send_keys方法。前面我们也已经学过。
如果要 把输入框中已经有的内容清除掉,可以使用WebElement对象的clear方法
请大家点击打开这个网址
并且按F12,观察HTML的内容
我们要写一个自动化程序:要求在输入框中填入姓名:白月黑羽。
而且要做到输入框中已经有的提示字符,需要先 清除掉
代码应该如下
1 2 3 4 | |
8、获取元素信息
获取元素的文本内容
上一章,我们已经知道,通过WebElement对象的 text
属性,可以获取元素 展示在界面上的
文本内容。
比如
element = wd.find_element(By.ID, 'animal')
print(element.text)
获取元素属性
通过WebElement对象的 get_attribute
方法来获取元素的属性值
比如要获取元素属性class的值,就可以使用 element.get_attribute('class')
如下:
element = wd.find_element(By.ID, 'input_name')
print(element.get_attribute('class'))
执行完自动化代码,如果想关闭浏览器窗口可以调用WebDriver对象的 quit 方法,像这样 wd.quit()
获取整个元素对应的HTML
要获取整个元素对应的HTML文本内容,可以使用 element.get_attribute('outerHTML')
如果,只是想获取某个元素 内部
的HTML文本内容,可以使用 element.get_attribute('innerHTML')
获取输入框里面的文字
对于input输入框的元素,要获取里面的输入文本,用text属性是不行的,这时可以使用 element.get_attribute('value')
比如
element = wd.find_element(By.ID, "input1")
print(element.get_attribute('value')) # 获取输入框中的文本
获取元素文本内容2
通过WebElement对象的 text
属性,可以获取元素 展示在界面上的
文本内容。
但是,有时候,元素的文本内容没有展示在界面上,或者没有完全完全展示在界面上。 这时,用WebElement对象的text属性,获取文本内容,就会有问题。
出现这种情况,可以尝试使用 element.get_attribute('innerText')
,或者 element.get_attribute('textContent')
使用 innerText 和 textContent 的区别是,前者只显示元素可见文本内容,后者显示所有内容(包括display属性为none的部分)
具体可以参考这里
注意
如果您了解web前端开发,可以知晓一下:
get_attribute 调用本质上就是调用 HTMLElement 对像的属性
比如
element.get_attribute('value') 等价于js里面的 element.value
element.get_attribute('innerText') 等价于js里面的 element.innerText