模擬瀏覽器操作神器Puppeteer初探
介紹
??剛接觸到puppeteer征讲,并不是用來做爬蟲震桶,只是想做一個(gè)后臺數(shù)據(jù)推送及性能數(shù)據(jù)抓取的功能竣况,需要模擬登陸內(nèi)部系統(tǒng)爬取數(shù)據(jù)截圖鹊杖。一開始想到利用很多方案坯沪,像wkhtmltopdf, phantomjs等等绿映,他們都是類瀏覽器的環(huán)境,因?yàn)橹笆褂眠^,都知道他們或多或少都存在些問題叉弦。再后來發(fā)現(xiàn)了headless丐一,谷歌的無頭瀏覽器服務(wù),這個(gè)最接近真實(shí)瀏覽器的東西(應(yīng)該說就是個(gè)瀏覽器吧)淹冰,然后決定采用headless钝诚,網(wǎng)上最多的是采用lighthouse作為操作headless的nodejs接口工具,后來看到puppeteer,和lighthouse差不多榄棵,但畢竟是谷歌團(tuán)隊(duì)自己維護(hù)的工具凝颇,當(dāng)然就選擇了它,后來看了看疹鳄,果然還是它用起來比較方便拧略。
??官方對于puppeteer的介紹(翻譯過來):
puppeteer由Chrome團(tuán)隊(duì)開發(fā)的Node庫。它提供了一個(gè)高級API來控制無頭(或完整)Chrome瘪弓。它與Phantom和NightmareJS等其他自動化測試庫類似垫蛆,但它只適用于最新版本的Chrome。
除此之外腺怯,Puppeteer還可用于輕松截取屏幕截圖袱饭,創(chuàng)建PDF绷杜,導(dǎo)航頁面以及獲取有關(guān)這些頁面的信息庙睡。如果您想快速自動化瀏覽器測試创橄,我建議使用該庫耙饰。它隱藏了DevTools協(xié)議的復(fù)雜性歇竟,并負(fù)責(zé)啟動Chrome的調(diào)試實(shí)例等冗余任務(wù)>
??看起來很強(qiáng)大對不對玉组,實(shí)時(shí)上除了無頭模式耍目,Puppeteer也可以操作真實(shí)瀏覽器進(jìn)行工作房交,你會發(fā)現(xiàn)它除了可以做完美的爬蟲之外帜篇,對于自動化的ui測試也是利器糙捺。目前也有了中文文檔,使用起來也是極其方便的
截圖
讓我們先來看一下它的api,首先是puppteer對象笙隙,用于啟動一個(gè)Chromium實(shí)例洪灯,例子:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.google.com');
// 其他操作...
await browser.close();
});
??上圖實(shí)際是打開了一個(gè)瀏覽器應(yīng)用,lauch方法支持一個(gè)對象類型的參數(shù)竟痰,其中可以指定headless為true還是false,當(dāng)指定為true是签钩,可以觀察到實(shí)際行為,在我們測試的時(shí)候還是很有用處的凯亮,當(dāng)我們設(shè)置為true是可以觀察到边臼,browser對象針對的是整個(gè)瀏覽器窗口,而page對象針對的是每個(gè)tab頁簽假消,當(dāng)關(guān)閉browser對象時(shí)柠并,所有page對象都會被銷毀,如果想要單獨(dú)銷毀page對象可以調(diào)用page.close();
??在實(shí)際應(yīng)用中,page對象是我們最常用的對象臼予,下面是使用page對象打開一個(gè)頁面并進(jìn)行截圖的例子:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.baidu.com');
// 截圖...
await page.screenshot({path:'xx/xx.png',type:'png',quality:100,fullPage:true});
await browser.close();
});
這里介紹下截圖的幾個(gè)參數(shù):
- path:圖片存儲路徑
- type: 圖片格式鸣戴,默認(rèn)png
- quality: 圖片質(zhì)量0-100的值,png格式無效
- fullpage: 是否截取整個(gè)頁面粘拾,如果不設(shè)置窄锅,截取的是窗口打開部分,并不是全頁面缰雇,默認(rèn)打開的窗口是800x600大小入偷,如果想截取更完美的大小需要調(diào)整視窗大小,通過設(shè)置launch的defaultViewport參數(shù)械哟。
性能數(shù)據(jù)獲取
puppteer也支持我們在打開頁面時(shí)進(jìn)行一些性能數(shù)據(jù)的采集疏之,page.metrics()方法可以幫我們獲取到頁面打開過程中的性能參數(shù):
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.target.com');
// 獲取頁面性能數(shù)據(jù)...
const result = await page.metrics();
console.log(result);
await browser.close();
});
返回結(jié)果包括:
- Timestamp <number> 時(shí)間點(diǎn)(when the metrics sample was taken)
- Documents <number> 頁面的documents數(shù)量。
- Frames <number> 頁面的iframe數(shù)量暇咆。
- JSEventListeners <number> 頁面的js事件數(shù)量锋爪。
- Nodes <number> 頁面的dom節(jié)點(diǎn)數(shù)量。
- LayoutCount <number> 整頁面或部分頁面的布局?jǐn)?shù)量爸业。
- RecalcStyleCount <number> 頁面樣式重新計(jì)算數(shù)量其骄。
- LayoutDuration <number> 頁面布局總時(shí)間。
- RecalcStyleDuration <number> 頁面樣式重新計(jì)算總時(shí)間扯旷。
- ScriptDuration <number> 頁面js代碼執(zhí)行總時(shí)間拯爽。
- TaskDuration <number> 頁面任務(wù)執(zhí)行總時(shí)間。
- JSHeapUsedSize <number> 頁面占用堆內(nèi)存大小薄霜。
-
JSHeapTotalSize <number> 總的頁面堆內(nèi)存大小某抓。
還有另外一個(gè)api,用于獲取我們平時(shí)利用瀏覽器觀察頁面加載性能的performance視圖惰瓜,它會生成和谷歌瀏覽器中profile.json一樣的一個(gè)json數(shù)據(jù),我們可以導(dǎo)入瀏覽器中查看
相關(guān)代碼:
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.tracing.start({path: 'trace.json'});
await page.goto('https://www.target.com');
await page.tracing.stop();
await browser.close();
});
我們拿到.json文件后也可以訪問DevTools Timeline Viewer導(dǎo)入去查看頁面加載的詳細(xì)信息汉矿。
那么對于性能數(shù)據(jù)來說崎坊,我們最常用的手機(jī)api就是performance.timing這個(gè)對象了,那么我們?nèi)绻趐uppteer中去獲取并收集數(shù)據(jù)呢洲拇?下面看一個(gè)例子:
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.target.com',{
waitUntil:'networkidle0'
});
const timing = await page.evaluate(() => (window.performance.timing.toJSON()));
console.log(timing);
await browser.close();
});
上面的goto方法內(nèi)我加了一個(gè)參數(shù)networkidle0奈揍,意思是不再有任何網(wǎng)絡(luò)連接時(shí)觸發(fā)(至少500毫秒后)后才算頁面跳轉(zhuǎn)完成,這么做是為了等頁面完全加載結(jié)束赋续,獲得最準(zhǔn)確的數(shù)據(jù)男翰,在evaluate方法內(nèi)可以使用page對象內(nèi)的上下文,也就是當(dāng)前頁面的dom對象都是可以使用的纽乱,這樣就拿到了timing數(shù)據(jù)蛾绎。
最后
除此之外,也可以利用puppteer的Coverage對象獲取js以及css的代碼覆蓋率,這里就不做過多介紹了租冠,感興趣的同學(xué)可以自行研究鹏倘。
參考文章:https://developers.google.com/web/updates/2017/04/headless-chrome
???????https://zhaoqize.github.io/puppeteer-api-zh_CN/#/