Python Selenium.WebDriverWait 最强详解页面加载策略
Posted XianZhe_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python Selenium.WebDriverWait 最强详解页面加载策略相关的知识,希望对你有一定的参考价值。
Python Selenium.WebDriverWait 网页加载策略『详细』
文章目录
一、网页加载策略🍗
在通过Selenium加载一个网页时,Selenium都会等待页面加载完了才会运行下面的代码,这是因为 webdriver.get
方法会阻塞直到网页全部加载完成。
通常如果当页面加载花费大量时间时,可能是加载了很多外部资源「如:图像、css」,又或则是浏览的是国外网站,使用的网络环境差等问题,这些都是造成页面加载慢的原因。
但对于某些网页来说,需要加载的元素往往比不需要使用到的网页更快的加载出来,那么如何才能在加载到需要的数据之后就停止阻塞并且执行 webdriver.get
方法下的代码是本文章要探究的问题。
二、加载策略种类
Selenium支持的加载策略有三种,分别是none
、eager
、normal
,且提供自带的方法让我们去设置启动策略。
关键字 | 加载策略状态 | 描述 |
---|---|---|
none | 没有 | 等待html下载完成,不等待解析完成就开始执行操作,selenium 会直接返回 |
eager | 渴望 | 等待整个dom树加载完成,即DOMContentLoaded这个事件完成。 只要 HTML 完全加载和解析完毕就开始执行操作,忽略加载样式表、图像和子框架 |
normal | 正常(默认) | 等待整个页面加载完毕再开始执行操作 |
在浏览器选项的基类源码中能够看到,Selenium已经写好了设置加载策略的方法,同时也限制了加载策略的种类『源码第13行』
class Options(object):
def __init__(self):
self._page_load_strategy = "normal"
self._caps = DesiredCapabilities.EDGE.copy()
@property
def page_load_strategy(self):
return self._page_load_strategy
@page_load_strategy.setter
def page_load_strategy(self, value):
if value not in ['normal', 'eager', 'none']:
raise ValueError("Page Load Strategy should be 'normal', 'eager' or 'none'.")
self._page_load_strategy = value
......
三、配置加载策略
每种类型的 webdriver
都有一个对应的配置文件放在特定的类 DesiredCapabilities
里面,这个配置文件的数据结构为字典格式,通过定义键为 pageLoadStrategy
的键值对,可以使webdriver的页面加载策略发生改变。
模块位置 👇
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
1)、源码中是这么去使用加载策略的👇
可以看到,源码实质上就是在 DesiredCapabilities
配置文件中增加了一个pageLoadStrategy
属性值『源码第32行』,而 page_load_strategy
则是 Selenium 提供设置加载策略的方法。
对于DesiredCapabilities类,在博客 Python Selenium.WebDriverWait 浏览器启动参数设置『Edge如何使用启动参数』 中也有提到过,不管是在浏览器启动参数类 Options
源码中,还是自定义的 Options
启动参数类中,都会用的上。本篇文章相当于对 Python Selenium.WebDriverWait 浏览器启动参数设置『Edge如何使用启动参数』 的扩展。
Options选项类部分源码
class Options(object):
def __init__(self):
self._page_load_strategy = "normal"
self._caps = DesiredCapabilities.EDGE.copy()
......
@property
def page_load_strategy(self):
return self._page_load_strategy
@page_load_strategy.setter
def page_load_strategy(self, value):
if value not in ['normal', 'eager', 'none']:
raise ValueError("Page Load Strategy should be 'normal', 'eager' or 'none'.")
self._page_load_strategy = value
@property
def capabilities(self):
return self._caps
......
def to_capabilities(self):
"""
Creates a capabilities with all the options that have been set and
returns a dictionary with everything
"""
caps = self._caps
caps['pageLoadStrategy'] = self._page_load_strategy
return caps
DesiredCapabilities 部分源码
class DesiredCapabilities(object):
......
FIREFOX =
"browserName": "firefox",
"marionette": True,
"acceptInsecureCerts": True,
INTERNETEXPLORER =
"browserName": "internet explorer",
"version": "",
"platform": "WINDOWS",
EDGE =
"browserName": "MicrosoftEdge",
"version": "",
"platform": "WINDOWS"
CHROME =
"browserName": "chrome",
"version": "",
"platform": "ANY",
......
2)、更改使用加载策略:👇
-
使用
page_load_strategy
方法更改加载策略:from selenium import webdriver from selenium.webdriver.edge.options import Options def timer(func): """计时装饰器,用于计算程序运行时间""" def inner(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) print(f"加载时间:time.time() - start_time") return res return inner @timer def get_url(browser_, url_): """对页面发起请求""" browser_.get(url_) if __name__ == '__main__': url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501" op = Options() # 设置页面加载策略为none # op.page_load_strategy = "none" # 设置页面加载策略为normal # op.page_load_strategy = "eager" browser = webdriver.Edge("msedgedriver 97.exe", capabilities=op.to_capabilities()) get_url(browser, url)
程序流程:
使用 Edge 浏览器对目标网址发起请求,timer
为装饰器方法进行计时,对发起请求的get_url
函数进行计时,分别计算各浏览器加载策略的耗时
normal加载时间: 3.539372682571411
eager加载时间: 2.0514888763427734
none加载时间: 0.003000974655151367 -
使用原生方法手动配置加载策略:
可以看到其实就是先将选项类的配置转换为字典,再为这个字典添加键为
pageLoadStrategy
的键值对,再将这个字典传入浏览器的实例化参数中。from selenium import webdriver from selenium.webdriver.chrome.options import Options def timer(func): """计时装饰器,用于计算程序运行时间""" def inner(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) print(f"加载时间:time.time() - start_time") return res return inner @timer def get_url(browser_, url_): """对页面发起请求""" browser_.get(url_) if __name__ == '__main__': url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501" op = Options() capabilities = op.to_capabilities() # 设置页面加载策略为none capabilities["pageLoadStrategy"] = "none" # 设置页面加载策略为normal # capabilities["pageLoadStrategy"] = "eager" browser = webdriver.Chrome("chromedriver 97.exe", desired_capabilities=capabilities) get_url(browser, url)
程序流程:
使用 Chrome 浏览器对目标网址发起请求,timer
为装饰器方法进行计时,对发起请求的get_url
函数进行计时,分别计算各浏览器加载策略的耗时
normal加载时间: 3.847010850906372
eager加载时间: 2.529080390930176
none加载时间: 0.002000093460083008
DesiredCapabilities类,其本质就是存放着关于浏览器启动的配置文件。
在Selenium3中,不同浏览器的Options选项类源码存在部分差异,为方便展示,上述参考源码使用的是Edge浏览器的选项类。
对于每次运行的计时结果,都会有差异。
四、对加载策略进行封装🎍
在上述 page_load_strategy
方法示例中,使用到 Edge 浏览器进行示例,不用 Chrome 浏览器是因为在 Chrome 的选项类中并没有自带加载策略方法供我们去使用,需要手动配置加载策略或则直接对这个方法进行自定义封装。
将 Edge 和 Chrome 加载策略配置好之后,在写法一样的情况下分别调用 to_capabilities
方法输出配置策略对其进行对比,会发现 Chrome 选项类的配置中少了 pageLoadStrategy
值,主要差异体现在有没有配置 pageLoadStrategy
值的加载策略
1)、Edge浏览器加载配置
配置部分代码
......
url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501"
op = Options()
# 设置页面加载策略为none
op.page_load_strategy = "none"
# 设置页面加载策略为normal
# op.page_load_strategy = "eager"
# 打印配置策略
print(op.to_capabilities())
browser = webdriver.Edge("msedgedriver 97.exe", capabilities=op.to_capabilities())
get_url(browser, url)
2)、Chrome浏览器加载配置
配置部分代码
......
url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501"
op = Options()
# 设置页面加载策略为none
op.page_load_strategy = "none"
# 设置页面加载策略为normal
# op.page_load_strategy = "eager"
# 打印配置策略
print(op.to_capabilities())
browser = webdriver.Chrome("chromedriver 97.exe", options=op)
get_url(browser, url)
3)、Chrome加载策略封装
在继承原有 Chrome 选项类的基础上,自定义加载策略方法,通过这种形式就可以弥补某些浏览器启动参数类方法不全的问题,或编写提升效率的方法
Chrome封装加载策略类
class ChromeOptions(Options):
def __init__(self):
super(ChromeOptions, self).__init__()
self._page_load_strategy = "normal"
@property
def page_load_strategy(self):
return self._page_load_strategy
@page_load_strategy.setter
def page_load_strategy(self, value):
"""设置加载策略方法"""
if value not in ['normal', 'eager', 'none']:
raise ValueError("Page Load Strategy should be 'normal', 'eager' or 'none'.")
self._page_load_strategy = value
def to_capabilities(self):
"""使用已设置的所有启动参数,并返回包含所有内容的字典"""
caps = self._caps
chrome_options = self.experimental_options.copy()
chrome_options["extensions"] = self.extensions
if self.binary_location:
chrome_options["binary"] = self.binary_location
chrome_options["args"] = self.arguments
if self.debugger_address:
chrome_options["debuggerAddress"] = self.debugger_address
# 添加加载策略键值对
caps["pageLoadStrategy"] = self._page_load_strategy
caps[self.KEY] = chrome_options
return caps
调用执行
可以看到,需要的 pageLoadStrategy
值已被成功添加,且程序也能正常使用自定义的加载策略
url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501"
op = ChromeOptions()
# 设置页面加载策略为none
op.page_load_strategy = "none"
# 设置页面加载策略为normal
# op.page_load_strategy = "eager"
# 打印配置策略
print(op.to_capabilities())
browser = webdriver.Chrome("chromedriver 97.exe", options=op)
get_url(browser, url)
五、配合显示等待使用加载策略
通过更改加载策略,Selenium不再等待页面加载完毕后才会执行 webdriver.get
下面的代码, 但这也会造成一个问题,在 webdriver.get
下面的代码通常都是页面元素的获取代码,但在页面没有加载结束的情况下去获取会造成程序抛出异常。
1)、显示等待
为了解决这个问题,这时候就需要用上 Selenium 的显示等待。
使用 Selenium 时能用上的等待方式共有三种,分别是显示等待、隐性等待、强制等待,这里只稍微提及一下显示等待。显示等待的作用:程序每隔xx秒看一眼,如果页面元素存在了,则代码继续执行下一步,否则继续循环检查,直到超过设置的最长时间抛出 TimeoutException
异常。
2)、配合显示等待
现使用 Selenium 配置 none
加载策略并打开博客页面,点击页面点赞标签,观察显示等待效果。
显示等待与加载策略配合使用,能够在一定程度上提高程序的执行效率,对于使用Selenium来说这是一个常见的技巧。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
class ChromeOptions(Options):
def __init__(self):
super(ChromeOptions, self).__init__()
self._page_load_strategy = "normal"
@property
def page_load_strategy(self):
return self._page_load_strategy
@page_load_strategy.setter
def page_load_strategy(self, value):
"""设置加载策略方法"""
if value not in ['normal', 'eager', 'none']:
raise ValueError("Page Load Strategy should be 'normal', 'eager' or 'none'.")
self._page_load_strategy = value
def to_capabilities(self):
"""使用已设置的所有启动参数,并返回包含所有内容的字典"""
caps = self._caps
chrome_options = self.experimental_options.copy()
chrome_options["extensions"] = self.extensions
if self.binary_location:
chrome_options["binary"] = self.binary_location
chrome_options["args"] = self.arguments
if self.debugger_address:
chrome_options["debuggerAddress"] = self.debugger_address
# 添加加载策略键值对
caps["pageLoadStrategy"] = self._page_load_strategy
caps[self.KEY] = chrome_options
return caps
def timer(func):
"""计时装饰器,用于计算程序运行时间"""
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
print(f"加载时间:time.time() - start_time")
return res
return inner
@timer
def get_url(browser_, url_):
"""对页面发起请求"""
browser_.get(url_)
def like(browser_: webdriver, sec=3, poll_frequency=0.5):
"""CSDN博客点赞方法
Args:
browser_: 浏览器对象
sec: 显示等待时长
poll_frequency: 显示等待轮询频率
"""
xpaths = "//li[@id='is-like']"
element = WebDriverWait(browser_, sec, poll_frequency=poll_frequency).until(
ec.presence_of_element_located((By.XPATH, xpaths)))
element.click()
if __name__ == '__main__':
url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501"
op = ChromeOptions()
# 设置页面加载策略为none
op.page_load_strategy = "none"
# 设置页面加载策略为normal
# op.page_load_strategy = "eager"
browser = webdriver.Chrome("chromedriver 97.exe", options=op)
get_url(browser, url)
# 执行点赞
like(browser)
六、Selenium4对加载策略的改动💣
在Selenium4中对页面的选项类进行了改动,每个浏览器的 Options选项类不再是单个存在的方式,在 Selenium4 每个选项类都继承来自了 BaseOptions
类。
这是一个很重要的改进,对于各个浏览器来讲,在原本没有定义加载策略方法浏览器选项类中也能用上加载策略了,不需要自行另外再去自定义方法,我们只需直接调用自带方法即可配置加载策略。
BaseOptions类部分源码 🐾
class BaseOptions(metaclass=ABCMeta):
"""
Base class for individual browser options
"""
......
@platform_name.setter
def platform_name(self, platform: str) -> NoReturn:
"""
Requires the platform to match the provided value: https://w3c.github.io/webdriver/#dfn-platform-name
:param platform: the required name of the platform
"""
self.set_capability("platformName", platform)
@property
def page_load_strategy(self) -> str:
"""
:returns: page load strategy if set, the default is "normal"
"""
return self._caps["pageLoadStrategy
......
Chrome浏览器启动选项直接使用🐔
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
def get_url(browser_, url_):
"""对页面发起请求"""
browser_.get(url_)
if __name__ == '__main__':
url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501"
op = Options()
# 设置页面加载策略为none
op.page_load_strategy = "none"
# 设置页面加载策略为normal
# op.page_load_strategy = "eager"
driver = Service("chromedriver 97.exe")
browser = webdriver.Chrome(service=driver, options=op)
get_url(browser, url)
Edge浏览器启动选项直接使用🐔
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
def get_url(browser_, url_):
"""对页面发起请求"""
browser_.get(url_)
if __name__ == '__main__':
url = "https://blog.csdn.net/XianZhe_/article/details/120929106?spm=1001.2014.3001.5501"
op = Options()
# 设置页面加载策略为none
op.page_load_strategy = "none"
# 设置页面加载策略为normal
# op.page_load_strategy = "eager"
driver = Service("msedgedriver 97.exe")
browser = webdriver.Edge(service=driver, options=op)
get_url(browser, url)
参考文献💗
相关博客🤩
以上是关于Python Selenium.WebDriverWait 最强详解页面加载策略的主要内容,如果未能解决你的问题,请参考以下文章
[python] python+selenium+webdriver