1

先看效果

其中的内容包含了当前时间、与女友的纪念日、当天天气、每日一句话和生活小常识(爱从小事做起)

​    

所用到的包

   "cheerio": "^1.0.0-rc.3",        //爬取网站内容

    "node-schedule": "^1.3.2",      //定时器

    "nodemailer": "^6.3.1",      //发送邮箱

    "nodemailer-smtp-transport": "^2.7.4",

    "superagent": "^5.1.0"

目录结构

整体思路

主要分为三步:

1.爬取数据和通过API获取数据

2.处理数据,整合成要发送的模板

3.设置发送时间,发送邮件

一、获取数据

本案例中的数据来源有两个,其中的“每日一句”是通过爬取ONE的web版往网站获取的(网址:http://wufazhuce.com/

天气信息和健康小知识是通过天行API获取的(网址:https://www.tianapi.com/signup.html?source=474284281),使用前需要去申请apikey。

config/confi.js中为配置信息

module.exports = {
    MEMORIAL_DAY: '2016-09-17',  //与女朋友的纪念日
    TXAPIKEY: '', //此处须填写个人申请的天行apikey,请替换成自己的 
    
    //邮箱配置(qq邮箱)
    emailUser: "@qq.com", // 账号   你自定义的域名邮箱账号
    emailPass: "",    // 密码   你自己开启SMPT获取的密码
    toEmailList: ['2657179843@qq.com'],    // 收件列表,可同时发送给多个人
    emailSubject: '来自馒头耙耙的每日关心',   //邮件标题
}

这里需要说明一下,上面的emailPass不是指的你的邮箱登陆密码,而是你的邮箱开启SMTP服务的密码,这里以QQ邮箱为例。

登陆QQ邮箱,点击设置->账户

往下翻,找到SMTP服务,点击开启后会弹出你的服务密码

config/superagent.js爬取页面信息

const superagent = require('superagent')

//请求
function req(url,method, params, data, cookies) {
  return new Promise(function (resolve,reject) {
    superagent(method, url)
        .query(params)
        .send(data)
        .set('Content-Type','application/x-www-form-urlencoded')
        .end(function (err, response) {
          if (err) {
            reject(err)
          }
          resolve(response)
        })
  })
}

module.exports = {
  req
}

utils/cheerio.js中为获取数据,内容如下:

const cheerio = require('cheerio');
const superagent = require('../config/superagent');
const ONE = 'http://wufazhuce.com/'; // ONE的web版网站
const TXHOST = 'http://api.tianapi.com/txapi/'; // 天行host
const config = require('../config/config')

async function getOne() {
    // 获取每日一句
    try {
        let res = await superagent.req(ONE, 'GET');
        let $ = cheerio.load(res.text);
        let todayOneList = $('#carousel-one .carousel-inner .item');
        let todayOne = $(todayOneList[0])
            .find('.fp-one-cita')
            .text()
            .replace(/(^\s*)|(\s*$)/g, '');
        return todayOne;
    } catch (err) {
        console.log('错误', err);
        return err;
    }
}

async function getTXweather() {
    // 获取天行天气
    let url = TXHOST + 'tianqi/';
    try {
        let res = await superagent.req(url, 'GET', {
            key: config.TXAPIKEY,
            city: '重庆'
        }); 
        let content = JSON.parse(res.text);
        if (content.code === 200) {
            let todayInfo = content.newslist[0];
            return todayInfo;
        } else {
            console.log('获取接口失败', content.code);
        }
    } catch (err) {
        console.log('获取接口失败', err);
    }
}
async function getTXhealthtip() {
    // 获取健康小提示
    let url = TXHOST + 'healthtip/';
    try {
        let res = await superagent.req(url, 'GET', {
            key: config.TXAPIKEY,
        }); 
        let content = JSON.parse(res.text);
        if (content.code === 200) {
            let healthtip = content.newslist[0].content;
            return healthtip;
        } else {
            console.log('获取接口失败', content.code);
        }
    } catch (err) {
        console.log('获取接口失败', err);
    }
}

module.exports = {
    getOne,
    getTXweather,
    getTXhealthtip
}

二、处理数据

处理时间:utils/dateTime.js(获取当天时间、计算当天与女友纪念日的差值、格式化时间)

function getDay(date) {
  var date2 = new Date();
  var date1 = new Date(date);
  var iDays = parseInt(
    Math.abs(date2.getTime() - date1.getTime()) / 1000 / 60 / 60 / 24
  );
  return iDays;
}

function getToday(){
  let today = new Date()
  var year = today.getFullYear();
  var month = today.getMonth() + 1;
  var day = today.getDate();
  return `今天是${year}年${month}月${day}日`
}

function formatDate(date) {
  var tempDate = new Date(date);
  var year = tempDate.getFullYear();
  var month = tempDate.getMonth() + 1;
  var day = tempDate.getDate();
  var hour = tempDate.getHours();
  var min = tempDate.getMinutes();
  var second = tempDate.getSeconds();
  var week = tempDate.getDay();
  var str = '';
  if (week === 0) {
    str = '星期日';
  } else if (week === 1) {
    str = '星期一';
  } else if (week === 2) {
    str = '星期二';
  } else if (week === 3) {
    str = '星期三';
  } else if (week === 4) {
    str = '星期四';
  } else if (week === 5) {
    str = '星期五';
  } else if (week === 6) {
    str = '星期六';
  }
  if (hour < 10) {
    hour = '0' + hour;
  }
  if (min < 10) {
    min = '0' + min;
  }
  if (second < 10) {
    second = '0' + second;
  }
  return year + '-' + month + '-' + day + '日 ' + hour + ':' + min + ' ' + str;
}

module.exports = {
  getDay,
  formatDate,
  getToday
};

处理发送邮件信息:utils/email.js

// 引入email 模块
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
const config = require('../config/config')

// 开启一个 SMTP 连接池
var transport = nodemailer.createTransport(smtpTransport({
    host: "smtp.qq.com", // qq邮箱主机
    secure: true, // 使用 SSL
    secureConnection: true, // 使用 SSL
    port: 465, // SMTP 端口
    auth: {
        user: config.emailUser, // 账号   你自定义的域名邮箱账号
        pass: config.emailPass    // 密码   你自己开启SMPT获取的密码
    }
}));

function sendEmail(htmlcon) {
    // 设置邮件内容  可以拼接html 美化发送内容
    var mailOptions = {
        from: config.emailUser, // 发件地址
        to: config.toEmailList, // 收件列表
        subject: config.emailSubject, // 标题
        text: "text",
        html: htmlcon // html 内容
    }
    transport.sendMail(mailOptions, function (error, response) {
        if (error) {
            console.log("fail: " + error);
            console.log("发送失败");
        } else {
            console.log("发送成功");
        }
        transport.close(); // 如果没用,关闭连接池
    });
}

module.exports = {sendEmail}

三、设置发送时间及发送邮件

设置发送时间:utils/schedule.js

const schedule = require('node-schedule')
// date 参数

//其他规则见 https://www.npmjs.com/package/node-schedule
// 规则参数讲解    *代表通配符
//
// *  *  *  *  *  *
// ┬ ┬ ┬ ┬ ┬ ┬
// │ │ │ │ │  |
// │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
// │ │ │ │ └───── month (1 - 12)
// │ │ │ └────────── day of month (1 - 31)
// │ │ └─────────────── hour (0 - 23)
// │ └──────────────────── minute (0 - 59)
// └───────────────────────── second (0 - 59, OPTIONAL)

// 每分钟的第30秒触发: '30 * * * * *'
//
// 每小时的1分30秒触发 :'30 1 * * * *'
//
// 每天的凌晨1点1分30秒触发 :'30 1 1 * * *'
//
// 每月的1日1点1分30秒触发 :'30 1 1 1 * *'
//
// 每周1的1点1分30秒触发 :'30 1 1 * * 1'

function setSchedule(date,callback) {
  schedule.scheduleJob(date, callback)
}
module.exports = {
  setSchedule
}

index.js入口文件

const Email = require('./utils/email')
const Schedule = require('./utils/schedule')
const DateTime = require('./utils/dateTime')
const Cheerio = require('./utils/cheerio')
const config = require('./config/config')


async function run(){
    let oneText = await Cheerio.getOne()
    let weather = await Cheerio.getTXweather()
    let healthtip = await Cheerio.getTXhealthtip()
    let today = DateTime.getToday()
    Email.sendEmail(`<div  >
    <div >
        <p >${today}&nbsp;&nbsp;&nbsp;&nbsp;${weather.week}</p>
        <p >和馒头耙耙相恋的第<span > ${DateTime.getDay(config.MEMORIAL_DAY)} </span>天</p>
    </div>
    <div >
        <div>
            <span >${weather.lowest}~${weather.highest}</span>&nbsp;
            <img  referrerpolicy="no-referrer" src="https://www.dzyong.com/emailBot/images/${weather.weatherimg}" alt="">
            <span>${weather.weather}</span>&nbsp;&nbsp;<span>${weather.wind}${weather.windspeed}</span>
        </div>
        <p>
            ${weather.tips}
        </p>
    </div>
    <P >
       ${oneText}
    </P>
    <div >
        <span >生活小常识:</span>
        <span >
            ${healthtip}
        </span>
    </div>
    </div>
</div>`)
}

Schedule.setSchedule("0 17 * * * *",function(){
    run()
})

最后执行 node index.js,女朋友就会在指定的时间收到来自你的每日关系啦,当然如果想要每天发送需要部署到云服务器上,这样你就不用管它了,到点自动发送

后期我会对该项目新增更多功能(可在网站随时修改发送人、收件人、发送时间等信息,可自定义发送内容等功能),感兴趣的小伙伴可以点个关注。

源码:https://github.com/DengZhanyong/emailBot    (觉得还不错的话就给我个star,你们的支持是我进步的动力)

本人个人博客网站:www.dzyong.com


邓占勇
109 声望6 粉丝

个人网站:www.dengzhanyong.com