puppeteer 螢幕截圖轉 base64 編碼問題

Emmie Lin
4 min readSep 11, 2019

--

puppeteer 提供了一組操控 chrome 的 API,藉由這些 API 我們可以模擬使用者進行頁面上的各種操作,很適合拿來當作爬蟲工具。最近正好專案有使用到這個 library,遇到了螢幕截圖的問題,進行各種搜尋都很少有直接的解答,只好自己摸了一番。

進入正題,要實現螢幕截圖並把圖片保存下來其實很簡單,但我這次要做的是在後端接收到請求後直接把圖片的 base64 編碼吐出來,準備讓前端去接,所以一開始寫的 code 是這樣:

把得到的 data URL 丟到瀏覽器上,結果在某些頁面會顯示只截到一半或不完整的圖片,如圖:

只有截到不到一半的圖 QWQ

這時候我就想說該不會是在執行 page.goto() 的時候沒有等待夠長的時間,導致執行 page.screenshot() 的時候還沒有拿到解析完整的頁面。(從這時候開始離真相愈來愈遠)於是開始找了各種延遲等候的方法,甚至在這兩個 function 之間加了延遲5秒的 function,結果依舊,每次爬這個頁面都只拿到半殘的圖。但就整體而言其實還是有收獲的啦,page.goto() 的第二個參數可以帶某些設定為一物件,這裡我使用了 timeoutwaitUntil

  • timeout<number> :連接超時時間,預設值為30秒,設為0等同禁用此選項。
  • waitUntil<string|array<string>>:確認導航成功的條件,預設為 load,可以為字串或陣列,若為陣列,會等到該陣列中每個事件都被觸發後才會認為導航成功,可選的事件包括:load、domcontentloaded、networkidle0、networkidle2,在此處使用了networkidle2表示「如果在500毫秒內發起的請求數不超過兩條,則認為導航結束」。

所以加了這兩個設定後,至少可以確保我們的畫面會是在該頁面大部分的請求都發完後才會回傳結果(但在此處沒有去接結果,而是等他執行完後繼續下一行 code)。

不對啊!!我的圖還是沒成功跑出來啊!

折騰好大一番之後,智障如我才終於意識到好像不是頁面沒載完的問題,而是 base64 檔案的問題,仔細觀察被抓下來的 base64 碼,在這個會得到半殘圖的頁面的 base64 總共有 100 多萬碼,而可以正常顯示的頁面則才 20~40萬左右而已,所以我暫下的結論就是: 檔案太大了!

那,該怎麼辦呢?這時候只好乖乖回去啃文件,希望有一些可以設定圖片解析度或尺寸的方法,於是我找到了可以在 page.screenshot() 第一個參數多帶一些屬性設定:

  • type<string>:可選值有 jpeg 和 png ,預設為 png。(看到這裏我才知道原來預設是png難怪我手動改 data URL 的 mediatype 就直接死掉了QAQ)
  • quality<number> :圖片質量,可選值為 0–100,不適用於 png。

所以透過這兩個屬性,我把 type 改成 jpeg,質量給他調到 50,就成功讓檔案變小了,再度觀察原本 100多萬的 base64 code 剩下10幾萬而已,理所當然圖片也顯示出來啦!

不過還有個疑惑就是不太確定是編碼本身有受損,還是瀏覽器顯示的問題?(沈默三秒)總之算是完成就先收工啦!這個問題如果我有解的話下次再補充~

附上參考資料:

--

--