Kadence

日幣匯率 ( Node-js 爬蟲 )

前一篇透過 Node-RED 即時地抓取日幣匯率,這邊要繼續介紹 Node.js 的做法,輕鬆實現「抓取日幣匯率,並且在指定匯率到達的時候用 Webduino 點亮燈泡提示,並且也會寄送 email 通知」。

安裝 Node.js

前往 https://nodejs.org/en/download/ 下載安裝,建議直接安裝 4.2 以上版本。

安裝 Node.js

安裝 Node.js 套件

因為要透過 Node.js 來完成抓匯率、寄 Email 和點燈,以下幾個 Node.js 套件是一定要安裝的,如果你的 Node.js 是 0.X 版本,建議透過 nvm 直接把 Node.js 升到 4.2 以上比較不會有問題。

  • request:抓取整個網頁的程式碼。
  • cheerio:後端的 jQuery
  • nodemailer:寄 Email
  • webduino-js:Webduino 主程式
  • webduino-blockly:可直接把 Webduino Blockly 產生程式碼貼進來

透過 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);

console.log 更換程式碼

不過不用擔心,我們回到剛剛網頁的原始碼,透過瀏覽器的「搜尋」功能,我們就可以知道日幣的位置排在第 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

寄送 Email 並且透過 Webduino 點亮燈泡

只有抓到匯率數值還不夠,重要的可以即時的通知我們,首先看到 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://[email protected]:[email protected]'); 這一段,記得把 userID 換成要寄件的信箱的帳號,password 也換成要寄件的信箱的密碼。

參考:nodemailer 套件

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://[email protected]:[email protected]');
//如果匯率小於我們設定的就寄信
if (result < 0.28) {
  var mailOptions = {
    from: '"xxxx" <[email protected]>', //寄件者
    to: '[email protected]', //收件者
    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 帳戶的設定,進入「登入和安全性」,勾選「允許安全性較低的應用程式」 設定處於啟用狀態,這一步驟一定要做,不然屆時就會回報錯誤。

e-mail 允許安全性較低的應用程式

都設定好了以後,執行程式,如果到達我們設定的匯率,就會點亮燈泡,同時寄信通知囉!

達到設定的匯率,點亮燈泡,同時寄信通知

當然,如果你想要每隔一段時間擷取一次,可以在最後加個 setInterval 就可以了,以下面的例子,就是每兩分鐘擷取一次。( 不過如果是有寄信的話,可以再多寫個判斷只寄一次就好,不然可能每兩分鐘就寄一次信囉 XD )

jp();
setInterval(jp,120000);

達到設定的匯率,點亮燈泡,同時寄信通知

小結

其實不論是用 Node-RED 或是純粹的 Node.js,都可以很輕鬆地抓取一些靜態網頁的資訊 ( 當然如果是一些有查詢或是需要登入的,就比較麻煩了 ),透過 Webduino 或其它套件的輔助,我們就可以做到即時通知的效果,例如辦公室的某盞燈突然亮了,大家就趕快去買日幣,或是突然收到一封要買日幣的信,就該去買日幣…等之類的。

總之,當我們可以活動這些應用與技巧,相信就能完成過去事情,並節省許多寶貴的時間與金錢囉!

參考:https://www.npmjs.com/package/nodemailer

分享