前陣子接到的需求,要使用爬蟲程式撈特定網站資料回來,那麼利用 Google 試算表是不錯的選擇,除了每個儲存格的容量最多有 50000 個字元,還可用 Google Apps Script(以下簡稱 GAS) 執行爬蟲程式、處理各種細節。
不過撈完網頁內仍後,如何解析 HTML 架構、操作頁面上的 HTML 元素都有不少難題要解決,因此本篇記錄一下 GAS 的操作心得與技巧。
(圖片出處: pixabay.com)
1. 爬網頁原始碼
由於操作平台是 GAS,需要先瞭解爬網頁資料的語法:
以上語法可很簡單取得 WFU BLOG 的網頁 HTML 內容字串。
2. 操作 XmlService
GAS 用來解析 HTML 語法的官方文件如下:
官方也附了簡單的範例,使用 XmlService.parse() 就能解析網頁原始碼。
但先說結論,這是沒有用的,因為 XmlService 只能解析結構完整的 XML 文件,而 HTML 語法結構並沒有 XML 那麼嚴謹,所以不是每個網頁都能解析。
可參考這篇「XML文件的結構」,每個元素都要有開始及結束標記,例如:
但 HTML 文件以下標記方式(開始即結束)是允許的:
那麼一個正常的網頁內容,使用 XmlService.parse() 解析都會報錯,這就非常麻煩了。
硬要處理的話只能先用正規表示式,一一修改 link、input 等等各種不合 XML 規範的結束標記,才能使用 XmlService.parse()。
3. GAS 舊的 XML 工具
找到這篇比較好的解法「What is the best way to parse html in google apps script」,提到 GAS 舊版本的 XML 這個工具可以解析 HTML,參考語法如下:
先用 Xml 解析 HTML 後,再轉成 XML 字串,就能使用 XmlService 來解析內容了。
需要注意的是,XML 這個工具已被 Google 棄用(deprecated),隨時有可能失效。
如果是前端的話,用 jQuery 操作取得的 HTML 內容非常簡單方便,但可惜的是 GAS 無法使用 jQuery,而且官方提供的工具還非常難用,比前端的 HTML API 還爛,所以國外有網友自行做了幾個方便的函數,可參考「Parsing HTML」。
這個頁面主要模擬 HTML API,做出了三個最常用的 DOM 操作工具:
範例程式碼如下,複製到自己的 GAS 即可執行:
另外也提供一些 GAS 我常會用到的幾個 DOM 操作工具:
1. 刪除元素
2. 屬性值
取得圖片網址 IMG 的 src:
設定圖片網址 IMG 的 src:
3. 字串
取得整個元素的 HTML 字串:
取得元素的文字:
設定元素的文字:
不過撈完網頁內仍後,如何解析 HTML 架構、操作頁面上的 HTML 元素都有不少難題要解決,因此本篇記錄一下 GAS 的操作心得與技巧。
(圖片出處: pixabay.com)
一、解析 HTML
1. 爬網頁原始碼
由於操作平台是 GAS,需要先瞭解爬網頁資料的語法:
var response = UrlFetchApp.fetch("https://www.wfublog.com/"),
content = response.getContentText();
以上語法可很簡單取得 WFU BLOG 的網頁 HTML 內容字串。
2. 操作 XmlService
GAS 用來解析 HTML 語法的官方文件如下:
官方也附了簡單的範例,使用 XmlService.parse() 就能解析網頁原始碼。
但先說結論,這是沒有用的,因為 XmlService 只能解析結構完整的 XML 文件,而 HTML 語法結構並沒有 XML 那麼嚴謹,所以不是每個網頁都能解析。
可參考這篇「XML文件的結構」,每個元素都要有開始及結束標記,例如:
<link></link>
但 HTML 文件以下標記方式(開始即結束)是允許的:
<link /> <input />
那麼一個正常的網頁內容,使用 XmlService.parse() 解析都會報錯,這就非常麻煩了。
硬要處理的話只能先用正規表示式,一一修改 link、input 等等各種不合 XML 規範的結束標記,才能使用 XmlService.parse()。
3. GAS 舊的 XML 工具
找到這篇比較好的解法「What is the best way to parse html in google apps script」,提到 GAS 舊版本的 XML 這個工具可以解析 HTML,參考語法如下:
var page = UrlFetchApp.fetch(contestURL);
var doc = Xml.parse(page, true);
var bodyHtml = doc.html.body.toXmlString();
doc = XmlService.parse(bodyHtml);
var root = doc.getRootElement();
先用 Xml 解析 HTML 後,再轉成 XML 字串,就能使用 XmlService 來解析內容了。
需要注意的是,XML 這個工具已被 Google 棄用(deprecated),隨時有可能失效。
二、操作 DOM
如果是前端的話,用 jQuery 操作取得的 HTML 內容非常簡單方便,但可惜的是 GAS 無法使用 jQuery,而且官方提供的工具還非常難用,比前端的 HTML API 還爛,所以國外有網友自行做了幾個方便的函數,可參考「Parsing HTML」。
這個頁面主要模擬 HTML API,做出了三個最常用的 DOM 操作工具:
- getElementById
- getElementsByClassName
- getElementsByTagName
範例程式碼如下,複製到自己的 GAS 即可執行:
function getElementById(element, idToFind) {
var descendants = element.getDescendants();
for(i in descendants) {
var elt = descendants[i].asElement();
if( elt !=null) {
var id = elt.getAttribute('id');
if( id !=null && id.getValue()== idToFind) return elt;
}
}
}
function getElementsByClassName(element, classToFind) {
var data = [];
var descendants = element.getDescendants();
descendants.push(element);
for(i in descendants) {
var elt = descendants[i].asElement();
if(elt != null) {
var classes = elt.getAttribute('class');
if(classes != null) {
classes = classes.getValue();
if(classes == classToFind) data.push(elt);
else {
classes = classes.split('');
for(j in classes) {
if(classes[j] == classToFind) {
data.push(elt);
break;
}
}
}
}
}
}
return data;
}
function getElementsByTagName(element, tagName) {
var data = [];
var descendants = element.getDescendants();
for(i in descendants) {
var elt = descendants[i].asElement();
if( elt !=null && elt.getName()== tagName) data.push(elt);
}
return data;
}
三、常用功能
另外也提供一些 GAS 我常會用到的幾個 DOM 操作工具:
1. 刪除元素
function removeElement(element) {
element.getParentElement().removeContent(element);
}
2. 屬性值
取得圖片網址 IMG 的 src:
imgElement.getAttribute("src").getValue()
設定圖片網址 IMG 的 src:
imgElement.setAttribute("src", "圖片網址");
3. 字串
取得整個元素的 HTML 字串:
XmlService.getCompactFormat().format(element);
取得元素的文字:
element.getText();
設定元素的文字:
element.setText("字串內容");
更多 Google Apps Script 相關技巧: