免責(zé)聲明:本人博客所有文章純屬學(xué)習(xí)之用,不涉及商業(yè)利益。不合適引用,自當(dāng)刪除!
先說(shuō)一些廢話
因?yàn)槭菧y(cè)試,沒(méi)有給出項(xiàng)目的具體搭建流程。
Puppeteer是谷歌官方出品的一個(gè)通過(guò)DevTools協(xié)議控制headless Chrome的Node庫(kù)。可以通過(guò)Puppeteer的提供的api直接控制Chrome模擬大部分用戶操作來(lái)進(jìn)行UI Test或者作為爬蟲(chóng)訪問(wèn)頁(yè)面來(lái)收集數(shù)據(jù)。所以開(kāi)發(fā)語(yǔ)言當(dāng)然也就是js啦。
Github項(xiàng)目地址:puppeteer
puppeteer API:puppeteer API,現(xiàn)在看的時(shí)候版本是1.7.0。
puppeteer的簡(jiǎn)單使用,大家可以參照官網(wǎng)上的demo,或者百度出來(lái)的文章,都會(huì)有相關(guān)的代碼,但是似乎puppeteer用的人相對(duì)較少,所以真實(shí)資料也少很多。能找到的文章就是那么幾篇。至于puppeteer的安裝就不累訴了,搜索一下,相信各位能找到,這里主要是針對(duì)使用puppeteer對(duì)訪問(wèn)網(wǎng)頁(yè)后,對(duì)全網(wǎng)頁(yè)進(jìn)行截圖(無(wú)對(duì)網(wǎng)頁(yè)重出現(xiàn)的特殊場(chǎng)景進(jìn)行處理,如:驗(yàn)證碼、登錄框等)。
以https://www.jd.com為例。注意點(diǎn):需要翻頁(yè),否則頁(yè)面加載不全,則截圖時(shí),展示不全。后續(xù)會(huì)有優(yōu)化版。
上代碼
無(wú)翻頁(yè)版本,寫到這里就簡(jiǎn)單的給出類似demo的例子:
// 導(dǎo)入包
const puppeteer =require('puppeteer');
(async () => {
// 啟動(dòng)Chromium
? ? const browser =await puppeteer.launch({ignoreHTTPSErrors:true, headless:false, args: ['--no-sandbox']});
? ? // 打開(kāi)新頁(yè)面
? ? const page =await browser.newPage();
? ? // 設(shè)置頁(yè)面分辨率
? ? await page.setViewport({width:1920, height:1080});
? ? let request_url ='https://www.jd.com';
? ? // 訪問(wèn)
? ? await page.goto(request_url, {waitUntil:'domcontentloaded'}).catch(err => console.log(err));
? ? await page.waitFor(1000);
? ? let title =await page.title();
? ? console.log(title);
? ? try {
// 截圖
? ? ? ? await page.screenshot({path:"jd.jpg", fullPage:true}).catch(err => {
console.log('截圖失敗');
? ? ? ? ? ? console.log(err);
? ? ? ? });
? ? ? ? await page.waitFor(5000);
? ? }catch (e) {
console.log('執(zhí)行異常');
? ? }finally {
await browser.close();
? ? }
})();
運(yùn)行結(jié)果截圖:

可以發(fā)現(xiàn),圖片缺失嚴(yán)重,不管你在代碼中等待多久,都是沒(méi)用的,需要對(duì)頁(yè)面進(jìn)行滾動(dòng),觸發(fā)頁(yè)面的滾動(dòng)事件。滾動(dòng)版本,這個(gè)版本可以實(shí)現(xiàn)滾動(dòng),但是覺(jué)得代碼寫的不好,而且對(duì)個(gè)別一些網(wǎng)站不兼容,所以才成為第一個(gè)版本:
const puppeteer =require('puppeteer');
(async () => {
// 啟動(dòng)Chromium
? ? const browser =await puppeteer.launch({ignoreHTTPSErrors:true, headless:false, args: ['--no-sandbox']});
? ? // 打開(kāi)新頁(yè)面
? ? const page =await browser.newPage();
? ? // 設(shè)置頁(yè)面分辨率
? ? await page.setViewport({width:1920, height:1080});
? ? let request_url ='https://www.jd.com';
? ? // 訪問(wèn)
? ? await page.goto(request_url, {waitUntil:'domcontentloaded'}).catch(err => console.log(err));
? ? await page.waitFor(1000);
? ? let title =await page.title();
? ? console.log(title);
? ? // 網(wǎng)頁(yè)加載最大高度
? ? const max_height_px =20000;
? ? // 滾動(dòng)高度
? ? let scrollStep =1080;
? ? let height_limit =false;
? ? let mValues = {'scrollEnable':true, 'height_limit': height_limit};
? ? while (mValues.scrollEnable) {
mValues =await page.evaluate((scrollStep, max_height_px, height_limit) => {
// 防止網(wǎng)頁(yè)沒(méi)有body時(shí),滾動(dòng)報(bào)錯(cuò)
? ? ? ? ? ? if (document.scrollingElement) {
let scrollTop = document.scrollingElement.scrollTop;
? ? ? ? ? ? ? ? document.scrollingElement.scrollTop = scrollTop + scrollStep;
? ? ? ? ? ? ? ? if (null != document.body && document.body.clientHeight > max_height_px) {
height_limit =true;
? ? ? ? ? ? ? ? }else if (document.scrollingElement.scrollTop + scrollStep > max_height_px) {
height_limit =true;
? ? ? ? ? ? ? ? }
let scrollEnableFlag =false;
? ? ? ? ? ? ? ? if (null != document.body) {
scrollEnableFlag = document.body.clientHeight > scrollTop +1081 && !height_limit;
? ? ? ? ? ? ? ? }else {
scrollEnableFlag = document.scrollingElement.scrollTop + scrollStep > scrollTop +1081 && !height_limit;
? ? ? ? ? ? ? ? }
return {
'scrollEnable': scrollEnableFlag,
? ? ? ? ? ? ? ? ? ? 'height_limit': height_limit,
? ? ? ? ? ? ? ? ? ? 'document_scrolling_Element_scrollTop': document.scrollingElement.scrollTop
? ? ? ? ? ? ? ? };
? ? ? ? ? ? }
}, scrollStep, max_height_px, height_limit);
? ? ? ? await sleep(800);
? ? }
try {
await page.screenshot({path:"jd.jpg", fullPage:true}).catch(err => {
console.log('截圖失敗');
? ? ? ? ? ? console.log(err);
? ? ? ? });
? ? ? ? await page.waitFor(5000);
? ? }catch (e) {
console.log('執(zhí)行異常');
? ? }finally {
await browser.close();
? ? }
})();
//延時(shí)函數(shù)
function sleep(delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(1)
}catch (e) {
reject(0)
}
}, delay)
})
}
結(jié)果截圖:

可以看到,效果還是可以的,至于等待時(shí)間,需要根據(jù)你的網(wǎng)絡(luò)環(huán)境進(jìn)行延時(shí)。當(dāng)然,此版本只是為了大家學(xué)習(xí)。