摘要:本文首發于個人博客項目源碼,歡迎,說不定哪天脫單了就能用到了寫在前面自從用郵箱注冊了很多賬號后,便會收到諸如以下類似的郵件剛開始還以為是一張圖片,后來仔細一看不是圖片呀,好像還是呀,于是好奇寶寶我一下,查閱多篇資料后總結出怎么用前端知識和做
本文首發于個人博客:Vince"Blog
項目源碼:NodeMail,歡迎star,說不定哪天脫單了就能用到了
寫在前面自從用郵箱注冊了很多賬號后,便會收到諸如以下類似的郵件,剛開始還以為是一張圖片,后來仔細一看不是圖片呀,好像還是HTML呀,于是好奇寶寶我Google一下,查閱多篇資料后總結出怎么用前端知識和Node做一個這樣的“郵件網頁”。
確認主題知道怎么實現功能后,思考著我該寫什么主題呢,用一個HTML模板隨便給小伙伴們發個郵件炫個技?不行,作為一個很cool的程序員怎么能這么low呢,最近天氣變化幅度大,溫度捉摸不定,女朋友總是抱怨穿少了又冷穿多了又熱,嗨呀,要不我就寫個每天定時給寶寶發送天氣預報的郵件,另外想起寶寶喜歡看ONE·一個這個APP上的每日更新,要不發天氣預報的同時,再附贈一個“ONE的每日訂閱”?機智又浪漫,開始搬磚~
劇透本來是想最后放效果圖的,怕你們看到一半就沒興趣了,就在前面劇透一下我最后做出來的效果圖吧~
待解決的問題1. 如何獲取天氣預報和ONE上的data?
答:獲取data有兩種方法,第一種方法是獲取天氣預報和ONE的API,第二種是用node爬蟲獲取天氣預報和ONE網頁的信息。后來找了下,發現ONE并沒有API接口,為了讓兩者統一,于是決定使用node上的一個插件叫cheerio,配合superagent能夠很方便地爬取網頁上的信息。
2. 如何做出HTML的這種郵件?
答:之前學過一段時間的express這個框架,接觸到模版引擎這個概念,傳入data便可獲得html文件,再結合node的fs模塊,獲取到這個html文件,便可以結合node的郵件插件發送HTML郵件啦!
3. 如何用node發送郵件?
感謝無私的開源開發者,開發了一款發送郵件的Node插件nodemailer,兼容主流的Email廠商,只需要配置好郵箱賬號和smtp授權碼,便可以用你的郵箱賬號在node腳本上發文件,很cool有沒有~
4. 如何做到每日定時發送?
其實可以通過各種hack的方式寫這么一個定時任務,但是既然node社區有這個定時的輪子,那我們直接用就好了,node-schedule是一個有著各種配置的定時任務發生器,可以定時每個月、每個禮拜、每天具體什么時候執行什么任務,這正符合每天早晨定時給寶寶發送郵件的需求。
一切準備就緒,開始做一次浪漫的程序員
編寫代碼 網頁爬蟲這里我們使用到superagent和cheerio組合來實現爬蟲:
分析網頁DOM結構,如下圖所示:
用superagent來獲取指定網頁的所有DOM:
superagent.get(URL).end(function(err,res){ // }
用cheerio來篩選superagent獲取到的DOM,取出需要的DOM
imgUrl:$(todayOne).find(".fp-one-imagen").attr("src"), type:$(todayOne).find(".fp-one-imagen-footer").text().replace(/(^s*)|(s*$)/g, ""), text:$(todayOne).find(".fp-one-cita").text().replace(/(^s*)|(s*$)/g, "")
以下就是爬取ONE的代碼,天氣預報網頁也是一個道理:
const superagent = require("superagent"); //發送網絡請求獲取DOM const cheerio = require("cheerio"); //能夠像Jquery一樣方便獲取DOM節點 const OneUrl = "http://wufazhuce.com/"; //ONE的web版網站 superagent.get(OneUrl).end(function(err,res){ if(err){ console.log(err); } let $ = cheerio.load(res.text); let selectItem=$("#carousel-one .carousel-inner .item"); let todayOne=selectItem[0]; //獲取輪播圖第一個頁面,也就是當天更新的內容 let todayOneData={ //保存到一個json中 imgUrl:$(todayOne).find(".fp-one-imagen").attr("src"), type:$(todayOne).find(".fp-one-imagen-footer").text().replace(/(^s*)|(s*$)/g, ""), text:$(todayOne).find(".fp-one-cita").text().replace(/(^s*)|(s*$)/g, "") }; console.log(todayOneData); })EJS模版引擎生成HTML
通過爬蟲獲取到了數據,那么我們就能夠通過將date輸入到EJS渲染出HTML,我們在目錄下創建js腳本和ejs模版文件:
app.js
const ejs = require("ejs"); //ejs模版引擎 const fs = require("fs"); //文件讀寫 const path = require("path"); //路徑配置 //傳給EJS的數據 let data={ title:"nice to meet you~" } //將目錄下的mail.ejs獲取到,得到一個模版 const template = ejs.compile(fs.readFileSync(path.resolve(__dirname, "mail.ejs"), "utf8")); //將數據傳入模版中,生成HTML const html = template(data); console.log(html)
mail.ejs
用Node發送郵件Document <%= title %>
這里我們可以發送純text也可以發送html,注意的是郵箱密碼不是你登錄郵箱的密碼,而是smtp授權碼,什么是smtp授權碼呢?就是你的郵箱賬號可以使用這個smtp授權碼在別的地方發郵件,一般smtp授權碼在郵箱官網的設置中可以看的到,設置如下注釋。
const nodemailer = require("nodemailer"); //發送郵件的node插件 let transporter = nodemailer.createTransport({ service: "126", // 發送者的郵箱廠商,支持列表:https://nodemailer.com/smtp/well-known/ port: 465, // SMTP 端口 secureConnection: true, // SSL安全鏈接 auth: { //發送者的賬戶密碼 user: "賬戶@126.com", //賬戶 pass: "smtp授權碼", //smtp授權碼,到郵箱設置下獲取 } }); let mailOptions = { from: ""發送者昵稱" <地址@126.com>", // 發送者昵稱和地址 to: "like@vince.studio", // 接收者的郵箱地址 subject: "一封暖暖的小郵件", // 郵件主題 text: "test mail", //郵件的text // html: html //也可以用html發送 }; //發送郵件 transporter.sendMail(mailOptions, (error, info) => { if (error) { return console.log(error); } console.log("郵件發送成功 ID:", info.messageId); });Node定時執行任務
這里我們用到了node-schedule來定時執行任務,示例如下:
var schedule = require("node-schedule"); //1. 確定的時間執行 var date = new Date(2017,12,10,15,50,0); schedule.scheduleJob(date, function(){ console.log("執行任務"); }); //2. 秒為單位執行 //比如:每5秒執行一次 var rule1 = new schedule.RecurrenceRule(); var times1 = [1,6,11,16,21,26,31,36,41,46,51,56]; rule1.second = times1; schedule.scheduleJob(rule1, function(){ console.log("執行任務"); }); //3.以分為單位執行 //比如:每5分種執行一次 var rule2 = new schedule.RecurrenceRule(); var times2 = [1,6,11,16,21,26,31,36,41,46,51,56]; rule2.minute = times2; schedule.scheduleJob(rule2, function(){ console.log("執行任務"); }); //4.以天單位執行 //比如:每天6點30分執行 var rule = new schedule.RecurrenceRule(); rule.dayOfWeek = [0, new schedule.Range(1, 6)]; rule.hour = 6; rule.minute =30; var j = schedule.scheduleJob(rule, function(){ console.log("執行任務"); getData(); });思路與步驟
當所有的問題都解決后,便是開始結合代碼成一段完整的程序,思路很簡單,我們來逐步分析:
由于獲取數據是異步的,并且不能判斷出哪個先獲取到數據,這個是可以將獲取數據的函數封裝成一個Promise對象,最后在一起用Promise.all來判斷所有數據獲取完畢,再發送郵件
// 其中一個數據獲取函數,其他的也是類似 function getOneData(){ let p = new Promise(function(resolve,reject){ superagent.get(OneUrl).end(function(err, res) { if (err) { reject(err); } let $ = cheerio.load(res.text); let selectItem = $("#carousel-one .carousel-inner .item"); let todayOne = selectItem[0]; let todayOneData = { imgUrl: $(todayOne) .find(".fp-one-imagen") .attr("src"), type: $(todayOne) .find(".fp-one-imagen-footer") .text() .replace(/(^s*)|(s*$)/g, ""), text: $(todayOne) .find(".fp-one-cita") .text() .replace(/(^s*)|(s*$)/g, "") }; resolve(todayOneData) }); }) return p }
將爬取數據統一處理,作為EJS的參數,發送郵件模板。
function getAllDataAndSendMail(){ let HtmlData = {}; // how long with let today = new Date(); let initDay = new Date(startDay); let lastDay = Math.floor((today - initDay) / 1000 / 60 / 60 / 24); let todaystr = today.getFullYear() + " / " + (today.getMonth() + 1) + " / " + today.getDate(); HtmlData["lastDay"] = lastDay; HtmlData["todaystr"] = todaystr; Promise.all([getOneData(),getWeatherTips(),getWeatherData()]).then( function(data){ HtmlData["todayOneData"] = data[0]; HtmlData["weatherTip"] = data[1]; HtmlData["threeDaysData"] = data[2]; sendMail(HtmlData) } ).catch(function(err){ getAllDataAndSendMail() //再次獲取 console.log("獲取數據失敗: ",err); }) }
發送郵件具體代碼
function sendMail(HtmlData) { const template = ejs.compile( fs.readFileSync(path.resolve(__dirname, "email.ejs"), "utf8") ); const html = template(HtmlData); let transporter = nodemailer.createTransport({ service: EmianService, port: 465, secureConnection: true, auth: EamilAuth }); let mailOptions = { from: EmailFrom, to: EmailTo, subject: EmailSubject, html: html }; transporter.sendMail(mailOptions, (error, info={}) => { if (error) { console.log(error); sendMail(HtmlData); //再次發送 } console.log("Message sent: %s", info.messageId); }); }安裝與使用
如果你覺得這封郵件的內容適合你發送的對象,可以按照以下步驟,改少量參數即可運行程序;
git clone https://github.com/Vincedream...
打開main.js,修改配置項
//紀念日 let startDay = "2016/6/24"; //當地拼音,需要在下面的墨跡天氣url確認 const local = "xiangtan"; //發送者郵箱廠家 let EmianService = "163"; //發送者郵箱賬戶SMTP授權碼 let EamilAuth = { user: "xxxxxx@163.com", pass: "xxxxxx" }; //發送者昵稱與郵箱地址 let EmailFrom = ""name""; //接收者郵箱地 let EmailTo = "like@vince.studio"; //郵件主題 let EmailSubject = "一封暖暖的小郵件"; //每日發送時間 let EmailHour = 6; let EmialMinminute= 30;
終端輸入npm install安裝依賴,再輸入node main.js,運行腳本,當然你的電腦不可能不休眠,建議你部署到你的云服務器上運行。
最后冬天到了,是不是也該用程序員的專業知識給身邊的人帶來一些溫暖呢,源代碼與demo已經放到github上,要不試一試?
GitHub:https://github.com/Vincedream/NodeMail
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102170.html
摘要:但是,畢竟是人,哪天忙了就會忘記提交,所以想著能不能實現在自己阿里云服務器系統上,設置,定制下命令,實現每天定點自動提交。 前言 進入自己github主頁會看到自己的提交記錄,如果某天沒有提交記錄,那天的小方框就顯示灰色。強迫癥的我,每次進來看著就感覺不爽,想著自己每天記得提交點東西,爭取像阮一峰大神一樣,每天都有提交記錄。 showImg(https://www.wty90.co...
摘要:使用腳本發送郵件并不復雜。以下為思路導圖模塊與發送郵件相關的模塊是關于簡單郵件傳輸協議的操作模塊,在發送郵件的過程中起到服務器之間互相通信的作用。 0. 前言 發送電子郵件是個很常見的開發需求。比如你寫了個監控天氣的腳本,發現第二天要下雨,或者網站上關注的某個商品降價了,就可以發個郵件到郵箱來提醒自己。 使用 Python 腳本發送郵件并不復雜。不過由于各家郵件的發送機制和安全策略不同...
摘要:也就是說,我的篇文章的請求對應個實例,這些實例都請求完畢后,執行以下邏輯他的目的在于對每一個返回值這個返回值為單篇文章的內容,進行方法處理。 英國人Robert Pitt曾在Github上公布了他的爬蟲腳本,導致任何人都可以容易地取得Google Plus的大量公開用戶的ID信息。至今大概有2億2千5百萬用戶ID遭曝光。 亮點在于,這是個nodejs腳本,非常短,包括注釋只有71行。 ...
摘要:源碼地址準備一臺云服務器寫好的腳本效果因為現在一個的客戶端啟動越來越慢,而且很多自己不感興趣的東西我只是想看看文章,所以就寫了這個小爬蟲。因為一個是每天點會更新,所以自己的服務器要做一個定時服務,下自帶了定時任務。 源碼地址:https://github.com/xcc3641/pySendOneToEmail 準備 一臺云服務器 寫好的Python腳本 效果 因為現在一個的And...
閱讀 2184·2020-06-12 14:26
閱讀 2487·2019-08-29 16:41
閱讀 1890·2019-08-29 15:28
閱讀 2455·2019-08-26 13:43
閱讀 757·2019-08-26 13:37
閱讀 2777·2019-08-23 18:13
閱讀 2800·2019-08-23 15:31
閱讀 1018·2019-08-23 14:10