GAS + Cheerio 分析網頁資訊寫入Google 試算表
一.簡介
現在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/
你好, 剛接觸GAS, 可惜沒有 JavaScript 的基礎. 你給的例子蠻清楚, 但在下對於如何輸入之後再抓取結果沒有頭緒, 以本例來說你是直接抓取 "上映中" 的頁面, 並且也有直接的網址. 假如想要在上方 "Yahoo!電影" 右方的搜尋欄填入譬如 "靈魂急轉彎" 按下搜尋之後爬取下方的搜尋結果. 能否請你給個範例關於這個動作如何完成?