相较于以前的版本,Selenium4除了推出了relative Locators,还有一个比较重要的更新就是对于Chrome Dev Tools Protocol的支持。
Chrome Dev Tools Protocol帮助用户监测、检查、调试和模版化Chrome浏览器以及基于Chromium的其它浏览器(比如EDGE,360极速等)。Chrome Dev Tools Protocol简称为CDP。而Chrome Dev Tools为用户提供接口来执行各种可编程操作。CDP的方法比较多,其涵盖的领域包括Browser,Debugger,DOM,Console,Network,Page等。
Selenium4提供了两个CDP相关方法:
- send()
- executeCDPCommand()
两者都用来和Chrome DevTools Protocol进行交互,但也不尽相同。前者selenium提供了一个wrapper,来调用Chrome DevTools Protocol命令;而后者直接调用ChromiumDriver的一个现有方法,无需借助selenium的wrapper。至于究竟用哪一个,我想selenium4可能更希望用户用前者。
1. 获取浏览器信息
browser.execute_cdp_cmd("Browser.getVersion", {})
2. 设置device mode
set_device_metrics_override = dict({
"width": 375,
"height": 812,
"deviceScaleFactor": 50,
"mobile": True
})
browser.execute_cdp_cmd('Emulation.setDeviceMetricsOverride', set_device_metrics_override)
3. 修改地理位置
map_coord = {
"latitude": 42.1408845,
"longitude": -72.5033907,
"accuracy": 100
}
browser.execute_cdp_cmd("Emulation.setGeolocationOverride", map_coord)
从实用角度来说,这在测试一些基于位置服务的Web APP中会有用武之地。
4. 设置网络条件
browser.driver.set_network_conditions(
offline=False,
latency=10,
download_throughput=500 * 1024,
upload_throughput=500 * 1024)
browser.get('https://www.baidu.com')
net_con = browser.driver.get_network_conditions()
print(net_con)
sleep(3)
print("Latency: " + str(net_con["latency"]))
print("Download Throughput: " + str(net_con['download_throughput']))
print("Upload Throughput: " + str(net_con['upload_throughput']))
这在测试或者重现一些和网络状态相关的问题时会有用。在selenium中,如果我们没有设置过network conditions, 那么selenium也无法通过get_network_conditions()方法获取网络状态;selenium设置的网络状态需要等待一定的时间才能生效。
5. 截图
res = browser.execute_cdp_cmd('Page.captureScreenshot', {})
with open('../output/baidu.png', 'wb') as f:
img = base64.b64decode(res['data'])
f.write(img)
截图在selenium中已经有现成的方法,所以这个功能看起来没有多少使用价值。或者,我们还没有看到其真正的用途。
6. HTML转成PDF
res = browser.execute_cdp_cmd('Page.printToPDF', {})
with open('../output/baidu.pdf', 'wb') as f:
img = base64.b64decode(res['data'])
f.write(img)
Selenium之前是没有现成的方法把当前的页面转成PDF的,所以,不管如何,至少这拓展了Selenium本身的功能。
7. 监控浏览器console中的error信息
capabilities = DesiredCapabilities.CHROME
capabilities['loggingPrefs'] = {'browser': 'ALL'}
browser = webdriver.Chrome(
desired_capabilities=capabilities,
service=Service(executable_path="../driver/chromedriver")
browser.get('https://www.bilibili.com/')
browser.execute_script("console.error('There is an error!');") # generate an error
logs = []
for entry in browser.driver.get_log('browser'):
if entry['level'] == 'SEVERE':
logs.append(entry)
logs_json = json.dumps(logs, indent=4, ensure_ascii=False)
with codecs.open('../output/console_logs.json', "w", "utf-8") as f:
f.write(logs_json)
当我们运行自动化Web测试用例的时候,Selenium更多关注与页面元素的呈现和交互。但有些时候,虽然页面上一切正常,但是浏览器的console里已经产生了一堆错误,这些错误常常对测试来说是一些有效信息。如果我们能在代码里自动去监控这些error,那一方面会让我们的测试更全面,另一方面也节省了时间。
8. 获取performance metrics
browser.get('https://www.baidu.com')
browser.execute_cdp_cmd('Performance.enable', {})
t = browser.execute_cdp_cmd('Performance.getMetrics', {})
print(t)
和页面装载相关的一些数据会被返回。
9. 获取requests和response信息
Selenium本身更关注浏览器中UI的end-to-end操作,而并不关注其产生的requests和response。而CDP提供了一种途径,让我们在UI自动化操作的过程中,也可以一窥其相应的requests和response。
capabilities = DesiredCapabilities.CHROME
capabilities["goog:loggingPrefs"] = {"performance": "ALL"}
browser = webdriver.Chrome(
desired_capabilities=capabilities,
service=Service(executable_path="../driver/chromedriver"))
browser.get('https://www.baidu.com')
request_log = browser.driver.get_log('performance')
for i in range(len(request_log)):
message = json.loads(request_log[i]['message'])
params = message['message']['params']
request = params.get('request')
if not request:
continue
url = request.get("url")
if filter_url(url):
print("Request url: {}".format(url))
print("Request headers: {}".format(request.get("headers")))
print("Request method: {}".format(request.get("method")))
content = browser.execute_cdp_cmd(
'Network.getResponseBody',
{'requestId': params.get("requestId")})
print("Response: {}".format(content))
print("**********")
其实,我还发现有个package,名为 seleniumwire也能实现在selenium中获取requests和responses。但美中不足的是,如果使用seleniumwire,那么我们使用的就是seleniumwire中的web driver,而不是原生selenium的web driver,不太喜欢这种在selenium外套壳的方式。
本来以为我需要两三篇文章才可以将CDP讲完,没想到这么短就结束了。内容其实还有很多,但是大部分只有用到才有价值,所以就不在乎那么多细节了。