安装第三方库:puppeteer
npm i puppeteer
安装谷歌 Chromium:若 npm
安装失败,需要手动下载 chromium 并解压至相应文件夹
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.baidu.com');
await page.close();
await browser.close();
})();
puppeteer 提供了两种方法用于创建一个 Browser 实例:
puppeteer.launch()
的参数解释:其使用字典进行配置输入
turn
和 false
turn
无头浏览器,不展示浏览器页面false
参数,展示浏览器页面['--start-maximized']
false
表示忽略 https 报错page.goto
: 打开新页面
page.goBack
: 回退到上一个页面
page.goForward
: 前进到下一个页面
page.reload
: 重新加载页面
page.waitForNavigation
: 等待页面跳转
Pupeeteer 中的基本上所有的操作都是异步的,以上几个 API 都涉及到关于打开一个页面,什么情况下才能判断这个函数执行完毕呢,这些函数都提供了两个参数 waitUtil 和 timeout , waitUtil 表示直到什么出现就算执行完毕,timeout 表示如果超过这个时间还没有结束就抛出异常。
page.waitForXPath
: 等待 XPath 对应的元素出现,返回对应的 ElementHandle 实例
page.waitForSelector
: 等待选择器对应的元素出现,返回对应的 ElementHandle 实例
page.waitForResponse
: 等待某个响应结束,返回 Response 实例
page.waitForRequest
: 等待某个请求出现,返回 Request 实例
page.waitForFunction
: 等待在页面中自定义函数的执行结果,返回 JsHandle 实例page.waitFor
: 设置等待时间,实在没办法的做法page.$('#uniqueId')
: 获取某个选择器对应的第一个元素page.$$('div')
: 获取某个选择器对应的所有元素page.$x('//img')
: 获取某个 XPath 对应的所有元素page.waitForXPath('//img')
: 等待某个 XPath 对应的元素出现page.waitForSelector('#uniqueId')
: 等待某个选择器对应的元素出现elementHandle.click()
: 点击某个元素elementHandle.tap()
: 模拟手指触摸点击elementHandle.focus()
: 聚焦到某个元素elementHandle.hover()
: 鼠标 hover 到某个元素上elementHandle.type('hello')
: 在输入框输入文本我们可以在监听 Page 的 request 事件,并进行请求拦截,前提是要开启请求拦截 page.setRequestInterception(true)
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const blockTypes = new Set(['image', 'media', 'font']);
await page.setRequestInterception(true); //开启请求拦截
page.on('request', request => {
const type = request.resourceType();
const shouldBlock = blockTypes.has(type);
if(shouldBlock){
//直接阻止请求
return request.abort();
}else{
//对请求重写
return request.continue({
//可以对 url,method,postData,headers 进行覆盖
headers: Object.assign({}, request.headers(), {
'puppeteer-test': 'true'
})
});
}
});
await page.goto('https://demo.youdata.com');
await page.close();
await browser.close();
})();
page 页面上都提供的触发事件:
page.on('close')
页面关闭page.on('console')
console API 被调用page.on('error')
页面出错page.on('load')
页面加载完page.on('request')
收到请求page.on('requestfailed')
请求失败page.on('requestfinished')
请求成功page.on('response')
收到响应page.on('workercreated')
创建 webWorker
page.on('workerdestroyed')
销毁 webWorker
Puppeteer 目前没有提供原生的用于处理 WebSocket 的 API 接口,但是我们可以通过更底层的 Chrome DevTool Protocol (CDP) 协议获得
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
//创建 CDP 会话
let cdpSession = await page.target().createCDPSession();
//开启网络调试,监听 Chrome DevTools Protocol 中 Network 相关事件
await cdpSession.send('Network.enable');
//监听 webSocketFrameReceived 事件,获取对应的数据
cdpSession.on('Network.webSocketFrameReceived', frame => {
let payloadData = frame.response.payloadData;
if(payloadData.includes('push:query')){
//解析payloadData,拿到服务端推送的数据
let res = JSON.parse(payloadData.match(/\{.*\}/)[0]);
if(res.code !== 200){
console.log(`调用websocket接口出错:code=${res.code},message=${res.message}`);
}else{
console.log('获取到websocket接口数据:', res.result);
}
}
});
await page.goto('https://netease.youdata.163.com/dash/142161/reportExport?pid=700209493');
await page.waitForFunction('window.renderdone', {polling: 20});
await page.close();
await browser.close();
})();
await page.evaluate(() => {
// document.getElementById("#menus").classList.add("menus-show");
// let menus = document.querySelector('#menus') as HTMLDivElement
// menus.classList.add('menus-show')
// console.log(menus)
let button = document.querySelector('#all_menus_item') as HTMLDivElement
button.addEventListener('click', function(){
console.log("点击【全部产品】")
})
})
有哪些函数可以在浏览器环境中执行代码:
page.evaluate(pageFunction[, ...args])
: 在浏览器环境中执行函数page.evaluateHandle(pageFunction[, ...args])
: 在浏览器环境中执行函数,返回 JsHandle 对象page.$$eval(selector, pageFunction[, ...args])
: 把 selector 对应的所有元素传入到函数并在浏览器环境执行page.$eval(selector, pageFunction[, ...args])
: 把 selector 对应的第一个元素传入到函数在浏览器环境执行page.evaluateOnNewDocument(pageFunction[, ...args])
: 创建一个新的 Document 时在浏览器环境中执行,会在页面所有脚本执行之前执行page.exposeFunction(name, puppeteerFunction)
: 在 window 对象上注册一个函数,这个函数在 Node 环境中执行,有机会在浏览器环境中调用 Node.js 相关函数库Puppeteer 提供了对页面性能分析的工具,目前功能还是比较弱的,只能获取到一个页面性能执行的数据
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.tracing.start({path: './files/trace.json'});
await page.goto('https://www.google.com');
await page.tracing.stop();
/*
continue analysis from 'trace.json'
*/
browser.close();
})();
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
//通过 CDP 会话设置下载路径
const cdp = await page.target().createCDPSession();
await cdp.send('Page.setDownloadBehavior', {
behavior: 'allow', //允许所有下载请求
downloadPath: 'path/to/download' //设置下载路径
});
//点击按钮触发下载
await (await page.waitForSelector('#someButton')).click();
//等待文件出现,轮训判断文件是否出现
await waitForFile('path/to/download/filename');
//上传时对应的 inputElement 必须是<input>元素
let inputElement = await page.waitForXPath('//input[@type="file"]');
await inputElement.uploadFile('/path/to/file');
browser.close();
})();
let page = await browser.newPage();
await page.goto(url);
let btn = await page.waitForSelector('#btn');
//在点击按钮之前,事先定义一个 Promise,用于返回新 tab 的 Page 对象
const newPagePromise = new Promise(res =>
browser.once('targetcreated',
target => res(target.page())
)
);
await btn.click();
//点击按钮后,等待新tab对象
let newPage = await newPagePromise;
Puppeteer 提供了模拟不同设备的功能,其中 puppeteer.devices 对象上定义很多设备的配置信息,这些配置信息主要包含 viewport 和 userAgent,然后通过函数 page.emulate 实现不同设备的模拟
const puppeteer = require('puppeteer');
const iPhone = puppeteer.devices['iPhone 6'];
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.emulate(iPhone);
await page.goto('https://www.google.com');
await browser.close();
});
// 模拟键盘“回车”键
await page.keyboard.press('Enter');