API 概览 && 编码Tips

文档地址

常用API

  • Network 网络请求、Cookie、缓存、证书等相关内容
  • Page 页面的加载、资源内容、弹层、截图、打印等相关内容
  • DOM 文档DOM的获取、修改、删除、查询等相关内容
  • Runtime JavaScript代码的执行,这里面我们可以搞事情~~

编码Tips

  • 我们这里不会直接调用Websocket相关的内容来调用chrome的调试命令,而是用chrome-remote-interface 这个封装的库来做,它是基于Promise风格的
  • 每一个功能块成为一个单独的domain,像Network,Page,DOM等都是不同的domain
  • 几乎每一个个头大的domain都有enable方法,需要先调用这个方法启用之后再使用
  • 各个domain的接口方法参数都是第一个对象或者说一个Map,不用考虑参数的位置了
  • 各个domain的接口返回值也是一个对象,取对应的key就行
  • 参数值和返回值经常是meta信息,经常是各种对象的id信息,而不是具体的对象内容(这里可能需要切一下风格)

编码实例

首先做一个简单的封装,准备API的执行环境,具体可参考前一篇关于工具库的。

const chromeLauncher = require('chrome-launcher');
const chromeRemoteInterface = require('chrome-remote-interface'); const prepareAPI = (config = {}) => {
const {host = 'localhost', port = 9222, autoSelectChrome = true, headless = true} = config;
const wrapperEntry = chromeLauncher.launch({
host,
port,
autoSelectChrome,
additionalFlags: [
'--disable-gpu',
headless ? '--headless' : ''
]
}).then(chromeInstance => {
const remoteInterface = chromeRemoteInterface(config).then(chromeAPI => chromeAPI).catch(err => {
throw err;
});
return Promise.all([chromeInstance, remoteInterface])
}).catch(err => {
throw err
}); return wrapperEntry
};

打开百度,获取页面性能数据,参考 Navigation Timing W3C规范

const wrapper = require('the-wrapper-module');

const performanceParser = (perforceTiming) => {
let timingGather = {};
perforceTiming = perforceTiming || {};
timingGather.redirect = perforceTiming.redirectEnd - perforceTiming.redirectEnd-perforceTiming.redirectStart;
timingGather.dns = perforceTiming.domainLookupEnd - perforceTiming.domainLookupStart;
timingGather.tcp = perforceTiming.connectEnd - perforceTiming.connectStart;
timingGather.request = perforceTiming.responseStart - perforceTiming.requestStart;
timingGather.response = perforceTiming.responseEnd - perforceTiming.responseStart;
timingGather.domReady = perforceTiming.domContentLoadedEventStart - perforceTiming.navigationStart;
timingGather.load = perforceTiming.loadEventStart - perforceTiming.navigationStart;
return timingGather;
}; const showPerformanceInfo = (performanceInfo) => {
performanceInfo = performanceInfo || {};
console.log(`页面重定向耗时:${performanceInfo.redirect}`);
console.log(`DNS查找耗时:${performanceInfo.dns}`);
console.log(`TCP连接耗时:${performanceInfo.tcp}`);
console.log(`请求发送耗时:${performanceInfo.request}`);
console.log(`响应接收耗时:${performanceInfo.response}`);
console.log(`DOMReady耗时:${performanceInfo.domReady}`);
console.log(`页面加载耗时:${performanceInfo.load}`);
}; wrapper.prepareAPI().then(([chromeInstance, remoteInterface]) => {
const {Runtime,Page} = remoteInterface; Page.loadEventFired(() => {
Runtime.evaluate({
expression:'window.performance.timing.toJSON()',
returnByValue:true //不加这个参数,拿到的是一个对象的meta信息,还需要getProperties
}).then((resultObj) => {
let {result,exceptionDetails} = resultObj;
if(!exceptionDetails){
showPerformanceInfo(performanceParser(result.value))
}else{
throw exceptionDetails;
}
});
}); Page.enable().then(() => {
Page.navigate({
url:'http://www.baidu.com'
})
});
});

打开百度 搜索Web自动化 headless chrome,并爬取首屏结果链接

const wrapper = require('the-wrapper-module');
//有this的地方写成箭头函数要注意,这里会有问题
const buttonClick = function () {
this.click();
}; const setInputValue = () => {
var input = document.getElementById('kw');
input.value = 'Web自动化 headless chrome';
}; const parseSearchResult = () => {
let resultList = [];
const linkBlocks = document.querySelectorAll('div.result.c-container');
for (let block of Array.from(linkBlocks)) {
let targetObj = block.querySelector('h3');
resultList.push({
title: targetObj.textContent,
link: targetObj.querySelector('a').getAttribute('href')
});
}
return resultList;
}; wrapper.prepareAPI({
// headless: false //加上这行代码可以查看浏览器的变化
}).then(([chromeInstance, remoteInterface]) => {
const {Runtime, DOM, Page, Network} = remoteInterface;
let framePointer;
Promise.all([Page.enable(), Network.enable(), DOM.enable(),Page.setAutoAttachToCreatedPages({autoAttach:true})]).then(() => {
Page.domContentEventFired(() => {
console.log('Page.domContentEventFired')
Runtime.evaluate({
expression:`window.location.href`,
returnByValue:true
}).then(result => {
console.log(result)
})
});
Page.frameNavigated(() => {
console.log('Page.frameNavigated')
Runtime.evaluate({
expression:`window.location.href`,
returnByValue:true
}).then(result => {
console.log(result)
})
})
Page.loadEventFired(() => {
console.log('Page.loadEventFired')
Runtime.evaluate({
expression:`window.location.href`,
returnByValue:true
}).then(result => {
console.log(result)
})
DOM.getDocument().then(({root}) => {
//百度首页表单
DOM.querySelector({
nodeId: root.nodeId,
selector: '#form'
}).then(({nodeId}) => {
Promise.all([
//找到 搜索框填入值
DOM.querySelector({
nodeId: nodeId,
selector: '#kw'
}).then((inputNode) => { Runtime.evaluate({
// 两种写法
// expression:'document.getElementById("kw").value = "Web自动化 headless chrome"',
expression: `(${setInputValue})()`
}); //这段代码不起作用 日狗
// DOM.setNodeValue({
// nodeId:inputNode.nodeId,
// value:'Web自动化 headless chrome'
// }); //上面的代码需求要这么写
// DOM.setAttributeValue({
// nodeId:inputNode.nodeId,
// name:'value',
// value:'headless chrome'
// });
})
//找到 提交按钮setInputValue
, DOM.querySelector({
nodeId,
selector: '#su'
})
]).then(([inputNode, buttonNode]) => { Runtime.evaluate({
expression: 'document.getElementById("kw").value',
}).then(({result}) => {
console.log(result)
}); return DOM.resolveNode({
nodeId: buttonNode.nodeId
}).then(({object}) => {
const {objectId} = object;
return Runtime.callFunctionOn({
objectId,
functionDeclaration: `${buttonClick}`
})
});
}).then(() => {
setTimeout(() => {
Runtime.evaluate({
expression: `(${parseSearchResult})()`,
returnByValue: true
}).then(({result}) => {
console.log(result.value)
//百度的URL有加密,需要再请求一次拿到真实URL
})
},3e3)
});
}) });
});
Page.navigate({
url: 'http://www.baidu.com'
}).then((frameObj) => {
framePointer = frameObj
});
}) });

Web自动化之Headless Chrome编码实战的更多相关文章

  1. Web自动化之Headless Chrome测试框架集成

    使用Selenium操作headless chrome 推荐 简介 WebDriver是一个W3C标准, 定义了一套检查和控制用户代理(比如浏览器)的远程控制接口,各大主流浏览器来实现这些接口以便调用 ...

  2. Web自动化之Headless Chrome概览

    Web自动化 这里所说的Web自动化是所有跟页面相关的自动化,比如页面爬取,数据抓取,页面内容检测,页面功能测试,页面加载性能测试,页面回归测试等等,当前主要由如下几种解决方式: 文本数据获取 这就是 ...

  3. Web自动化之Headless Chrome开发工具库

    命令行运行Headless Chrome Chrome 安装(需要带梯子) 下载地址 几个版本的比较 Chromium 不是Chrome,但Chrome的内容基本来源于Chromium,这个是开源的版 ...

  4. 爬虫实战:爬虫之 web 自动化终极杀手 ( 上)

    欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:陈象 导语: 最近写了好几个简单的爬虫,踩了好几个深坑,在这里总结一下,给大家在编写爬虫时候能给点思路.本次爬虫内容有:静态页面的爬 ...

  5. Selenium Web 自动化 - 项目实战(一)

    Selenium Web 自动化 - 测试框架(一) 2016-08-05 目录 1 框架结构雏形2 把Java项目转变成Maven项目3 加入TestNG配置文件4 Eclipse编码修改5 编写代 ...

  6. docker+headless+robotframework+jenkins实现web自动化持续集成

    在Docker环境使headless实现web自动化持续集成 一.制作镜像 原则:自动化测试基于基础制作镜像 命令:docker run --privileged --name=$1 --net=ho ...

  7. 《Selenium+Pytest Web自动化实战》随到随学在线课程,零基础也能学!

    课程介绍 课程主题:<Selenium+Pytest Web自动化实战> 适合人群: 1.功能测试转型自动化测试 2.web自动化零基础的小白 3.对python 和 selenium 有 ...

  8. Selenium Web 自动化 - 项目实战(三)

    Selenium Web 自动化 - 项目实战(三) 2016-08-10 目录 1 关键字驱动概述2 框架更改总览3 框架更改详解  3.1 解析新增页面目录  3.2 解析新增测试用例目录  3. ...

  9. Selenium Web 自动化 - 项目实战环境准备

    Selenium Web 自动化 - 项目实战环境准备 2016-08-29 目录 1 部署TestNG  1.1 安装TestNG  1.2 添加TestNG类库2 部署Maven  2.1 mav ...

随机推荐

  1. MacBook使用之配置jdk&Eclipse

    查看系统版本:关于本机-软件-查看当前版本信息 打开另一个Finder的快捷键:Command + n 终端命令:Finder - 使用工具 - 终端命令 配置jdk系统变量: cd ~ touch ...

  2. 使用 jQuery.Pin 垂直滚动时固定导航

    ZKEACMS的导航默认是不能固定的,随着页面的滚动而滚动,为了有更好的用户体验,当页面往下滚动时,可以将导航固定在顶端,这样方便用户点击. jQuery Pin 借助jQuery的一个插件 jQue ...

  3. JMeter-Eclipse添加自定义函数 MD5加密 32位和16位

    最近公司的接口都是MD5  16位加密,所以要使用加密功能. 之前也做过加密,因为用的比较少,所以是写了一个加密方法,导出JAR包,调用的.用起来需要很多设置,并且换算效率也不高.听前同事说,jmet ...

  4. setTimeout异步加载

    两道经典的面试题,直接上代码 for(var i=0; i<3; i++){ setTimeout(function(){ i+=i; console.log(i); },1000) } var ...

  5. Outlook 客户端无法通过 MAPI over HTTP 连接

    随着Exchange 版本更新升级,是否进行验证客户端建立MapiHttp连接所需的服务器设置已正确配置.即使服务器,负载均衡器和反向代理的所有设置都正确,您可能会遇到连接到Exchange Serv ...

  6. 38. Count and Say - Unsolved

    https://leetcode.com/problems/count-and-say/#/description The count-and-say sequence is the sequence ...

  7. postgresql 多表联查

    使用语句的先后顺序并不是优先级的排序: 连接分为:内连接和外连接,外连接分为左外连接,右外连接,全连接 概念上解释,表之间联合后数据如何整合. 返回的数据条数,可以通过集合求算.假如A集合有10条数据 ...

  8. Python 基于TK 文本编辑器

    #coding=utf-8 import sys,os import tkFileDialog from Tkinter import * from tkFont import Font print ...

  9. io-nio 区别示意图

    no:一个线程管理多个连接请求并且一个线程在处理事情,需要一个一个处理连接. nio:由一个 bOSS 线程连接分发,分发至每个工作线程,工作线程接收到请求后直接负责连接任务的处理,多线程任务处理机制 ...

  10. SQLServer 理解copyonly备份操作

    标签:MSSQL/日志截断 概述 Alwayson在添加数据库的过程中如果同步首选项选择的是“完整”,那么就会在主副本上执行copyonly的完整备份和日志备份在辅助副本上执行还原操作,也正是这个操作 ...