Puppeteer 谷歌开发是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。
能做啥?
- 生成页面 PDF,截图。
- 抓取单页应用执行并渲染
- 自动提交表单,进行 UI 测试,键盘输入等。
- 创建一个时时更新的自动化测试环境。
- 用来帮助分析性能问题。
介绍
Puppeteer API 是分层次的,反映了浏览器结构
这张图需要了解一下,即是puppeteer的结构,也是代码的顺序结构;
// 浏览器实例
const puppeteer = require('puppeteer');
// 启动 返回 browser
const browser = await puppeteer.launch();
// 返回 page
const page = await browser.newPage();
// 跳转
await page.goto('https://www.baidu.com/');
// 返回page的frame
const frame = await page.mainFrame();
// 当前页面的url https://www.baidu.com/
console.log(frame.url());
// 关闭
await browser.close();
复制代码
- Puppeteer 使用 DevTools 协议 与浏览器进行通信。
- Browser 实例可以拥有浏览器。
- BrowserContext 浏览器上下文。
- Page 至少有一个框架:主框架。 可能还有其他框架由 iframe 或 框架标签 创建。
- frame 至少有一个执行上下文 - 默认的执行上下文 - 框架的 JavaScript 被执行。 一个框架可能有额外的与 扩展 关联的执行上下文。
- Worker 具有单一执行上下文,并且便于与 WebWorkers 进行交互。
安装
// 安装puppeteer,如果报错改用 cnpm 安装
cnpm install puppeteer --save
复制代码
常用函数
Puppeteer返回的大部分是Promise支持一下async/await会很方便; 每个功能方法都有很多参数配置,先列举部分
浏览器操作、打开页面
上方代码内容
跳转地址
await page.goto('https://google.com/', {
// 配置项 等待网络状态为空闲的时候才继续执行
waitUntil: 'networkidle'
});
复制代码
生成PDF,截图
await page.screenshot({ path: "download/example.png" });
await page.pdf({
path: "download/example_pdf.pdf',
format: "A4"
});
复制代码
等待
waitFor: 参数可以是<string|number|function> 选择器, 方法 或者 超时时间
// 等待1s
await page.waitFor(1000);
// 等待元素加载完成
await page.waitForSelector("#id");
复制代码
选择器
- 返回的类型 ElementHandle 表示一个页内的 DOM 元素;
- 是继承自 JSHandle。而 JSHandle 表示页面内的 JavaScript 对象
- 其实是执行的document.querySelector,document.querySelectorAll
// 返回单个,如果多个返回第一个,没有返回null
const ElementHandle = await page.$("#js_login_select")
// 返回多个,如果没有返回[]
await page.$$(".js_login_select")
复制代码
page.$eval(selector, pageFunction[, ...args])
此方法在页面内执行 document.querySelector,然后把匹配到的元素作为第一个参数传给 pageFunction
// 获取html
const html = await page.$eval("body", e => e.outerHTML);
console.log(html);
// 获取id
const id = await page.$eval('#div',div => div.id );
//清空输入框的值,获取焦点
await page.$eval('#input',input => {
input.focus();
input.value = '';
})
复制代码
evaluate
页面实例上下文中执行的方法
const dimensions = await page.evaluate(param => {
alert("我的方法dimensions和" + param);
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
};
}, "参数");
复制代码
eval与evaluate区别
page.evaluate 意为在浏览器环境执行脚本,可传入第二个参数作为句柄,而 page.$eval 则针对选中的一个 DOM 元素执行操作。
注意:选择器过滤后得到的dom,都是通过执行querySelector或者querySelectorALl得到的,所以页面脚本能执行的方法属性,都可以在这里使用
-常用函数
性能分析
Puppetter当然可以分析网站的性能,不过是创建一个可以在Chrome DevTools中打开的跟踪文件。
// 每个浏览器一次只能激活一条跟踪
await page.tracing.start({
path: "download/trace.json",
screenshots: true
});
// 需要关闭
await page.tracing.stop();
复制代码
成功后会在path的位置生成.json的文件,里面一堆的数字和变量~ 打开chrome浏览器的devtools,拖进performance中就OK了~
请求拦截
Puppeteer还可以监听很多事件,load,error,close等等,当然包括request,response
对页面的图片请求拦截,如果不是图片后缀可以找规则筛选
// 启动 request
await page.setRequestInterception(true);
// 监听request
page.on("request", interceptedRequest => {
if (
interceptedRequest.url().endsWith(".png") || interceptedRequest.url().endsWith(".jpg") ||
interceptedRequest.url().includes(".jpg")
) {
// 中断
interceptedRequest.abort();
} else {
interceptedRequest.continue();
}
});
await page.goto("https://www.58pic.com/");
复制代码
注入
- addScriptTag:注入一个指定src(url)或者代码(content)的 script 标签到当前页面。
- addStyleTag:添加一个指定link(url)的 < link rel="stylesheet" > 标签。 或者添加一个指定代码(content)的 < style type="text/css" > 标签。
await page.addScriptTag({ path: "public/javascripts/test.js" });
await page.addStyleTag({ path: "public/css/test.css" });
复制代码
这样不同站点,只需要注入不同的脚本爬取
模拟浏览器
关于模拟不同的手机,需要不同的参数,Puppeteer准备了很多,可以直接拿来用,在puppeteer/DeviceDescriptors中
const page = await browser.newPage();
// 模拟机型
await page.emulate(iPhone);
复制代码