Nodejs监控Apple召回计划&邮件提醒

最近,我的13寸 MacBook Pro 2015款电池膨胀了

把笔记本平放在桌面,四个脚中的前两个无法落地,笔记本盖合上之后,屏幕上会印上键盘的纹路,也就是说,笔记本C面D面变形了,已经购买超过3年,售后不给换,同年生产的15寸的MacBook Pro因为同样的问题出了电池召回计划,我想着再坚持一下,看看13寸的会不会也出召回计划

Apple的召回计划全都更新在这里https://support.apple.com/zh-cn/exchange_repair,每天手动去查看一次,不太对得起这台笔记本,干脆写了一个爬虫监控这个页面,有最新消息就邮件通知我,对笔记本来说,也算是“自己的事情自己做”

首先利用axios加载页面,cheerio负责解析,然后找到最新一篇召回计划的标题和链接

import axios from 'axios';
import async from 'async';
import cheerio from 'cheerio';

const URL = 'https://support.apple.com/zh-cn/exchange_repair';
const homePage = await axios.get(URL);
const $ = cheerio.load(homePage.data);
const firstRepair = $('.as-columns .table-responsive .icon-chevronright');
const firstTitle = firstRepair.eq(0).text();
const firstHref = firstRepair.closest('a').attr('href');

比对标题的开头,是不是以“13 英寸 MacBook Pro”开头的,如果是,用nodemailer以我qq邮箱的身份发邮件给我(发到我的gmail邮箱)

import nodemailer from 'nodemailer';
import path from 'path';

const reg = /^13 英寸 MacBook Pro/g;
// 创建传输器对象
let transporter = nodemailer.createTransport({
    service: 'qq',
    port: 465,
    secureConnection: true,
    auth: {
        // 发件人地址
        user: '[email protected]',
        // SMTP授权码
        pass: 'xxxx'
    }
});

// 有针对MacBook Pro 13寸的新召回计划,邮件我
if (reg.test(firstTitle)) {
    let mailOptions = {
        // 发件人
        from: '"【我的定时任务】"[email protected]', 
        // 收件人
        to: '[email protected]', 
        // 邮件主题
        subject: '有针对MacBook Pro 13寸的新召回计划了', 
        // 发送text或者html格式
        // text: 'Hello world?',
        html: `<div>
            <h3><a style="color: black" href="https://support.apple.com${firstHref}" target="_blank">${firstTitle}</a></h3>
            <img src="cid:01" />
        </div>`,
        // 附件
        attachments: [
            {
                filename: 'Apple.png',
                path: path.resolve(__dirname, 'Apple.png'),
                cid: '01',
            }
        ]
    };

    transporter.sendMail(mailOptions, (err, info) => {
        if (err) {
            return console.log(err);
        }
    });
}

其中transporter里的pass不是邮箱密码,而是SMTP授权码,就是授权nodejs用我的qq邮箱发邮件,在qq邮箱【设置】-【账户】里面开启SMTP服务并获取SMTP授权码

你可能注意到我在邮件HTML模板里加入了一张图片Apple.png,并且这张图片的来源就是附件,给附件加个cid就可以在模板里引用了,图片是邮件HTML模板唯一可以引用的外部资源,其他包括字体文件、视频、js文件等都不可引用

另外需要注意的是,我将召回计划的标题颜色设置为黑色,用的是行间样式,是考虑到两个问题

一是兼容性问题,部分邮箱客户端会过滤掉style标签

二是行间样式权重高,web版gmail会给a链接增加一个样式类,设置链接的字体颜色为蓝色,我利用样式权重高的特性,将浏览器给的样式覆盖,从而达到我要的效果

做了个测试,字体颜色前后对比

更多类似兼容性去这里查询 

mailOptions还有更多配置,如CC抄送等,更多配置请到这里查看

回到正题,我的需求是每天自动查看一次,此处需要一个定时任务,交给node-schedule

import schedule from 'node-schedule';

// 每天上午9点执行
schedule.scheduleJob('0 9 * * *', () => {
    // 每天到点干某事
});

综上,完整代码如下

/**
 * 定时查看Apple召回计划&邮件提醒
 */
import schedule from 'node-schedule';
import axios from 'axios';
import async from 'async';
import cheerio from 'cheerio';
import nodemailer from 'nodemailer';
import dayjs from 'dayjs';
import path from 'path';

const formatString = 'YYYY-MM-DD HH:mm';
const timestamp = () => {
    return dayjs().format(formatString);
}
const reptile = async () => {
    const URL = 'https://support.apple.com/zh-cn/exchange_repair';
    const homePage = await axios.get(URL);
    const $ = cheerio.load(homePage.data);
    const firstRepair = $('.as-columns .table-responsive .icon-chevronright');
    const firstTitle = firstRepair.eq(0).text();
    const firstHref = firstRepair.closest('a').attr('href');
    const reg = /^13 英寸 MacBook Pro/g;

    // 创建传输器对象
    let transporter = nodemailer.createTransport({
        service: 'qq',
        port: 465,
        secureConnection: true,
        auth: {
            user: '[email protected]',
            pass: 'xxx'
        }
    });

    // 有针对MacBook Pro 13寸的新召回计划,邮件我
    if (reg.test(firstTitle)) {
        let mailOptions = {
            // 发件人
            from: '"【我的定时任务】"[email protected]', 
            // 收件人
            to: '[email protected]', 
            // 邮件主题
            subject: '有针对MacBook Pro 13寸的新召回计划了', 
            // 发送text或者html格式
            // text: 'Hello world?',
            html: `<div>
                <h3><a style="color: black" href="https://support.apple.com${firstHref}" target="_blank">${firstTitle}</a></h3>
                <img src="cid:01" />
            </div>`,
            // 附件
            attachments: [
                {
                    filename: 'Apple.png',
                    path: path.resolve(__dirname, 'Apple.png'),
                    cid: '01',
                }
            ]
        };

        transporter.sendMail(mailOptions, (err, info) => {
            if (err) {
                return console.log(err);
            } else {
                console.log(`${timestamp()}:邮件已发送~`);
            }
        });
    }else{
        console.log(`${timestamp()}:Apple暂无新召回计划~`);
    }
};
reptile();
console.log(`${timestamp()}:定时任务执行中……`);

// 每天上午9点执行
schedule.scheduleJob('0 9 * * *', () => {
    try {
        reptile();
    } catch (err) {
        console.log(err);
    }
});

由于nodejs不能直接执行ES6,需要配置一下环境

一、安装babel-node

npm i -g @babel/core @babel/node

二、安装 presets 并配置 .babelrc 文件

npm i @babel/preset-env --save-dev

配置.babelrc 

{
  "presets": [ "@babel/preset-env" ]
}

OK,可以执行了

babel-node xxx.js

……

本文地址:https://www.cnblogs.com/wangmeijian/p/11225845.html 

猜你喜欢

转载自www.cnblogs.com/wangmeijian/p/11225845.html