【重学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();
})
});
}
完整的逻辑去项目里翻代码吧。
【重学Node.js 第4篇】实现一个简易爬虫&启动定时任务的更多相关文章
- 【重学Node.js 第5篇】部署项目到腾讯云服务器
课程介绍看这里:https://www.cnblogs.com/zhangran/p/11963616.html 项目github地址:https://github.com/hellozhangran ...
- 【重学Node.js 第3篇】mongodb以及mongoose的使用
mongodb以及mongoose的使用 本篇为这个系列的第三篇,想看更多可以直接去github的项目:https://github.com/hellozhangran/happy-egg-serve ...
- 打算写一个《重学Node.js》系列,希望大家多多支持
先放上链接吧,项目已经开始2周了:https://github.com/hellozhangran/happy-egg-server 想法 现在是2019年11月24日,还有人要开始学习Node.js ...
- 【重学Node.js 第1&2篇】本地搭建Node环境并起RESTful Api服务
本地搭建Node环境并起RESTful Api服务 课程介绍看这里:https://www.cnblogs.com/zhangran/p/11963616.html 项目github地址:https: ...
- 学习node.js 第4篇 建立一个最小的web聊天系统
我们生活在一个实时的世界里,有什么比聊天更加实时吗?那就让我们先写一个基于TCP 的聊天服务器吧,并且支持Telnet 连接.这很容易,而且能够完全用Node来编写.首先,我们需要在Node 中包含T ...
- Node.js Stream-基础篇
Node.js Stream - 基础篇 邹斌 ·2016-07-08 11:51 背景 在构建较复杂的系统时,通常将其拆解为功能独立的若干部分.这些部分的接口遵循一定的规范,通过某种方式相连,以共同 ...
- 一目了然的 Node.js Windows10 安装篇
本篇文章 介绍 NodeJS 的安装 及环境变量配置 Node JS 的 了解 1.Node.js简介 简单的说 Node.js 就是运行在服务端的 JavaScript.Node.js 是一个基于 ...
- 利用Node.js的Net模块实现一个命令行多人聊天室
1.net模块基本API 要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用.NET模块API分为两大类:Server和Socket类.工厂方法. Server类 ...
- Node.js简单介绍并实现一个简单的Web MVC框架
编号:1018时间:2016年6月13日16:06:41功能:Node.js简单介绍并实现一个简单的Web MVC框架URL :https://cnodejs.org/topic/4f16442cca ...
随机推荐
- 基本数据类型的值传递 和引用数据类型的引用传递 Day06
ValueTest1.java package com.sxt.valuetest; /* * 基本数据类型的传递:传递的是值得副本 */ public class ValueTest1 { publ ...
- iOS 11 适配UIWebView,页面下移20的问题
方案1: AppDelegate文件 didFinishLaunchingWithOptions()中添加如下代码 if (@available(iOS 11.0, *)) { [[UIScrollV ...
- 2019-8-31-dotnet-core-输出调试信息到-DebugView-软件
title author date CreateTime categories dotnet core 输出调试信息到 DebugView 软件 lindexi 2019-08-31 16:55:58 ...
- jsp页面关建字查询出记录后,点下一页关键字会清空,怎么保持关键字不变而进行下一页操作?
解决方案一: 1 把关键字带回后台,从后台再次传入! 2 把关键字传入cookie,从cookie获取 3 把表格一栏放在iframe中,搜索时,刷新iframe即可 解决方案二: 用2个div分开就 ...
- oracle函数 SOUNDEX(c1)
[功能]返回字符串参数的语音表示形式 [参数]c1,字符型 [返回]字符串 [说明]相对于比较一些读音相同,但是拼写不同的单词是非常有用的. 计算语音的算法: 1.保留字符串首字母,但删除a.e.h. ...
- linux下修改gcc编译器版本
可以使用如下命令行来让 gcc 选择不同的 C++ 版本: g++ -std=c++11 main.cpp 在你的系统中,由于编译器或是编译器设定上的差别,操作也许有所不同.
- 「BZOJ3694」「FJ2014集训」最短路
「BZOJ3694」「FJ2014集训」最短路 首先树剖没得说了,这里说一下并查集的做法, 对于一条非树边,它会影响的点就只有u(i),v(i)到lca,对于lca-v的路径上所有点x,都可通过1-t ...
- P3899 [湖南集训]谈笑风生 主席树
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> ...
- ajax的状态
readyState:ajax对象的状态值,客户端与客户的交互过程 0:未初始化 1:已经调用了open方法 2:已经接收到响应头 3:已经接受了一部分数据(存在相应正文里) 4:已经接受了全部数据 ...
- U盘还原系统
相信现在不少的人已经开始使用U盘作为启动盘来安装系统,说起来这可比用光盘装系统可是方便多了.毕竟U盘可以随身携带,至于光盘嘛,就不多说了. 可是还有许多人对U盘安装系统还是有些陌生的感觉. ...