前一篇我們透過 Node-RED 即時地抓取日幣匯率,這邊要繼續介紹 Node.js 的做法,輕鬆實現「抓取日幣匯率,並且在指定匯率到達的時候用 Webduino 點亮燈泡提示,並且也會寄送 email 通知」。
前往 https://nodejs.org/en/download/ 下載安裝,建議直接安裝 4.2 以上版本。
因為要透過 Node.js 來完成抓匯率、寄 Email 和點燈,以下幾個 Node.js 套件是一定要安裝的,如果你的 Node.js 是 0.X 版本,建議透過 nvm 直接把 Node.js 升到 4.2 以上比較不會有問題。
透過 npm 安裝完成之後,建立一個 index.js 的檔案,開頭先輸入下列的程式碼,就可以準備開始了。
require("webduino-js");
require("webduino-blockly");
var request = require("request");
var cheerio = require("cheerio");
var nodemailer = require('nodemailer');
首先我們輸入下面這一段,當我們執行 jp
這個流程的時候,會透過 request
抓取整個網頁內容,然後回傳到下一個流程的 body
裡頭,當我們回到指令列,輸入 node index
,就會看到整個網頁的原始碼呈現在畫面裡。
var jp = function() {
request({
url: "http://rate.bot.com.tw/Pages/Static/UIP003.zh-TW.htm",
method: "GET"
}, function(error, response, body) {
if (error || !body) {
return;
}else{
// 爬完網頁後要做的事情
console.log(body);
}
});
};
接著我們把剛剛的 console.log
換成成下面的程式碼,也就是透過 cheerio
來篩選資料,不過當你執行後,會發現 target
印出的是一個很嚇人的陣列,因為 .rate-content-sight.text-right.print_hide
的數量多達 38 個這麼多,而且從陣列中好像又看不出日幣到底排在哪裡 ( 因為都隱藏在 children 裡面了 )。
var $ = cheerio.load(body);
var target = $(".rate-content-sight.text-right.print_hide");
console.log(target);
不過不用擔心,我們回到剛剛網頁的原始碼,透過瀏覽器的「搜尋」功能,我們就可以知道日幣的位置排在第 16 位,也就是陣列的 15 ( 如果你有看上一篇透過 Node-RED 抓取日幣,也應該就知道順序是在 16 了 )。
這時候只要把程式稍做修改,就可以看到日幣匯率了。
var $ = cheerio.load(body);
var target = $(".rate-content-sight.text-right.print_hide");
console.log(target[15].children);
或是你也可以做更精準的寫法,就會只出現匯率數字而已,到這邊基本上我們已經完成了大部分的工作了。
target[15].children[0].data
只有抓到匯率數值還不夠,重要的可以即時的通知我們,首先看到 Webduino 的部分,把剛剛的程式改成這樣,指定一個變數 result
為日幣匯率,讓匯率小於我們設定的匯率就開燈,否則就關燈。
var $ = cheerio.load(body);
var target = $(".rate-content-sight.text-right.print_hide");
var result = target[15].children[0].data;
var led;
//輸入你的裝置 ID
boardReady({
device: deviceId,
multi: true
}, function(board) {
board.samplingInterval = 20;
led = getLed(board, 10); //設定 LED 腳位
if (result < 0.28) {
led.on();
} else {
led.off();
}
});
可以點亮燈泡之後,接下來就是要寄送 Email,這邊可以參考 nodemailer 套件 的寫法,一開始先獲取當下的時間,然後印出時間與日幣的關係,然後就是判斷當匯率小於多少的時候,會寄送 Email,程式裡比較特別的是 nodemailer.createTransport('smtps://userID@gmail.com:password@smtp.gmail.com');
這一段,記得把 userID
換成要寄件的信箱的帳號,password
也換成要寄件的信箱的密碼。
var date = new Date(); //獲取當前時刻與日期
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
if (h < 10) {
h = '0' + h;
}
if (m < 10) {
m = '0' + m;
}
if (s < 10) {
s = '0' + s;
}
var time = h + ':' + m + ':' + s; //獲取當前時間
console.log('現在時間:' + time + ',日幣匯率為' + result); //印出時間與匯率
//初始化寄信
var transporter = nodemailer.createTransport('smtps://userID@gmail.com:password@smtp.gmail.com');
//如果匯率小於我們設定的就寄信
if (result < 0.28) {
var mailOptions = {
from: '"xxxx" <xxxx@gmail.com>', //寄件者
to: 'xxxx@gmail.com', //收件者
subject: '該買日幣啦', //標題
text: '現在時間:' + time + ',日幣匯率為' + result, //純文字內容
html: '現在時間:' + time + ',日幣匯率為 <b>' + result + '</b>' //帶有 HTML 格式的內容
};
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
return console.log(error);
}else{
console.log('Message sent: ' + info.response); //寄信成功後印出訊息
}
});
}
注意,如果要用這種方式寄信,一定要記得在 Google 帳戶的設定,進入「登入和安全性」,勾選「允許安全性較低的應用程式」 設定處於啟用狀態,這一步驟一定要做,不然屆時就會回報錯誤。
都設定好了以後,執行程式,如果到達我們設定的匯率,就會點亮燈泡,同時寄信通知囉!
當然,如果你想要每隔一段時間擷取一次,可以在最後加個 setInterval
就可以了,以下面的例子,就是每兩分鐘擷取一次。( 不過如果是有寄信的話,可以再多寫個判斷只寄一次就好,不然可能每兩分鐘就寄一次信囉 XD )
jp();
setInterval(jp,120000);
其實不論是用 Node-RED 或是純粹的 Node.js,都可以很輕鬆地抓取一些靜態網頁的資訊 ( 當然如果是一些有查詢或是需要登入的,就比較麻煩了 ),透過 Webduino 或其它套件的輔助,我們就可以做到即時通知的效果,例如辦公室的某盞燈突然亮了,大家就趕快去買日幣,或是突然收到一封要買日幣的信,就該去買日幣...等之類的。
總之,當我們可以活動這些應用與技巧,相信就能完成過去事情,並節省許多寶貴的時間與金錢囉!
參考:https://www.npmjs.com/package/nodemailer