關注公眾號「執鳶者」,回復「資料」獲取500G資料(各「兵種」均有),還有專業交流群等你一起來瀟灑。(哈哈)
本文主要講述一下Google出版並一直在不斷維護的神器puppeteer,通過學習本文你將了解其基本使用和常用功能。
一、Puppeteer簡介Puppeteer 是一個 Node 庫,它提供了一個高級 API 來通過 DevTools 協議控制 Chromium 或 Chrome,利用Puppeteer可以獲取頁面DOM節點、網絡請求和響應、程序化操作頁面行為、進行頁面的性能監控和優化、獲取頁面截圖和PDF等,利用該神器就可以操作Chrome瀏覽器玩出各種花樣。
二、Puppeteer核心組成結構Puppeteer的結構也反映了瀏覽器的結構,其核心結構如下所示:
Browser:這是一個瀏覽器實例,可以擁有瀏覽器上下文,可通過 puppeteer.launch 或 puppeteer.connect 創建一個 Browser 對象。
BrowserContext:該實例定義了一個瀏覽器上下文,可擁有多個頁面,創建瀏覽器實例時默認會創建一個瀏覽器上下文(不能關閉),此外可以利用 browser.createIncognitoBrowserContext()創建一個匿名的瀏覽器上下文(不會與其它瀏覽器上下文共享cookie/cache).
Page:至少包含一個主框架,除了主框架外還有可能存在其它框架,例如iframe。
Frame:頁面中的框架,在每個時間點,頁面通過page.mainFrame()和frame.childFrames()方法暴露當前框架的細節。對於該框架中至少有一個執行上下文
ExecutionCOntext:表示一個JavaScript的執行上下文。
Worker:具有單個執行上下文,便於與 WebWorkers 交互。
三、基本使用和常用功能該神器整體使用起來比較簡單,下面就開始我們的使用之路。
3.1 啟動Browser核心函數就是異步調用puppeteer.launch()函數,根據相應的配置參數創建一個Browser實例。
const path = require('path');
const puppeteer = require('puppeteer');
const chromiumPath = path.join(__dirname, '../', 'chromium/chromium/chrome.exe');
async function main() {
// 啟動chrome瀏覽器
const browser = await puppeteer.launch({
// 指定該瀏覽器的路徑
executablePath: chromiumPath,
// 是否為無頭瀏覽器模式,默認為無頭瀏覽器模式
headless: false
});
}
main();
訪問頁面首先需要創建一個瀏覽器上下文,然後基於該上下文創建一個新的page,最後指定要訪問的網址。
async function main() {
// 啟動chrome瀏覽器
// ……
// 在一個默認的瀏覽器上下文中被創建一個新頁面
const page1 = await browser.newPage();
// 空白頁訪問該指定網址
await page1.goto('https://51yangsheng.com');
// 創建一個匿名的瀏覽器上下文
const browserContext = await browser.createIncognitoBrowserContext();
// 在該上下文中創建一個新頁面
const page2 = await browserContext.newPage();
page2.goto('https://www.baidu.com');
}
main();
經常需要不同類型的機型的瀏覽結果,此時就可以採用設備模擬實現,下面模擬一個iPhone X的設備的瀏覽器結果
async function main() {
// 啟動瀏覽器
// 設備模擬:模擬一個iPhone X
// user agent
await page1.setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1')
// 視口(viewport)模擬
await page1.setViewport({
width: 375,
height: 812
});
// 訪問某頁面
}
main();
獲取DOM節點有兩種方式,一種方式是直接調用page所帶的原生函數,另一種是通過執行js代碼獲取。
async function main() {
// 啟動chrome瀏覽器
const browser = await puppeteer.launch({
// 指定該瀏覽器的路徑
executablePath: chromiumPath,
// 是否為無頭瀏覽器模式,默認為無頭瀏覽器模式
headless: false
});
// 在一個默認的瀏覽器上下文中被創建一個新頁面
const page1 = await browser.newPage();
// 空白頁訪問該指定網址
await page1.goto('https://www.baidu.com');
// 等待title節點出現
await page1.waitForSelector('title');
// 用page自帶的方法獲取節點
const titleDomText1 = await page1.$eval('title', el => el.innerText);
console.log(titleDomText1);// 百度一下
// 用js獲取節點
const titleDomText2 = await page1.evaluate(() => {
const titleDom = document.querySelector('title');
return titleDom.innerText;
});
console.log(titleDomText2);
}
main();
下面就來監聽一下百度中某一js腳本的請求和響應,request事件是監聽請求,response事件是監聽響應。
async function main() {
// 啟動chrome瀏覽器
const browser = await puppeteer.launch({
// 指定該瀏覽器的路徑
executablePath: chromiumPath,
// 是否為無頭瀏覽器模式,默認為無頭瀏覽器模式
headless: false
});
// 在一個默認的瀏覽器上下文中被創建一個新頁面
const page1 = await browser.newPage();
page1.on('request', request => {
if (request.url() === 'https://s.bdstatic.com/common/openjs/amd/eslx.js') {
console.log(request.resourceType());
console.log(request.method());
console.log(request.headers());
}
});
page1.on('response', response => {
if (response.url() === 'https://s.bdstatic.com/common/openjs/amd/eslx.js') {
console.log(response.status());
console.log(response.headers());
}
})
// 空白頁剛問該指定網址
await page1.goto('https://www.baidu.com');
}
main();
默認情況下request事件只有隻讀屬性,不能夠攔截請求,若想攔截該請求則需要通過page.setRequestInterception(value)啟動請求攔截器,然後利用request.abort, request.continue 和 request.respond 方法決定該請求的下一步操作。
async function main() {
// 啟動chrome瀏覽器
const browser = await puppeteer.launch({
// 指定該瀏覽器的路徑
executablePath: chromiumPath,
// 是否為無頭瀏覽器模式,默認為無頭瀏覽器模式
headless: false
});
// 在一個默認的瀏覽器上下文中被創建一個新頁面
const page1 = await browser.newPage();
// 攔截請求開啟
await page1.setRequestInterception(true);// true開啟,false關閉
page1.on('request', request => {
if (request.url() === 'https://s.bdstatic.com/common/openjs/amd/eslx.js') {
// 終止該請求
request.abort();
console.log('該請求被終止!!!');
}
else {
// 繼續該請求
request.continue();
}
});
// 空白頁訪問該指定網址
await page1.goto('https://www.baidu.com');
}
main();
截圖是一個很有用的功能,通過截取就可以保存一份快照,方便後期問題的排查。(註:在無頭模式下進行截圖,否則截的圖可能有問題)
async function main() {
// 啟動瀏覽器,訪問頁面的操作
// 截屏操作,使用Page.screenshot函數
// 截取整個頁面:Page.screenshot函數默認截取整個頁面,加上fullPage參數就是全屏截取
await page1.screenshot({
path: '../imgs/fullScreen.png',
fullPage: true
});
// 截取屏幕中一個區域的內容
await page1.screenshot({
path: '../imgs/partScreen.jpg',
type: 'jpeg',
quality: 80,
clip: {
x: 0,
y: 0,
width: 375,
height: 300
}
});
browser.close();
}
main();
除了利用截圖保留快照外,還可以使用pdf保留快照。
async function main() {
// 啟動瀏覽器,訪問頁面的操作
// 根據網頁內容生成pdf文件,使用Page.pdf——注意:必須在無頭模式下才可以調用
await page1.pdf({
path: '../pdf/baidu.pdf'
});
browser.close();
}
main();
1.如果覺得這篇文章還不錯,來個分享、點讚、在看三連吧,讓更多的人也看到~
2.關注公眾號執鳶者,領取學習資料,定期為你推送原創深度好文
3.掃描下方添加進群,裡面大佬多多,一起向他們學習
1. 圖解JavaScript——代碼實現(Object.create()、flat()等十四種代碼原理實現不香嗎?)
2. 圖解JavaScript——代碼實現【2】(重點是Promise、Async、發布/訂閱原理實現)
3. 圖解javascript——基礎篇
4. 圖解JavaScript——進階篇
5. 十五張圖帶你徹底搞懂從URL到頁面展示發生的故事
6. 圖解瀏覽器安全(同源策略、XSS、CSRF、跨域、HTTPS、安全沙箱等串成糖葫蘆)
7. 六張圖帶你從HTTP/0.9進化到HTTP3.0
8. (2.6w字)網絡知識點靈魂拷問(上)——前端面試必問
9. (2.6w字)網絡知識點靈魂拷問(下)——前端面試必問
10. 理論與API相結合理解Node中的網絡通信
11. 硬核知識點——瀏覽器中的三類五種請求
12. 理論與實踐相結合徹底理解CORS
13. 三步法解析Express源碼
14. 一篇搞定前端高頻手撕算法題(36道)
15. 十七張圖玩轉Node進程——榨乾它
16. 理論與API相結合理解Node中的網絡通信
17. 一文徹底搞懂前端監控
18. 前端的葵花寶典——架構