chrome devtools protocol——Web 性能自动化实践介绍
随着互联网的发展,网页性能问题已经成为了一个非常重要的话题。高性能的网页不仅能够提升用户体验,还能够提高网站的流量和收益。因此,如何优化网页性能已经成为了开发者们必须要掌握的技能之一。
目录
前言:
随着互联网的发展,网页性能问题已经成为了一个非常重要的话题。高性能的网页不仅能够提升用户体验,还能够提高网站的流量和收益。因此,如何优化网页性能已经成为了开发者们必须要掌握的技能之一。
chrome devtools protocol
chrome devtools protocol允许第三方对基于 chrome 的 web 应用程序进行调试、分析等,它基于 WebSocket,利用 WebSocket 建立连接 DevTools 和浏览器内核的快速数据通道。一句话,有了这个协议就可以自己开发工具获取 chrome 的数据
协议详细内容看这里chrome devtools protocol
目前已经有很多大神针对这个协议封装出不同语言(nodejs,python,java...)的库

这边我选择的是 python 的 pychromegithub 地址,使用方法很简单,直接看 github 上它的 Demo
这个库依赖websocket-client
获取 performance api 数据
这里使用 Runtime Domain 中运行 JavaScript 脚本的 APIRuntime.evaluate
# 开始前先启动chrome,启动chrome必须带上参数`--remote-debugging-port=9222`开启远程调试否则无法与chrome交互
browser = pychrome.Browser('http://127.0.0.1:%d' % 9222)
tab = browser.new_tab()
tab.start()
tab.Runtime.enable()
tab.Page.navigate(url={你的页面地址})
# 设置等待页面加载完成的时间
tab.wait(10)
# 运行js脚本
timing_remote_object = tab.Runtime.evaluate(
expression='performance.timing'
)
# 获取performance.timing结果数据
timing_properties = tab.Runtime.getProperties(
objectId=timing_remote_object.get('result').get('objectId')
)
timing = {}
for item in timing_properties.get('result'):
if item.get('value', {}).get('type') == 'number':
timing[item.get('name')] = item.get('value').get('value')
# 获取performance.getEntries()数据
entries_remote_object = tab.Runtime.evaluate(
expression='performance.getEntries()'
)
entries_properties = tab.Runtime.getProperties(
objectId=entries_remote_object.get('result').get('objectId')
)
entries_values = []
for item in entries_properties.get('result'):
if item.get('name').isdigit():
url_timing_properties = tab.Runtime.getProperties(
objectId=item.get('value').get('objectId')
)
entries_value = {}
for son_item in url_timing_properties.get('result'):
if (son_item.get('value', {}).get('type') == 'number'or
son_item.get('value', {}).get('type') == 'string'):
entries_value[son_item.get('name')] = son_item.get('value').get('value')
entries_values.append(entries_value)
获取 Network 数据
实际上 performance.getEntries() 不会记录 404 的请求信息,另外当前页面通过 js 触发新 html 页面请求时它只会记录第一个页面的请求,在这些情况下就需要通过 Network Domain 的 API 来收集所有请求信息,先介绍用到的 API:
Network.requestWillBeSent每个 http 请求发送前回调Network.responseReceived首次接送到 http 响应时回调Network.loadingFinished请求加载完成时回调-
Network.loadingFailed请求加载失败时回调# 封装上面4个事件对应的回调方法 class NetworkAPIImplemention(object): def __init__(self): self.request_dict = {} # 首个请求开始时间 self.start = None def request_will_be_sent(self, **kwargs): if self.start is None: self.start = time.time() dict_http = { 'url':kwargs.get('request').get('url'), 'start':kwargs.get('timestamp') } self.request_dict[kwargs.get('requestId')]=dict_http #print "loading:%s" % kwargs.get('request').get('url') def loading_finished(self, **kwargs): # 服务器返回code 例如404也是finished self.request_dict[kwargs.get('requestId')]['end'] = kwargs.get('timestamp') self.request_dict[kwargs.get('requestId')]['size'] = kwargs.get('encodedDataLength') def response_received(self, **kwargs): self.request_dict[kwargs.get('requestId')]['type'] = kwargs.get('type') self.request_dict[kwargs.get('requestId')]['response'] = kwargs.get('response') def loading_failed(self, **kwargs): self.request_dict[kwargs.get('requestId')]['end'] = kwargs.get('timestamp') self.request_dict[kwargs.get('requestId')]['error_text'] = kwargs.get('errorText') network_api = NetworkAPIImplemention() browser = pychrome.Browser('http://127.0.0.1:%d' % 9222) tab = browser.new_tab() # 绑定回调函数 tab.Network.requestWillBeSent = network_api.request_will_be_sent tab.Network.responseReceived = network_api.response_received tab.Network.loadingFinished = network_api.loading_finished tab.Network.loadingFailed = network_api.loading_failed tab.start() tab.Network.enable() tab.Runtime.enable() # 是否禁用缓存 if disable_cache: tab.Network.setCacheDisabled(cacheDisabled=True) tab.Page.navigate(url={你的页面地址}) tab.wait(10) tab.stop() self.browser.close_tab(tab) # 获取的所有url详细信息 print network_api.request_dict
监听页面事件
有时候特别是一些复杂的页面,页面依赖 js 和后端资源数据,并不是通常意义上页面 loadEventEnd 事件触发完就表示页面加载完成,这种情况可能需要依赖开发打点。
这里以开发设计了一个Loaded事件为例
# 具体事件注册方式和注册时机询问开发,所谓注册时机即要求在js对象生成后注册,我们项目中page是在一个js文件中声明的,需要等这个js文件请求完成后再注册
# 这边使用Promise方式,这种方式awaitPromise参数必须是True
js = """
new Promise((resolve, reject) => {
page.getController().getPageEvent().addEventListener("Loaded",
function(){
resolve(new Date().getTime());
});
});
"""
custom_result = tab.Runtime.evaluate(
expression=js,
awaitPromise=True,
timeout=timeout * 1000
)
print custom_result.get('result').get('value')
有个坑
peformance.now()获取与 chrome 开发者工具协议一样类型的时间时,这个时间不准确,只好用new Date().getTime()
![]()
作为一位过来人也是希望大家少走一些弯路
在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。
(软件测试相关资料,自动化测试相关资料,技术问题答疑等等)
相信能使你更好的进步!
点击下方小卡片
更多推荐

http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=8J30vUQ4Dwe-Bi6g7S7DSz8H0yLtnwiy&authKey=hx0%2BVuvMtmByHmuBIh0PIsaP55U45oHRQeQi9su5xrtqQvx2cqoeqUDYRYlity4c&noverify=0&group_code=574737577



所有评论(0)