双11的时候,为了给我家主子囤些猫砂猫罐头啥的,一直刷豆瓣爱猫小组的开车贴,边刷边玩cod16,结果就是错过了不少豪车,游戏KD也降了很多。过后我痛定思痛,把猫送人,耽搁我刷金枪 决定整个小玩意儿糊弄一下主子html
其实要作的事也简单,写个爬虫,定时爬一下带关键字的帖子,而后邮件通知我。尽管是随便发挥,接触下实际工做中没太接触过的东西也是好的么。
做为一个纯前端,固然是用node啦,配合puppeteer、nodemailer、node-schedule来实现核心功能前端
我把关键的部分提出来方便看,其实都是几个工具的快速入门部分,难度基本没有,毕竟是糊弄入门学习么。
不合理的地方大佬们使劲喷,我顶得住node
const puppeteer = require('puppeteer'); const url = 'https://www.douban.com/group/search?group=656297&cat=1013&q=开车'; const sleep = time => new Promise(resolve => { setTimeout(resolve, time); }); // puppeteer文档地址:https://github.com/puppeteer/puppeteer/blob/v2.0.0/docs/api.md#pagegotourl-options const queryInfos = async () => { const browser = await puppeteer.launch({}); const page = await browser.newPage(); page.goto(url, { waitUntil: 'networkidle2', }); await sleep(5000);// 确保爬到东西,时间能够缩短 const result = await page.evaluate(() => { // eslint-disable-next-line no-undef const $ = window.$; // 我比较关注的关键字,能够考虑扩展下来实现相似只匹配猫砂但不匹配猫砂盆,这就不展开了 const keywords = /罐|餐盒|巅峰|渴望|go|砂/; const postList = $('.td-subject a'); const links = []; if (postList.length > 0) { postList.each((i, e) => { const title = $(e).text(); const link = $(e).attr('href'); const id = link.match(/\d+/g).toString(); if (keywords.test(title)) { links.push({ id, title, link, keywords: title.match(keywords), }); } }); } return links; }); browser.close(); return result; };
const nodemailer = require('nodemailer'); const smtpTransport = require('nodemailer-smtp-transport'); const url = 'https://www.douban.com/group/search?group=656297&cat=1013&q=开车'; const qqTransport = nodemailer.createTransport(smtpTransport({ service: 'QQ', auth: { user: '123@qq.com',// 发件地址 pass: '',// 受权码 }, })); const sendMail = function(num, content) { qqTransport.sendMail({ from: '123@qq.com', to: '456@qq.com', subject: `${num}辆新车上路`, html: content, }, function(err, res) { if (err) { return; } console.log('发送成功', res); }); }; async queryCarsList() { const list = await getInfos(); let total = 0; let carList = ''; // 注意async/await跟for更配哦 for (let i = 0, len = list.length; i < len; i++) { const car = list[i]; const { id, title, link, } = car; // 这部分的实现比较简单粗暴,但愿你们多批评 // 爬到的数据我一开始简单粗暴的直接用fs写到json文件里了,但来都来了,顺便用下数据库也无伤大雅么 const temp = await queryById(id); if (temp.length < 1) { carList += `<p><a href="${link}">${title}</a></p>`; total++; const info = new this.ctx.model.Cars({ ...car, }); info.save(); } } if (total > 0) { sendMail(total, carList); } } async queryById(id) { return this.ctx.model.Cars.find({id}); }
基本的功能setInterval应该也是能够完成的,但为了后期好扩展,并且,来都来了,试一下node-schedule也无妨git
const schedule = require('node-schedule'); const queryTask = ()=>{ // 半小时执行一次 schedule.scheduleJob('* 30 * * * *', queryCarsList); } // queryTask.cancel() // 取消任务
部署就不展开讲了,我是打算eggjs+pm2丢本身服务器上,目前仍是本机跑一下,毕竟本职工做优先级最高,并且最近不用给它囤东西了github
考虑下要一直维护的话,还有不少地方要搞数据库
算球,为了一只猫,逗猫棒乐呵乐呵得了❌
唉,来都来了✅json
具体功能不难实现,但好像能接触的东西还很多,并且要作好了仍是得花点功夫的,随便发散一下,需求又是无限多,慢慢填吧。
对了,不合理的地方大佬们使劲喷,我顶得住
附恶毒甲方照片一张:api