雙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