本文適用於對docker,node有一定了解的童鞋
Puppeteer簡介
今年5月在github上建立的專案,屬於比較新的chromium無頭瀏覽器類庫。
Puppeteer在專案中的實際使用
基礎安裝
選用Puppeteer的主要原因有兩點,
- 1:GOOGLE官方維護,活躍度很高,個人覺得前途光明。
- 2:我們的產品在chrome上適配最好。目前最新版本是
0.13.0
,我們採用0.12.0
版本,因0.13.0
版本API做了一些變化無法滿足我們的需求。我們截圖時有如下兩個必須解決的場景- 網站需要等待當前儀表盤所有查詢都完成才可以進行截圖操作
- 我們並不知道所有儀表盤發起的查詢會查詢多久結束
npm安裝puppeteer時會從google一個網站上下載chromium,因為牆的原因會下載失敗。我們採用的方式先設定環境變數
set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
複製程式碼
阻止install的時候自動下載,然後手工下載chromium後通過docker build打包成一個基礎映象。我們在Dockerfile中From此映象,然後再做後續操作。
npm instal puppeteer@0.12.0 --save
複製程式碼
現在可通過docker很快速的進行打包。最終打包後的image裡/usr/src/node/包含node程式碼及chromium目錄
基本操作
呼叫puppeteer
我們手動指定chromium目錄來執行。
const browser = await puppteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'], // docker中執行需要加上這兩個args
executablePath: 'chromium/chrome', // 基礎映象已將chromium複製到/usr/src/node/chromium目錄下
});
複製程式碼
儲存圖片
通過URL開啟網站
await page.goto(fullUrl, {
waitUntil: 'networkidle',
networkIdleTimeout: 15000,
timeout: 240000
});
複製程式碼
networkIdleTimeout: 15000
引數代表當前頁面網路處於idle狀態至少15秒
時導航完畢,避免匯出的截圖資料不全。
如果直接儲存整個頁面為圖片或PDF是很簡單的,有現成的API直接呼叫。但這次我們只將某一區域儲存為圖片,
let rect = await page.evaluate(() => {
const element = document.querySelector(
'.class1'
); // 選擇包含指定class屬性的dom節點
const { x, y, width, height } = element.getBoundingClientRect();
return {
left: x,
top: y,
width,
height,
};
});
await page.screenshot({
path: imagePath,
clip: {
x: rect.x,
y: rect.y,
width: actualWidth,
height: actualHeight
}
});
複製程式碼
可以在page.evaluate中操作頁面元素,所以可以獲取指定區域的長寬等資訊。這樣我們只需擷取那一區域即可。完整的API地址還是請參閱github官方API文件
儲存PDF
如上節所說,如果儲存整個頁面為PDF很簡單,因為我們只儲存某一區域,然而儲存pdf的API中沒有類似page.screenshot中clip引數,我的處理方式就是將上一步儲存的圖片轉為PDF即可。轉換方式很多,我採用pdfkit
類庫實現。程式碼就不贅述,可以參考很多DEMO。
總結
因為我們通過docker+CICD+devops打包部署node服務,puppeteer在docker中也有一些坑,好在官方給出了一系列解決方案。我在實際使用中還是偶爾發生頁面載入失敗的情況,期望在未來版本會變得更加強大和穩定。