• 【重学Node.js 第4篇】实现一个简易爬虫&启动定时任务


    实现一个简易爬虫&启动定时任务

    课程介绍看这里:https://www.cnblogs.com/zhangran/p/11963616.html
    项目github地址:https://github.com/hellozhangran/happy-egg-server

    爬虫

    目前 node.js 爬虫工具比较火的有 node-crawler puppeteer。不过我目前没打算用这些,因为至少现在我们的项目还用不到。只要能发送请求、解析dom我们就能自己实现一个爬虫。所以我选择了axios + cheerio来自己写爬虫。

    获取博客园的推荐文章

    首先我们用 axios + cheerio 来获取博客园的首页编辑推荐文章,并解析出这篇文章的正文部分。

    // controller/crawler.js 文件
    const axios = require('axios');
    const cheerio = require('cheerio');
    // articleCtrl是一个写好了的controller,里面有存储数据到mongo的逻辑。
    const articleCtrl = require('./article');
    
    async function cnblogs () {
        const res = await axios.get('https://www.cnblogs.com/');
        // 把axios得到的数据用cheerio解析,解析后的$对象拥有jquery的能力,可以通过jquery api直接操作dom
        const $ = cheerio.load(res.data);
        const $href = $('#editor_pick_lnk');
        let name = $href.text();
        // 找到编辑推荐文章的url,继续访问该页面
        let href = $href.attr('href');
        
        const subRes = await axios.get(href);
        const $$ = cheerio.load(subRes.data);
        // 获得编辑推荐文章的正文部分的html
        const bodyStr = $$('#cnblogs_post_body').html();
        // 存入mongodb,具体articleCtrl.create方法的实现可以从项目源码中看,位置express/controller/article.js
        const cRes = await articleCtrl.create({
            from: 'cnblogs',
            title: name,
            article: bodyStr,
            hot_level: 1,
            favor: 1,
            comment: 1
        });
    };
    
    module.exports = {
        cnblogs
    };
    

    通过上面简单的代码,我们就能把博客园的推荐文章正文部分存到数据库。接下来要创建定时任务,把每天的推荐文章都存到自己的数据库了。

    定时任务

    实例

    定时任务工具我选择 node-schedule ,先上实例,后面再详细讲下用法。

    // schedule/index.js 文件
    var schedule = require('node-schedule');
    
    // 可以按照cron的格式设置
    function runSchedule (cb) {
        // cron风格的配置:每天上午10点执行一次
        schedule.scheduleJob('0 0 10 * * *', function () {
            console.log('定时任务执行一次');
                cb && cb();
        });
        // object风格的配置:每天上午10点执行一次
        // 注意,这里需要加minute:0, 否则10点的每一分钟都执行一次。
        schedule.scheduleJob({hour: 10, minute: 0}, function () {
            console.log('定时任务执行一次');
                cb && cb();
        });
    }
    
    module.exports = runSchedule;
    

    接下来讲讲 cron 与 object 两种配置风格的差异。

    建议大家直接用 cron 风格的配置方式。当我第一次看到 object 配置风格的时候也觉得很人性化,可用过后会发现坑太多,越用成本越大。不信可以慢慢看

    object风格

    // 每天上午7点的每分钟都执行一次 (本以为会每天7点执行一次)
    let obj = { hour: 7};
    
    // 同上
    let obj = { hour: 7, minute: null};
    
    // 上午7点整执行一次
    let obj = { hour: 7, minute: 0};
    
    // 每秒执行一次
    let obj = { second: null }
    
    // 每分钟执行一次
    let obj = { hour: null }; // 费解,这个不应该是每小时执行一次吗
    
    // 每分钟执行一次
    let obj = { minute: null };
    
    // 每小时执行一次
    let obj = { hour: null, minute: 0 }
    

    cron风格定时器

    • * * * * * * 每秒执行一次
    • 0 * * * * * 每分钟的第0秒执行一次
    • 0 0 * * * * 每小时的0分0秒执行一次
    • 0 0 7 * * * 每天早上7点的0分0秒执行一次
    • 0 0 7 1 * * 每月的1日早上7点0分0秒执行一次
    • 0 0 7 * * 1 每周1的早上7点0分0秒执行一次

    对比完了这两种风格能明显的看出:虽然 object 更人性化但个人觉的有点中看不中用的感觉。尤其是对于个性化的配置,object 显的很蹩脚,而且你根本没法查,没那么多使用说明给到你。相比下 cron 本身就是linux的通用定时任务,各种玩法都被人用了多少遍了。

    启动定时任务

    最后,在 app.js 补上下面的逻辑,node app.js 启动服务,等待定时任务的执行吧。

    const runSchedule = require('./schedule');
    const crawlerCtrl = require('./controller/crawler');
    
    function listen () {
        app.listen('3000', () => {
            console.log('listen: 3000');
            // 开启自动脚本
            runSchedule(function() {
                crawlerCtrl.cnblogs();
            })
        });
    }
    

    完整的逻辑去项目里翻代码吧。

  • 相关阅读:
    LeetCode: 18. 4Sum
    LeetCode:15. 3Sum
    Leetcode:1. Two Sum
    tensorflow placeholder
    Tensorflow变量
    13.git的简单使用
    13.Django1.11.6文档
    12.python进程协程异步IO
    12.Flask-Restful
    12.Django思维导图
  • 原文地址:https://www.cnblogs.com/zhangran/p/12144703.html
Copyright © 2020-2023  润新知