2019年11月10日

Google Apps Script 使用 XmlService 解析 XML 要注意的地方

Google Apps Script 使用 XmlService 解析 XML 要注意的地方

Wayne Fu 0 A+
google-apps-script-xmlservice-problem.jpg-Google Apps Script 使用 XmlService 解析 XML 要注意的地方之前曾記錄使用 Google Apps Script(簡稱 GAS) 爬網頁資料,「解析 HTML 及操作 DOM 的技巧」,主要利用 GAS 的 XmlService 這個官方函數。

而最近爬 XML 頁面時,發現之前記錄的心得不敷使用,沒想到 XML 架構有點難以理解。因此花了點時間解決問題,也另外記錄一下心得。

(圖片出處: pxhere.com)


一、GAS 標準範例


首先看一下官方提供的標準範例,來自官網「XML Service」:

function parseXml() {
var url = 'https://gsuite-developers.googleblog.com/atom.xml';
var xml = UrlFetchApp.fetch(url).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement();
var atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');

var entries = root.getChildren('entry', atom);
for (var i = 0; i < entries.length; i++) {
var title = entries[i].getChild('title', atom).getText();
var categoryElements = entries[i].getChildren('category', atom);
var labels = [];
for (var j = 0; j < categoryElements.length; j++) {
labels.push(categoryElements[j].getAttribute('term').getValue());
}
Logger.log('%s (%s)', title, labels.join(', '));
}
}


以上需要注意的是紅字那兩行,getNamespace 是取得「命名空間」(namespace)之意,概念說明可參考 Wiki「XML命名空間」。

不是每個 HTML 頁面都有設定命名空間,同樣也不是每個 XML 頁面都有命名空間。之前解析 HTML 網頁時,剛好沒處理命名空間同樣可以正常執行,但這次解析 XML 頁面就踢到鐵板,所以如果 XML 頁面無法正常解析時,就必須注意紅字內容,檢查該頁面是否設定了命名空間:

  • 先用 getNamespace 取得該 XML 頁面的命名空間
  • 接著取得頁面任何元素,例如使用 getChildren 時,都需要加入命名空間的參數
  • 否則可能什麼東西都取不出來



二、YouTube 播放清單 feed 頁面


直接以實際範例說明比較容易理解,例如下面是 YouTube 提供的影片播放清單 RSS Feed,公視「有話好說」XML 頁面:

https://www.youtube.com/feeds/videos.xml?playlist_id=UUgxXuXHJ4VwovSTvDiWlzZQ

google-apps-script-xmlservice-problem-1.jpg-Google Apps Script 使用 XmlService 解析 XML 要注意的地方

從這個頁面可以爬到的資料相當多,例如影片 id、標題、作者資訊等等:

  • A:紅色底線這裡,就是這個 XML 頁面的 namespace 命名空間
  • B:此處的紅色底線是另一個困難的概念,這裡是 yt 這個命名空間
  • C:如果要從此處的 videoId 元素取得影片 id 字串,請注意到有個前綴字串 yt,這就是該元素命名空間

以上就是使用 XmlService 會卡關的地方,以下來看範例程式碼。



三、爬取 XML 頁面範例程式碼


同樣以公視「有話好說」的 RSS Feed 當範例,嘗試以 GAS 來爬取 XML 頁面內容,取得每個影片的 id、標題:

(function() {
// 取得清單 feed 內容, 解析 xml 格式
var xmlUrl = "https://www.youtube.com/feeds/videos.xml?playlist_id=UUgxXuXHJ4VwovSTvDiWlzZQ",
xml = UrlFetchApp.fetch(xmlUrl).getContentText(),
doc = XmlService.parse(xml),
root = doc.getRootElement(),
atom = XmlService.getNamespace('http://www.w3.org/2005/Atom'), // 這個 feed 一定要有 namespace 才能讀取
yt = XmlService.getNamespace('http://www.youtube.com/xml/schemas/2015'), // 有 prefix 前綴 yt 一定要有 namespace 才能讀取
entries = root.getChildren("entry", atom), // 一定要加上 atom namespace 才能取得
i, videoId, programTitle;

// loop 所有影片
for (i in entries) {
// 取得影片 id, 影片標題
videoId = entries[i].getChildText("videoId", yt); // 一定要加上 yt namespace 才能取得
programTitle = entries[i].getChildText("title", atom); // 一定要加上 atom namespace 才能取得

Logger.log("影片 id = "+videoId);
Logger.log("影片標題 = "+programTitle);
}
})();

所有注意事項請直接看註解字串,並參照前面「二、YouTube 播放清單 feed 頁面」的說明即可理解。

參照此範例後,要取得此頁面其他欄位的資料,按相同邏輯加入參數即可抓到。


更多 相關文章:
0 0
如這篇文章對你有幫助,歡迎「分享」到 FB、「追蹤」粉絲團、「訂閱」最新文章

沒有留言:

張貼留言注意事項:

◎ 勾選「通知我」可收到後續回覆的mail!
◎ 請在相關文章留言,與文章無關的主題可至「Blogger 社團」提問。
◎ 提問若無法提供足夠的資訊供判斷,可能會被無視。建議先參考這篇「Blogger 提問技巧及注意事項」。
◎ CSS 相關問題非免費諮詢,建議使用「Chrome 開發人員工具」尋找答案。
◎ 手機版相關問題請參考「Blogger 行動版範本的特質」→「三、行動版範本不一定能執行網頁版工具」。
◎ 非官方範本問題、或貴站為商業網站,請參考「Blogger 免費諮詢 + 付費諮詢
◎ 若是使用官方 RWD 範本,請參考「Blogger 推出全新自適應 RWD 官方範本及佈景主題」→ 不建議對範本進行修改!
◎ 若留言要輸入語法,"<"、">"這兩個符號請用其他符號代替,否則語法會消失!
◎ 為了過濾垃圾留言,所有留言不會即時發佈,請稍待片刻。
◎ 本站「已關閉自刪留言功能」。

TOP