Selenium 等待响应

背景

  • 写了些程序,发现网页的等待很有问题,要么等的时间不够长,要么等的时间太长了。所以专门上网查了一下等待。

强制等待

time.sleep(5)
  • 这个叫做强制等待。就是让程序等待 5s ,不管网页有没有渲染完,就等 5s,然后继续执行。

隐性等待

driver.implicitly_wait(30)
  • 这个叫做隐性等待,就是最多等网页 30s,如果网页提前加载完毕了,就继续执行,否则到了 30s,就执行。
  • 还有之前的一个盲区:这个隐形等待整个 driver 只要写一次,不是和 sleep 一样哪都要写的。
  • 这个有一点小问题,就是有时候我们想要的元素已经加载完毕了,但是整个网页还有一些其他的东西木有加载完,就会浪费时间。

显性等待

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get('https://huilansame.github.io')
locator = (By.LINK_TEXT, 'CSDN')

try:
    WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator))
    print driver.find_element_by_link_text('CSDN').get_attribute('href')
finally:
    driver.close()
  • 这段例子一下子引入 3 个之前没有用过的包,我们先看一下都是啥意思:
WebDriverWait
  • 上面那个函数的意思是,在最长 20s 中,每隔 0.5s 检查后面那个 EC 函数,知道后面那个函数返回真。
  • 是不是很好理解,这就是最基本的用法,完整的函数如下:
WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时时返回的信息)
  • 忽略异常是一个元组,如果 until 抛出这个元组之外的异常,就会报错。
  • until 可以换成 until_not,意思就是逻辑相反。
by
  • 这里面的 locator 元组其实不是新东西,就是之前我们定位用到的 find_element_by 这个意思,也就是寻找元素的方法。特别注意,这个 locator 不能直接用 driver.find_element 来替代。
expected_conditions
函数 说明
presenceOfElementLocated(locator) 是否存在
visibilityOfElementLocated(locator) 是否可见
invisibilityOfElementLocated(locator) 是否不可见
elementToBeClickable(locator) 是否可见并且enable
elementToBeSelected(locator) 是否被选中了,一般用在下拉列表
alertIsPresent() 判断页面上是否存在alert
textToBePresentInElement(locator,text) text是否包含字符串
textToBePresentInElementValue(locator,text) value是否包含字符串
titleIs(title) title是否等于预期
titleContains(title) title是否包含字符串

网页等待

  • 本来以为就是上面这三个等待了,结果发现自己理解的非常有问题,打开一些比较慢加载完毕的页面的时候,逻辑根本就不对。查资料试了好久才发现问题。
  • 上面的等待,除了 time.sleep 就是纯粹的等待,另外两个都是针对的 get_element,而不涉及一个网页打开的等待时间。也就是 web.get(url) 这个等待时间还是默认的无敌之长。
  • 我们必须解决这个 get 的等待时间,因为很多慢的网页,明明需要的东西都已经加载了,偏偏有一些其他的东西让网页状态一直停留在加载中。
限制加载时间
web.set_page_load_timeout(5)
try:
    web.get(url)
except:
    print('timeout')
  • 这个方法可以限制加载网页的时间,如果超时就会报错,与 try 使用可以达到一些不错的效果。
设置不阻塞程序
  • 上面那个方法有一点问题,就是那个时间不好办,时间长了浪费,时间短了东西还没出来,web 直接停掉,你只能再刷新。
  • 我们理想中的最优方案是,你加载你的,我代码继续往下跑,我只要在代码里面加上一个显性等待(嫌麻烦可以加一个隐形等待),就可以在第一时间运行后面的代码。这就是要设置 get 不阻塞。在网上找到了设置的代码,如下:
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

desired_capabilities = DesiredCapabilities.CHROME
desired_capabilities["pageLoadStrategy"] = "none"
  • 终于可以肆无忌惮地开心玩耍了。

本文章使用limfx的vsocde插件快速发布