前言
现在的网站越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出了。如果实际⻚⾯等待时间过⻓导致某个dom元素还没出来,但是你的代码直接使⽤了这个WebElement,那么就会抛出NullPointer的异常。还有些情况是你打开一个网站,比如你的网速比较慢,网页还没有加载出来,你的代码就已经执行了。这个时候你的程序就会报错。为了解决这个问题。所以 Selenium 提供了两种等待⽅式:一种是隐式等待、一种是显式等待。
实战
隐式等待
我们以前解决这些问题的时候,都是使用python自带的time模块中来实现强制等待2秒。我们用代码来演示一下
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
time.sleep(2)
driver.find_element_by_id('kw').send_keys('python')
执行结果
这种属于强制等待,无论成功与否都要等待2秒。我们在代码中尽量少写,这会让我们代码性能显的非常不好那我们来看一下隐式等待。
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
driver.implicitly_wait(2)
driver.find_element_by_id('kw').send_keys('python')
执行结果
效果是差不多的。但是我们没有等待2秒,而是直接打开了这个页面。所以隐式等待如果我找到了标签我就直接打开,没有找到就等待2秒接着去找,没有找到就抛出异常了。所以隐式等待还是比较友好的
显示等待
显示等待需要用到一个类
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
实例代码
driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
这个代码是什么意思?就是传递一个驱动和时间。until是我们的这个条件。EC是我们上面的那个期望条件设置的别名。 proesence_of_element_located 条件出现的一个方式 比如我们这个方式就是通过id来查找 。那么id是什么呢?就是后面的这个myDynamicElement
下面我们用12306这个网站来演示一下 假如我们要去买票,肯定是要填写好出发地 目的地和出发日期
需要注意的是12306这个input标签和普通的input标签有点不一样。它并不是来读取我们这个里面的长沙和北京的 而是根据它里面的一个 value值 CSQ就是长沙的代号。所以你在查询的时候它就是根据这个代号进行操作的,就非常的麻烦
那么我们可以这样做。就是我在点击查询之前,先去等待一下。这个出发地和目的地的数据出现。如果出现了,我就点击这个查询操作
我们先去获取下这个查询的按钮
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
# 显示等待
driver.get('https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc')
# 定位查询按钮
btn = driver.find_element_by_id('query_ticket')
btn.click()
这个时候就告诉我们 出发地和目的地必须填写才可以点击查询。那么这一块我们就可以用显示等待
那么我们的这个条件是什么 例如我的出发地里面要输入长沙这2个字
# 出发地的条件
WebDriverWait(driver,100).until(
EC.text_to_be_present_in_element_value((By.ID,'fromStationText'),'长沙')
)
下面就是目的地的条件原理是一样的
# 目的地的条件
WebDriverWait(driver,100).until(
EC.text_to_be_present_in_element_value((By.ID,'toStationText'),'北京')
)
个条件都成立,我们才点击查询 运行
这个就是我们想要的效果了。效果出来了,还不赶紧动手试一试。