google app script cheerio

GAS + Cheerio 分析網頁資訊寫入Google 試算表

江直穎 2020/12/30 11:55:19
6426

一.簡介

現在Google提供非常多免費服務,想必最常見就是透過Google文件、試算表、簡報、表單將資料存放於雲端上,方便隨時能不受限制的跨平台上使用。然而Google也提供可線上開發建置的後端服務Google App Script(GAS),可以透過撰寫JavaScript透過相關API呼叫各種服務,以達到各式各樣作業需求。

Cheerio:

是一個輕量化、易操作,以jQuery核心架構開發的HTML&XML檔案解析工具,且它比jsdom或其他方式來解析DOM元件來的更方便許多,只要透過Cheerio載入文檔,即可使用類似jQuery Selector方式輕鬆操作資料節點,快速取得並篩選相關資料。

 

二.實作目標

    1.於新建立的Google 試算表撰寫內崁的GAS程式碼

    2.使用官方提供的函式庫UrlFetchApp訪問電影資訊網站

    3.最後將透過Cheerio套件解析其中網頁提供之相關資料,並寫入試算表中

 

三.事前準備

由於GAS上的環境不能直接使用各種前端js套件,需要使用包裝過的版本,經過查找後發現國外網友撰寫提供GAS版本(cheeriogs)

Cheerio函式庫,這部分待會需要透過Script ID加入函式庫,並依照說明文件指示使用 "load" function 載入並解析文檔來執行操作

 

參考Google App Script API : Spreadsheet  "appendRow" function 來實作寫入資料至試算表內步驟

 

 

四.實作與測試

於Google Drive上建立一個名稱為MovieListDemo試算表

 

透過試算表"工具"->"指令碼編輯器" 來建立Google App Script 其中會自動建立一個名為myFunction 的函式,即可以開始撰寫此函式要執行的流程

 

接著於左側功能選項 "資料庫" -> "+"按鈕來載入Cheerio 函式庫

 

將剛才Cheerio 套件所需要的Script ID : -> 1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0  貼上並查詢

 

找到函式庫後選擇最新版本,按下新增按鈕即可載入

 

新增後回到編輯列表左側,即可看見Cheerio函式庫被載入

 

參考上方事前準備步驟的 GAS API,此部份先測試是否能透過 SpreadsheetApp物件取得要操作的工作表MovieList1 

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("MovieList1");

 

並加入測試寫入表格方法appendRow 的Function

 

按下上方"執行"按鈕後,若為第一次執行寫入試算表時會通知該動作需要授權,按下審查權限即會檢核Google帳戶登入狀態,允許存取相關功能即可

 

觀察試算表文件結果已有寫入一行兩列的資料

 

測試appendRow能夠正常執行後,開始實作部分,首先需要連結外部網頁,使用GAS 全域函式庫 UrlFetchApp 物件中 "fetch" function 來取得網頁內容並放入response中

var response = UrlFetchApp.fetch("https://movies.yahoo.com.tw/movie_intheaters.html");

 

接著透過Cheerio 函式庫 Cheerio物件 "load"方法取得剛才的response內容,並將decode功能關掉

//需要加上decodeEntities:false 關閉讀取中文網頁編碼功能,以避免解析時遇到亂碼問題 
var $ = Cheerio.load(response.getContentText(),{ decodeEntities: false }); 

 

可以使用GAS提供Log輸出語法Logger.log(),來測試解析過的資料以jQuery撰寫方式呼叫 .html() 的輸出內容

Logger.log($.html());

 

參考並分析要抓取資料的電影資訊網站,找到清單列表的css 樣式class

 

分析完要抓取的網頁原始碼後,接著就需要透過程式找出各網頁節點,並實際操作取得資料

 

實際執行結果,資料皆有正確寫入試算表格中

 

以上為手動按下執行按鈕後產出資料的結果,GAS也提供觸發條件(Trigger)功能,讓開發者可以排程執行程式碼,

只需要按下左側功能表  -> 觸發條件 -> 新增觸發條件

 

新增觸發條件,GAS有提供多種方式,可以選擇常用且直覺的"時間觸發"方式設定,即可透過排程來執行選擇的功能

 

最後附上程式碼:

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("MovieList1");

function demoExecuteFunc() {
  var response = UrlFetchApp.fetch("https://movies.yahoo.com.tw/movie_intheaters.html");

//需要加上decodeEntities:false 關閉讀取中文網頁編碼功能,以避免解析時遇到亂碼問題 
  var $ = Cheerio.load(response.getContentText(),{ decodeEntities: false }); 

  writeToSheetDataForHeader();

  // 解析並抓取最外層的電影清單表格(div class=release_list) 並只取得release_info_text內電影資訊
  var releaseList = $(".release_list li .release_info_text"); 

    for (let i = 0; i < releaseList.length; i++) {
        var movie = releaseList.eq(i); // 擷取單一電影資訊
        var releaseTime = movie.find('.release_movie_time').text().split(" : ")[1]; //只取得上映時間部分
        var name = movie.find('.release_movie_name').find('a').eq(0).text().trim();  //取得電影名稱-中文
        var engName = movie.find('.release_movie_name').find('a').eq(1).text().trim(); //取得電影名稱-英文
        var movieName =  name + '( ' + engName + ' )' ; //組合完整電影名稱
        var expect = movie.find('dt').find('.leveltext').find('span').text();  //取得網友期待度
        var infoUrl = movie.find('.release_movie_name').find('a').eq(0).attr("href") ; //取得電影介紹網址
  
        writeToSheetData(Object.assign({ releaseTime , movieName , expect , infoUrl})); //將資料寫入google sheets
    }
}

function writeToSheetDataForHeader() {
  sheet.appendRow(['上映日期', '電影名稱', '網友期待度', '電影介紹網址']);
}

function writeToSheetData(param) {
  sheet.appendRow([param.releaseTime, param.movieName, param.expect, param.infoUrl]);
}

 

參考資料

https://developers.google.com/apps-script/reference

https://github.com/tani/cheeriogs

https://cheerio.js.org/

江直穎
D5B526CF0D0AE5E9B42788D09226C03D803956E769BF75429632F81D76DAA91C
2021/03/12 13:05:48

你好, 剛接觸GAS, 可惜沒有 JavaScript 的基礎. 你給的例子蠻清楚, 但在下對於如何輸入之後再抓取結果沒有頭緒, 以本例來說你是直接抓取 "上映中" 的頁面, 並且也有直接的網址. 假如想要在上方 "Yahoo!電影" 右方的搜尋欄填入譬如 "靈魂急轉彎" 按下搜尋之後爬取下方的搜尋結果. 能否請你給個範例關於這個動作如何完成?