node爬虫案例-定时发送邮件
1. 说明
- 主要实现功能
- 利用node实现网页爬取数据
- 利用模板引擎制作html邮件
- 利用node发送电子邮件
- 利用node实现定时任务
- 项目依赖
所有依赖均在npm官网中可以找到
- superagent => 向服务器发起http请求
- cheerio => 解析html
- art-template => 模板引擎
- nodemailer => 发送邮件
- node-schedule => 定时任务
- 需要抓取的页面
http://tianqi.moji.com/
http://wufazhuce.com/
2. 环境安装
- 创建文件夹及初始化
mkdir nodemail
npm init -y
- 安装所有依赖包
yarn add superagent cheerio art-template nodemailer node-schedule
- 查看文件目录 =>
ls
或ls -al
- 打开文件 =>
start package.json
3. 处理日期格式
main.js
js
// 获取时间信息
let getDayDate = ()=> {
// 由于很多数据要提前准备好,才能渲染到页面,最终才能发送
// 这里就使用promise
return new Promise((resolve, reject)=> {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
let format = `${today.getFullYear()}/${today.getMonth()+1}/${today.getDate()}`
let dayData = {
count,
format
}
// console.log(dayData);
resolve(dayData);
}).catch(err=> {
reject(err);
});
}
getDayDate(); // 获取时间信息
// 获取时间信息
let getDayDate = ()=> {
// 由于很多数据要提前准备好,才能渲染到页面,最终才能发送
// 这里就使用promise
return new Promise((resolve, reject)=> {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
let format = `${today.getFullYear()}/${today.getMonth()+1}/${today.getDate()}`
let dayData = {
count,
format
}
// console.log(dayData);
resolve(dayData);
}).catch(err=> {
reject(err);
});
}
getDayDate(); // 获取时间信息
4. 请求墨迹天气获取数据
js
// 向服务器发起http请求
const superagent = require('superagent');
const cheerio = require('cheerio');
// 请求墨迹天气获取数据
let getMojiData = ()=> {
// 发起http请求
superagent.get('https://tianqi.moji.com/weather/china/zhejiang/xiaoshan-district').end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图标
let icon = $('.wea_weather span img').attr('src');
// console.log(icon);
// 获取天气
let weather = $('.wea_weather b').text();
// console.log(weather);
// 获取温度
let temperature = $('.wea_weather em').text();
// console.log(temperature);
// 获取提示
let tip = $('.wea_tips em').text();
// console.log(tip);
let mojiData = {
icon,
weather,
temperature,
tip
}
console.log(mojiData);
});
}
getMojiData(); // 请求墨迹天气获取数据
// 向服务器发起http请求
const superagent = require('superagent');
const cheerio = require('cheerio');
// 请求墨迹天气获取数据
let getMojiData = ()=> {
// 发起http请求
superagent.get('https://tianqi.moji.com/weather/china/zhejiang/xiaoshan-district').end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图标
let icon = $('.wea_weather span img').attr('src');
// console.log(icon);
// 获取天气
let weather = $('.wea_weather b').text();
// console.log(weather);
// 获取温度
let temperature = $('.wea_weather em').text();
// console.log(temperature);
// 获取提示
let tip = $('.wea_tips em').text();
// console.log(tip);
let mojiData = {
icon,
weather,
temperature,
tip
}
console.log(mojiData);
});
}
getMojiData(); // 请求墨迹天气获取数据
5. 请求one网站
该网站每天会出一张图和一句话
js
// 请求one抓取数据
let getOneData = ()=> {
superagent.get("http://wufazhuce.com/").end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图片
let onePic = $('.carousel-inner .item.active img').attr('src');
// let onePic = $('#carousel-one > div > div.item img').eq(0).attr('src');
console.log(onePic);
// 获取文本
let oneTxt = $('.carousel-inner .item.active .fp-one-cita a').text();
// let oneTxt = $('.carousel-inner .item .fp-one-cita a').eq(0).text();
console.log(oneTxt);
let oneData = {
onePic,
oneTxt
}
console.log(oneData);
});
}
getOneData();
// 请求one抓取数据
let getOneData = ()=> {
superagent.get("http://wufazhuce.com/").end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图片
let onePic = $('.carousel-inner .item.active img').attr('src');
// let onePic = $('#carousel-one > div > div.item img').eq(0).attr('src');
console.log(onePic);
// 获取文本
let oneTxt = $('.carousel-inner .item.active .fp-one-cita a').text();
// let oneTxt = $('.carousel-inner .item .fp-one-cita a').eq(0).text();
console.log(oneTxt);
let oneData = {
onePic,
oneTxt
}
console.log(oneData);
});
}
getOneData();
5. 等待数据请求完成
需要注意执行顺序,将所有方法全部改成promise的方式,并使用async和await控制
js
const superagent = require('superagent'); // 向服务器发起http请求
const cheerio = require('cheerio');
// 获取时间信息
let getDayDate = ()=> {
// 由于很多数据要提前准备好,才能渲染到页面,最终才能发送
// 这里就使用promise
return new Promise((resolve, reject)=> {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
let format = `${today.getFullYear()}/${today.getMonth()+1}/${today.getDate()}`
let dayData = {
count,
format
}
// console.log(dayData);
resolve(dayData); // 返回数据
});
}
// getDayDate(); // 获取时间信息
// 请求墨迹天气获取数据
let getMojiData = ()=> {
return new Promise((resolve, reject)=> {
// 发起http请求
superagent.get('https://tianqi.moji.com/weather/china/zhejiang/xiaoshan-district').end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图标
let icon = $('.wea_weather span img').attr('src');
// console.log(icon);
// 获取天气
let weather = $('.wea_weather b').text();
// console.log(weather);
// 获取温度
let temperature = $('.wea_weather em').text();
// console.log(temperature);
// 获取提示
let tip = $('.wea_tips em').text();
// console.log(tip);
let mojiData = {
icon,
weather,
temperature,
tip
}
// console.log(mojiData);
resolve(mojiData);
});
});
}
// getMojiData(); // 请求墨迹天气获取数据
// 请求one抓取数据
let getOneData = ()=> {
return new Promise((resolve, reject)=> {
superagent.get("http://wufazhuce.com/").end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图片
let oneImg = $('.carousel-inner .item.active img').attr('src');
// let onePic = $('#carousel-one > div > div.item img').eq(0).attr('src');
// console.log(oneImg);
// 获取文本
let oneTxt = $('.carousel-inner .item.active .fp-one-cita a').text();
// let oneTxt = $('.carousel-inner .item .fp-one-cita a').eq(0).text();
// console.log(oneTxt);
let oneData = {
oneImg,
oneTxt
}
// console.log(oneData);
resolve(oneData);
});
});
}
// getOneData();
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// 在方法里面涉及到数据请求(异步),会造成数据还没拿到,就开始渲染dom了
// 使用async和await
// 如果要用await调用得到函数,那么该函数必须返回的是promise对象
// 获取日期 - 等待请求完成之后才进行赋值
let dayDate = await getDayDate();
// 获取墨迹天气 - 等待请求完成之后才进行赋值
let mojiData = await getMojiData();
// 获取one数据 - 等待请求完成之后才进行赋值
let oneData = await getOneData();
// 所有数据获取成功之后,才进行模板引擎数据的替换
console.log(dayDate);
console.log(mojiData);
console.log(oneData);
}
renderTemplate();
const superagent = require('superagent'); // 向服务器发起http请求
const cheerio = require('cheerio');
// 获取时间信息
let getDayDate = ()=> {
// 由于很多数据要提前准备好,才能渲染到页面,最终才能发送
// 这里就使用promise
return new Promise((resolve, reject)=> {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
let format = `${today.getFullYear()}/${today.getMonth()+1}/${today.getDate()}`
let dayData = {
count,
format
}
// console.log(dayData);
resolve(dayData); // 返回数据
});
}
// getDayDate(); // 获取时间信息
// 请求墨迹天气获取数据
let getMojiData = ()=> {
return new Promise((resolve, reject)=> {
// 发起http请求
superagent.get('https://tianqi.moji.com/weather/china/zhejiang/xiaoshan-district').end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图标
let icon = $('.wea_weather span img').attr('src');
// console.log(icon);
// 获取天气
let weather = $('.wea_weather b').text();
// console.log(weather);
// 获取温度
let temperature = $('.wea_weather em').text();
// console.log(temperature);
// 获取提示
let tip = $('.wea_tips em').text();
// console.log(tip);
let mojiData = {
icon,
weather,
temperature,
tip
}
// console.log(mojiData);
resolve(mojiData);
});
});
}
// getMojiData(); // 请求墨迹天气获取数据
// 请求one抓取数据
let getOneData = ()=> {
return new Promise((resolve, reject)=> {
superagent.get("http://wufazhuce.com/").end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图片
let oneImg = $('.carousel-inner .item.active img').attr('src');
// let onePic = $('#carousel-one > div > div.item img').eq(0).attr('src');
// console.log(oneImg);
// 获取文本
let oneTxt = $('.carousel-inner .item.active .fp-one-cita a').text();
// let oneTxt = $('.carousel-inner .item .fp-one-cita a').eq(0).text();
// console.log(oneTxt);
let oneData = {
oneImg,
oneTxt
}
// console.log(oneData);
resolve(oneData);
});
});
}
// getOneData();
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// 在方法里面涉及到数据请求(异步),会造成数据还没拿到,就开始渲染dom了
// 使用async和await
// 如果要用await调用得到函数,那么该函数必须返回的是promise对象
// 获取日期 - 等待请求完成之后才进行赋值
let dayDate = await getDayDate();
// 获取墨迹天气 - 等待请求完成之后才进行赋值
let mojiData = await getMojiData();
// 获取one数据 - 等待请求完成之后才进行赋值
let oneData = await getOneData();
// 所有数据获取成功之后,才进行模板引擎数据的替换
console.log(dayDate);
console.log(mojiData);
console.log(oneData);
}
renderTemplate();
6. 通过模板引擎替换html
art-template
js
const template = require('art-template'); // 导入模板引擎
const path = require('path');
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// ......
// 代码见上
// 所有数据获取成功之后,才进行模板引擎数据的替换
/* console.log(dayDate);
console.log(mojiData);
console.log(oneData); */
// 使用模板方法
let html = template(path.join(__dirname, './res.html'), {
// 在这里定义的值,在模板文件可以直接使用双花括号的形式引用
// test: '测试'
dayDate,
mojiData,
oneData
})
console.log(html);
}
renderTemplate();
const template = require('art-template'); // 导入模板引擎
const path = require('path');
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// ......
// 代码见上
// 所有数据获取成功之后,才进行模板引擎数据的替换
/* console.log(dayDate);
console.log(mojiData);
console.log(oneData); */
// 使用模板方法
let html = template(path.join(__dirname, './res.html'), {
// 在这里定义的值,在模板文件可以直接使用双花括号的形式引用
// test: '测试'
dayDate,
mojiData,
oneData
})
console.log(html);
}
renderTemplate();
res.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>res</title>
</head>
<body>
<section id="date">
{{ dayDate.count }}天
{{ dayDate.format }}
</section>
<section id="weather">
<img src="{{mojiData.icon}}" alt="">
{{ mojiData.temperature }}
{{ mojiData.tip }}
</section>
<section id="tips">
<img src="{{oneData.oneImg}}" alt="">
{{ oneData.oneTxt }}
</section>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>res</title>
</head>
<body>
<section id="date">
{{ dayDate.count }}天
{{ dayDate.format }}
</section>
<section id="weather">
<img src="{{mojiData.icon}}" alt="">
{{ mojiData.temperature }}
{{ mojiData.tip }}
</section>
<section id="tips">
<img src="{{oneData.oneImg}}" alt="">
{{ oneData.oneTxt }}
</section>
</body>
</html>
7. 使用node发送邮件
nodemailer
js
const nodemailer = require('nodemailer');
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// ......
代码见上
// 使用模板方法
return new Promise((resolve, reject)=> {
let html = template(path.join(__dirname, './res.html'), {
// 在这里定义的值,在模板文件可以直接使用双花括号的形式引用
// test: '测试'
dayDate,
mojiData,
oneData
})
// console.log(html);
resolve(html); // html作为成功之后的参数
});
}
// 发送电子邮件
let sendNodeMail = async ()=> {
// 必须要等数据全部渲染完成之后,才往后面走
let html = await renderTemplate();
// console.log(html);
// 使用默认SMTP传输,创建可重用邮箱对象
let transporter = nodemailer.createTransport({
host: "smtp.163.com", // 网易邮箱SMTP服务器
port: 465,
secure: true, // 开启加密协议,需要使用465端口(网易ssl协议)
auth: {
user: 'xxxx@163.com', // 邮箱地址
pass: "JXOKFCNHYHGKGSRE", // 客户端授权密码(网易邮箱界面、设置、开启IMAP/SMTP)
},
});
// 设置电子邮件数据
let mailOptions = {
from: "'xxxx' <xxxx@163.com>", // 发件人邮箱
to: 'xxxx@qq.com', // 收件人列表(可以用逗号隔开)
subject: '测试邮件',
html: html // html内容
}
// 发送邮件
transporter.sendMail(mailOptions, (err, info={})=> {
if(err) {
console.log(err);
sendNodeMail(); // 再次发送
}
console.log('邮件发送成功', `${info.response}`);
console.log('等待下一次发送');
});
}
sendNodeMail();
const nodemailer = require('nodemailer');
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// ......
代码见上
// 使用模板方法
return new Promise((resolve, reject)=> {
let html = template(path.join(__dirname, './res.html'), {
// 在这里定义的值,在模板文件可以直接使用双花括号的形式引用
// test: '测试'
dayDate,
mojiData,
oneData
})
// console.log(html);
resolve(html); // html作为成功之后的参数
});
}
// 发送电子邮件
let sendNodeMail = async ()=> {
// 必须要等数据全部渲染完成之后,才往后面走
let html = await renderTemplate();
// console.log(html);
// 使用默认SMTP传输,创建可重用邮箱对象
let transporter = nodemailer.createTransport({
host: "smtp.163.com", // 网易邮箱SMTP服务器
port: 465,
secure: true, // 开启加密协议,需要使用465端口(网易ssl协议)
auth: {
user: 'xxxx@163.com', // 邮箱地址
pass: "JXOKFCNHYHGKGSRE", // 客户端授权密码(网易邮箱界面、设置、开启IMAP/SMTP)
},
});
// 设置电子邮件数据
let mailOptions = {
from: "'xxxx' <xxxx@163.com>", // 发件人邮箱
to: 'xxxx@qq.com', // 收件人列表(可以用逗号隔开)
subject: '测试邮件',
html: html // html内容
}
// 发送邮件
transporter.sendMail(mailOptions, (err, info={})=> {
if(err) {
console.log(err);
sendNodeMail(); // 再次发送
}
console.log('邮件发送成功', `${info.response}`);
console.log('等待下一次发送');
});
}
sendNodeMail();
8. 设置定时任务
js
// 创建定时任务
// 定时每天发送(每天5时20分14秒发送邮件)
(()=> {
// 每天5时20分14秒
schedule.scheduleJob('14 20 5 * * *',()=>{
// 开始发送邮件
console.log(new Date());
console.log("===================");
console.log("====开始发送邮件====");
console.log("===================");
sendNodeMail();
});
})();
// 创建定时任务
// 定时每天发送(每天5时20分14秒发送邮件)
(()=> {
// 每天5时20分14秒
schedule.scheduleJob('14 20 5 * * *',()=>{
// 开始发送邮件
console.log(new Date());
console.log("===================");
console.log("====开始发送邮件====");
console.log("===================");
sendNodeMail();
});
})();
9. 全部代码
js
const superagent = require('superagent'); // 向服务器发起http请求
const cheerio = require('cheerio');
const template = require('art-template'); // 导入模板引擎
const path = require('path');
const nodemailer = require('nodemailer'); // 邮件
const schedule = require("node-schedule"); // 定时任务
// 工具集
/* let util = {
// 时间戳
dateFormate(now) {
let year = now.getFullYear(); // 年
let month = now.getMonth() + 1; // 月
let date = now.getDate(); // 日
// 加上0
month < 10 ? month=`0${month}` : month; // 月
date < 10 ? date=`0${date}` : date; // 日
return `${year}-${month}-${date}`
},
// 计算时间
getCount() {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
return count;
}
} */
// 获取时间信息
let getDayDate = ()=> {
// 由于很多数据要提前准备好,才能渲染到页面,最终才能发送
// 这里就使用promise
return new Promise((resolve, reject)=> {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
let format = `${today.getFullYear()}/${today.getMonth()+1}/${today.getDate()}`
let dayData = {
count,
format
}
// console.log(dayData);
resolve(dayData); // 返回数据
});
}
// getDayDate(); // 获取时间信息
// 请求墨迹天气获取数据
let getMojiData = ()=> {
return new Promise((resolve, reject)=> {
// 发起http请求
superagent.get('https://tianqi.moji.com/weather/china/zhejiang/xiaoshan-district').end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图标
let icon = $('.wea_weather span img').attr('src');
// console.log(icon);
// 获取天气
let weather = $('.wea_weather b').text();
// console.log(weather);
// 获取温度
let temperature = $('.wea_weather em').text();
// console.log(temperature);
// 获取提示
let tip = $('.wea_tips em').text();
// console.log(tip);
let mojiData = {
icon,
weather,
temperature,
tip
}
// console.log(mojiData);
resolve(mojiData);
});
});
}
// getMojiData(); // 请求墨迹天气获取数据
// 请求one抓取数据
let getOneData = ()=> {
return new Promise((resolve, reject)=> {
superagent.get("http://wufazhuce.com/").end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图片
let oneImg = $('.carousel-inner .item.active img').attr('src');
// let onePic = $('#carousel-one > div > div.item img').eq(0).attr('src');
// console.log(oneImg);
// 获取文本
let oneTxt = $('.carousel-inner .item.active .fp-one-cita a').text();
// let oneTxt = $('.carousel-inner .item .fp-one-cita a').eq(0).text();
// console.log(oneTxt);
let oneData = {
oneImg,
oneTxt
}
// console.log(oneData);
resolve(oneData);
});
});
}
// getOneData();
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// 在方法里面涉及到数据请求(异步),会造成数据还没拿到,就开始渲染dom了
// 使用async和await
// 如果要用await调用得到函数,那么该函数必须返回的是promise对象
// 获取日期 - 等待请求完成之后才进行赋值
let dayDate = await getDayDate();
// 获取墨迹天气 - 等待请求完成之后才进行赋值
let mojiData = await getMojiData();
// 获取one数据 - 等待请求完成之后才进行赋值
let oneData = await getOneData();
// 所有数据获取成功之后,才进行模板引擎数据的替换
/* console.log(dayDate);
console.log(mojiData);
console.log(oneData); */
// 使用模板方法
return new Promise((resolve, reject)=> {
let html = template(path.join(__dirname, './res.html'), {
// 在这里定义的值,在模板文件可以直接使用双花括号的形式引用
// test: '测试'
dayDate,
mojiData,
oneData
})
// console.log(html);
resolve(html); // html作为成功之后的参数
});
}
// renderTemplate();
// 发送电子邮件
let sendNodeMail = async ()=> {
// 必须要等数据全部渲染完成之后,才往后面走
let html = await renderTemplate();
// console.log(html);
// 使用默认SMTP传输,创建可重用邮箱对象
let transporter = nodemailer.createTransport({
host: "smtp.163.com", // 网易邮箱SMTP服务器
port: 465,
secure: true, // 开启加密协议,需要使用465端口(网易ssl协议)
auth: {
user: 'xxxx@163.com', // 邮箱地址
pass: "xxxxxx", // 客户端授权密码(网易邮箱界面、设置、开启IMAP/SMTP)
},
});
// 设置电子邮件数据
let mailOptions = {
from: "'xxxx' <xxxx@163.com>", // 发件人邮箱
to: 'xxxx@qq.com', // 收件人列表(可以用逗号隔开)
subject: '测试邮件',
html: html // html内容
}
// 发送邮件
transporter.sendMail(mailOptions, (err, info={})=> {
if(err) {
console.log(err);
sendNodeMail(); // 再次发送
}
console.log('邮件发送成功', `${info.response}`);
console.log('等待下一次发送');
});
}
// sendNodeMail();
// 创建定时任务
// 定时每天发送(每天5时20分14秒发送邮件)
(()=> {
// 每天5时20分14秒
schedule.scheduleJob('14 20 5 * * *',()=>{
// 开始发送邮件
console.log(new Date());
console.log("===================");
console.log("====开始发送邮件====");
console.log("===================");
sendNodeMail(); // 发送电子邮件
});
})();
const superagent = require('superagent'); // 向服务器发起http请求
const cheerio = require('cheerio');
const template = require('art-template'); // 导入模板引擎
const path = require('path');
const nodemailer = require('nodemailer'); // 邮件
const schedule = require("node-schedule"); // 定时任务
// 工具集
/* let util = {
// 时间戳
dateFormate(now) {
let year = now.getFullYear(); // 年
let month = now.getMonth() + 1; // 月
let date = now.getDate(); // 日
// 加上0
month < 10 ? month=`0${month}` : month; // 月
date < 10 ? date=`0${date}` : date; // 日
return `${year}-${month}-${date}`
},
// 计算时间
getCount() {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
return count;
}
} */
// 获取时间信息
let getDayDate = ()=> {
// 由于很多数据要提前准备好,才能渲染到页面,最终才能发送
// 这里就使用promise
return new Promise((resolve, reject)=> {
// 现在的时间
let today = new Date();
// 设定的时间(2019-5-20)
let anniversary = new Date('2019-05-20');
// 计算时间差毫秒值
let count = today - anniversary;
// 时间格式转换(转换为天并向上取整)
count = Math.ceil(count/1000/60/60/24);
// count = Math.floor(count/1000/60/60/24); // 向下取整
// console.log(count);
let format = `${today.getFullYear()}/${today.getMonth()+1}/${today.getDate()}`
let dayData = {
count,
format
}
// console.log(dayData);
resolve(dayData); // 返回数据
});
}
// getDayDate(); // 获取时间信息
// 请求墨迹天气获取数据
let getMojiData = ()=> {
return new Promise((resolve, reject)=> {
// 发起http请求
superagent.get('https://tianqi.moji.com/weather/china/zhejiang/xiaoshan-district').end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图标
let icon = $('.wea_weather span img').attr('src');
// console.log(icon);
// 获取天气
let weather = $('.wea_weather b').text();
// console.log(weather);
// 获取温度
let temperature = $('.wea_weather em').text();
// console.log(temperature);
// 获取提示
let tip = $('.wea_tips em').text();
// console.log(tip);
let mojiData = {
icon,
weather,
temperature,
tip
}
// console.log(mojiData);
resolve(mojiData);
});
});
}
// getMojiData(); // 请求墨迹天气获取数据
// 请求one抓取数据
let getOneData = ()=> {
return new Promise((resolve, reject)=> {
superagent.get("http://wufazhuce.com/").end((err, res)=> {
// 如果可以成功返回
if(err) {
return console.log("数据请求失败,请检查路径");
}
// console.log(res.text);
// 把字符串解析成html,并可用jquery核心选择器获取内容
let $ = cheerio.load(res.text);
// 获取图片
let oneImg = $('.carousel-inner .item.active img').attr('src');
// let onePic = $('#carousel-one > div > div.item img').eq(0).attr('src');
// console.log(oneImg);
// 获取文本
let oneTxt = $('.carousel-inner .item.active .fp-one-cita a').text();
// let oneTxt = $('.carousel-inner .item .fp-one-cita a').eq(0).text();
// console.log(oneTxt);
let oneData = {
oneImg,
oneTxt
}
// console.log(oneData);
resolve(oneData);
});
});
}
// getOneData();
// 通过模板引擎替换html
// 需要注意执行顺序
let renderTemplate = async ()=> {
// 在方法里面涉及到数据请求(异步),会造成数据还没拿到,就开始渲染dom了
// 使用async和await
// 如果要用await调用得到函数,那么该函数必须返回的是promise对象
// 获取日期 - 等待请求完成之后才进行赋值
let dayDate = await getDayDate();
// 获取墨迹天气 - 等待请求完成之后才进行赋值
let mojiData = await getMojiData();
// 获取one数据 - 等待请求完成之后才进行赋值
let oneData = await getOneData();
// 所有数据获取成功之后,才进行模板引擎数据的替换
/* console.log(dayDate);
console.log(mojiData);
console.log(oneData); */
// 使用模板方法
return new Promise((resolve, reject)=> {
let html = template(path.join(__dirname, './res.html'), {
// 在这里定义的值,在模板文件可以直接使用双花括号的形式引用
// test: '测试'
dayDate,
mojiData,
oneData
})
// console.log(html);
resolve(html); // html作为成功之后的参数
});
}
// renderTemplate();
// 发送电子邮件
let sendNodeMail = async ()=> {
// 必须要等数据全部渲染完成之后,才往后面走
let html = await renderTemplate();
// console.log(html);
// 使用默认SMTP传输,创建可重用邮箱对象
let transporter = nodemailer.createTransport({
host: "smtp.163.com", // 网易邮箱SMTP服务器
port: 465,
secure: true, // 开启加密协议,需要使用465端口(网易ssl协议)
auth: {
user: 'xxxx@163.com', // 邮箱地址
pass: "xxxxxx", // 客户端授权密码(网易邮箱界面、设置、开启IMAP/SMTP)
},
});
// 设置电子邮件数据
let mailOptions = {
from: "'xxxx' <xxxx@163.com>", // 发件人邮箱
to: 'xxxx@qq.com', // 收件人列表(可以用逗号隔开)
subject: '测试邮件',
html: html // html内容
}
// 发送邮件
transporter.sendMail(mailOptions, (err, info={})=> {
if(err) {
console.log(err);
sendNodeMail(); // 再次发送
}
console.log('邮件发送成功', `${info.response}`);
console.log('等待下一次发送');
});
}
// sendNodeMail();
// 创建定时任务
// 定时每天发送(每天5时20分14秒发送邮件)
(()=> {
// 每天5时20分14秒
schedule.scheduleJob('14 20 5 * * *',()=>{
// 开始发送邮件
console.log(new Date());
console.log("===================");
console.log("====开始发送邮件====");
console.log("===================");
sendNodeMail(); // 发送电子邮件
});
})();