The summer is coming

我知道,那些夏天,就像青春一样回不来。 - 宋冬野

青春是回不来了,倒是要准备渡过在西安的第三个夏天了。

废话

我发现,自己对 coding 这件事的称呼,从敲代码 改为 写代码 了。

emmm....敲代码,自我感觉,就像是,习惯了用 const 定义常量的我看到别人用 var 定义的常量。

对,优雅!

写代码 这三个字,显得更为优雅一些,更像是在创作,打磨一件精致的作品。

改编自 掘金站长 的一句话:

子非猿,安之 coding 之乐也。

看完本文的收获

  • ctrl + c
  • ctrl + v
  • nodejs 入门级爬虫

为何写爬虫相关的文章

最近访问 艾特网 的时候发现请求有点慢。

后来经过一番检查,发现首页中搜索热点需要每次去爬取百度热搜的数据并当做接口返回给前端,由于是服务端渲染,接口堵塞就容易出现访问较慢的情况。

就想着对这个接口进行一次重构。

解决方案

  • 设置定时任务,每隔1分钟/3分钟/5分钟爬取新浪微博实时热搜(新浪微博热搜点击率更高一些)
  • 爬取到数据后不直接返回给前端,先写入一个.json格式的文件。
  • 服务端渲染的后台接口请求并返回给前端json文件的内容

需求捋清楚以后就可以开干了。

创建工程

初始化

首先得找到目标站点,如下:(微博实时热搜)

https://s.weibo.com/top/summary?cate=realtimehot

创建文件夹 weibo

进入文件夹根目录

使用 npm init -y 快速初始化一个项目

安装依赖

创建app.js文件

安装以下依赖

npm i cherrio superagent -D

关于superagentcherrio的介绍

superagent 是一个轻量级、渐进式的请求库,内部依赖 nodejs 原生的请求 api,适用于 nodejs 环境。

cherrio 是 nodejs 的抓取页面模块,为服务器特别定制的,快速、灵活、实施的 jQuery 核心实现。适合各种 Web 爬虫程序。node.js 版的 jQuery。

代码编写

打开 app.js ,开始完成主要功能

首先在顶部引入cheeriosuperagent 以及 nodejs 中的 fs 模块

const cheerio = require("cheerio");
const superagent = require("superagent");
const fs = require("fs");

通过变量的方式声明热搜的url,便于后面 复用

const weiboURL = "https://s.weibo.com";
const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot";

superagent

使用 superagent 发送get请求
superagentget 方法接收两个参数。第一个是请求的 url 地址,第二个是请求成功后的回调函数。

回调函数有俩参数,第一个参数为 error ,如果请求成功,则返回 null,反之则抛出错误。第二个参数是请求成功后的 响应体

superagent.get(hotSearchURL, (err, res) => {
if (err) console.error(err);
});

网页元素分析

打开目标站对网页中的 DOM 元素进行一波分析。

jQuery 比较熟的小老弟,看到下图如此简洁清晰明了的 DOM 结构,是不是有 N 种取出它每个 tr 中的数据并 push 到一个 Array 里的方法呢?

对!我们最终的目的就是要通过 jQuery 的语法,遍历每个 tr ,并将其每一项的 热搜地址热搜内容热度值序号表情等信息 push 进一个空数组中

再将它通过 nodejsfs 模块,写入一个 json 文件中。

jQuery 遍历拿出数据

使用 jQueryeach 方法,对 tbody 中的每一项 tr 进行遍历,回调参数中第一个参数为遍历的下标 index,第二个参数为当前遍历的元素,一般 $(this) 指向的就是当前遍历的元素。

let hotList = [];
$("#pl_top_realtimehot table tbody tr").each(function (index) {
if (index !== 0) {
const $td = $(this).children().eq(1);
const link = weiboURL + $td.find("a").attr("href");
const text = $td.find("a").text();
const hotValue = $td.find("span").text();
const icon = $td.find("img").attr("src")
? "https:" + $td.find("img").attr("src")
: "";
hotList.push({
index,
link,
text,
hotValue,
icon,
});
}
});

cheerio 包装请求后的响应体

nodejs 中,要想向上面那样愉快的写 jQuery 语法,还得将请求成功后返回的响应体,用 cheerioload 方法进行包装。

const $ = cheerio.load(res.text);

写入 json 文件

接着使用 nodejsfs 模块,将创建好的数组转成 json字符串,最后写入当前文件目录下的 hotSearch.json 文件中(无此文件则会自动创建)。

fs.writeFileSync(
`${__dirname}/hotSearch.json`,
JSON.stringify(hotList),
"utf-8"
);

完整代码如下:

const cheerio = require("cheerio");
const superagent = require("superagent");
const fs = require("fs");
const weiboURL = "https://s.weibo.com";
const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot";
superagent.get(hotSearchURL, (err, res) => {
if (err) console.error(err);
const $ = cheerio.load(res.text);
let hotList = [];
$("#pl_top_realtimehot table tbody tr").each(function (index) {
if (index !== 0) {
const $td = $(this).children().eq(1);
const link = weiboURL + $td.find("a").attr("href");
const text = $td.find("a").text();
const hotValue = $td.find("span").text();
const icon = $td.find("img").attr("src")
? "https:" + $td.find("img").attr("src")
: "";
hotList.push({
index,
link,
text,
hotValue,
icon,
});
}
});
fs.writeFileSync(
`${__dirname}/hotSearch.json`,
JSON.stringify(hotList),
"utf-8"
);
});

打开终端,输入 node app,可看到根目录下多了个 hotSearch.json 文件。

定时爬取

虽然代码可以运行,也能爬取到数据并存入 json 文件。

但是,每次都要手动运行,才能爬取到当前时间段的热搜数据,这一点都 不人性化!

最近微博热搜瓜这么多,咱可是一秒钟可都不能耽搁。我们最开始期望的是每隔多长时间 定时执行爬取 操作。瓜可不能停!


接下来,对代码进行 小部分改造

数据请求封装

由于 superagent 请求是个异步方法,我们可以将整个请求方法用 Promise 封装起来,然后 每隔指定时间 调用此方法即可。

function getHotSearchList() {
return new Promise((resolve, reject) => {
superagent.get(hotSearchURL, (err, res) => {
if (err) reject("request error");
const $ = cheerio.load(res.text);
let hotList = [];
$("#pl_top_realtimehot table tbody tr").each(function (index) {
if (index !== 0) {
const $td = $(this).children().eq(1);
const link = weiboURL + $td.find("a").attr("href");
const text = $td.find("a").text();
const hotValue = $td.find("span").text();
const icon = $td.find("img").attr("src")
? "https:" + $td.find("img").attr("src")
: "";
hotList.push({
index,
link,
text,
hotValue,
icon,
});
}
});
hotList.length ? resolve(hotList) : reject("errer");
});
});
}

node-schedule 详解

定时任务我们可以使用 node-schedule 这个 nodejs库 来完成。

https://github.com/node-schedule/node-schedule

先安装

npm i node-schedule -D

头部引入

const nodeSchedule = require("node-schedule");

用法(每分钟的第 30 秒定时执行一次):

const rule = "30 * * * * *";
schedule.scheduleJob(rule, () => {
console.log(new Date());
});

规则参数:

*    *    *    *    *    *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ │
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)

6 个占位符从左到右依次代表:秒、分、时、日、月、周几
* 表示通配符,匹配任意。当 * 为秒时,表示任意秒都会触发,其他类推。
来看一个 每小时的第20分钟20秒 定时执行的规则:

20 20 * * * *

更多规则自行搭配。

定时爬取,写入文件

使用定时任务来执行上面的请求数据,写入文件操作:

nodeSchedule.scheduleJob("30 * * * * *", async function () {
try {
const hotList = await getHotSearchList();
await fs.writeFileSync(
`${__dirname}/hotSearch.json`,
JSON.stringify(hotList),
"utf-8"
);
} catch (error) {
console.error(error);
}
});

哦对,别忘了 捕获异常

下面贴上完整代码(可直接 ctrl c/v):

const cheerio = require("cheerio");
const superagent = require("superagent");
const fs = require("fs");
const nodeSchedule = require("node-schedule");
const weiboURL = "https://s.weibo.com";
const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot";
function getHotSearchList() {
return new Promise((resolve, reject) => {
superagent.get(hotSearchURL, (err, res) => {
if (err) reject("request error");
const $ = cheerio.load(res.text);
let hotList = [];
$("#pl_top_realtimehot table tbody tr").each(function (index) {
if (index !== 0) {
const $td = $(this).children().eq(1);
const link = weiboURL + $td.find("a").attr("href");
const text = $td.find("a").text();
const hotValue = $td.find("span").text();
const icon = $td.find("img").attr("src")
? "https:" + $td.find("img").attr("src")
: "";
hotList.push({
index,
link,
text,
hotValue,
icon,
});
}
});
hotList.length ? resolve(hotList) : reject("errer");
});
});
}
nodeSchedule.scheduleJob("30 * * * * *", async function () {
try {
const hotList = await getHotSearchList();
await fs.writeFileSync(
`${__dirname}/hotSearch.json`,
JSON.stringify(hotList),
"utf-8"
);
} catch (error) {
console.error(error);
}
});

各种玩法

  • 以上代码可直接集成进现有的 express koa eggjs 或者原生的 nodejs 项目中,作为接口返回给前端。

  • 集成进 Serverless,作为接口返回给前端。

  • 对接微信公众号,发送 热搜 关键字即可实时获取热搜数据。

  • 集成进 微信机器人 ,每天在指定的时间给自己/群里发送微博热搜数据。

  • other......

都看到这里啦,就很棒! 点个赞 再走嘛。


程序员导航站:https://iiter.cn

下面是咱的公众号呀 前端糖果屋

代码 github 已开源:

https://github.com/isnl/weibo-hotSearch-crawler

nodejs实现定时爬取微博热搜的更多相关文章

  1. Python网络爬虫-爬取微博热搜

    微博热搜的爬取较为简单,我只是用了lxml和requests两个库 url=https://s.weibo.com/top/summary?Refer=top_hot&topnav=1& ...

  2. BeautifulSoup爬取微博热搜榜

    获取url 设定请求头 requests发出get请求 实例化BeautifulSoup对象 BeautifulSoup提取数据 import requests 2 from bs4 import B ...

  3. Python爬取微博热搜以及链接

    基本操作,不再详述 直接贴源码(根据当前时间创建文件): import requests from bs4 import BeautifulSoup import time def input_to_ ...

  4. 【网络爬虫】【java】微博爬虫(一):小试牛刀——网易微博爬虫(自定义关键字爬取微博数据)(附软件源码)

    一.写在前面 (本专栏分为"java版微博爬虫"和"python版网络爬虫"两个项目,系列里所有文章将基于这两个项目讲解,项目完整源码已经整理到我的Github ...

  5. 2020不平凡的90天,Python分析三个月微博热搜数据带你回顾

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:刘早起早起 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...

  6. 第一个nodejs爬虫:爬取豆瓣电影图片

    第一个nodejs爬虫:爬取豆瓣电影图片存入本地: 首先在命令行下 npm install request cheerio express -save; 代码: var http = require( ...

  7. python3爬取微博评论并存为xlsx

    python3爬取微博评论并存为xlsx**由于微博电脑端的网页版页面比较复杂,我们可以访问手机端的微博网站,网址为:https://m.weibo.cn/一.访问微博网站,找到热门推荐链接我们打开微 ...

  8. C#爬取微博文字、图片、视频(不使用Cookie)

    前两天在网上偶然看到一个大佬OmegaXYZ写的文章,Python爬取微博文字与图片(不使用Cookie) 于是就心血来潮,顺手撸一个C#版本的. 其实原理也很简单,现在网上大多数版本都需要Cooki ...

  9. 纯前端实现词云展示+附微博热搜词云Demo代码

    前言 最近工作中做了几个数据可视化大屏项目,其中也有用到了词云展示,以前做词云都是用python库来生成图片显示的,这次用了纯前端的实现(Ctrl+V真好用),同时顺手做个微博热搜的词云然后记录一下~ ...

随机推荐

  1. 【tensorflow2.0】数据管道dataset

    如果需要训练的数据大小不大,例如不到1G,那么可以直接全部读入内存中进行训练,这样一般效率最高. 但如果需要训练的数据很大,例如超过10G,无法一次载入内存,那么通常需要在训练的过程中分批逐渐读入. ...

  2. 构建Mysql服务器

    <综合>构建Mysql服务器 构建MySQL服务器 数据库基本管理 MySQL 数据类型 表结构的调整 1 构建MySQL服务器 1.1 问题 本案例要求熟悉MySQL官方安装包的使用,快 ...

  3. find的基本查询命令《二》

    Linux find命令详解 由于find具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时间来了解一下.即使系统中含有网络文件系统( NFS),find命令在该文件系统中同样有效,只你 ...

  4. time_wait 详解和解决方案

    1. 产生原因 2. 导致问题 3. Nginx 3.1 长连接 4. 解决方案 5 .参考 产生原因 TCP 连接关闭时,会有 4 次通讯(四次挥手),来确认双方都停止收发数据了.如上图,主动关闭方 ...

  5. 【mysql】mysql优化

    一,表设计 1.1. E-R(entity relation)实体关系图 长方形 实体 表 椭圆形 属性 字段 菱形 关系 一对一 多对一 属于 多对多 1.2. 三范式标准 原子性 个人信息 省市县 ...

  6. Docker的简介以及Dockerfile编写与使用

    Docker的简介 Docker是在容器的基础上,进行了进一步的封装,极大的简化了容器的创建和维护.使得Docker技术比虚拟机技术更为轻便.快捷. 下面是两张对比图. 可以看到传统虚拟机技术是虚拟出 ...

  7. django-rest-framework视图和url

    django-rest-framework视图 GenericView class GenericView(GenericAPIView): queryset = models.Role.object ...

  8. tp6源码解析-第二天,ThinkPHP6编译模板流程详解,ThinkPHP6模板源码详解

    TP6源码解析,ThinkPHP6模板编译流程详解 前言:刚开始写博客.如果觉得本篇文章对您有所帮助.点个赞再走也不迟 模板编译流程,大概是: 先获取到View类实例(依赖注入也好,通过助手函数也好) ...

  9. 面试官求你了,别再问我TCP的三次握手和四次挥手

    少点代码,多点头发 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles 三次握手建立链接,四次挥手断 ...

  10. lr具体使用步骤概述

    lr具体使用 1 无工具情况下的性能测试 2性能测试工具LoadRunner的工作原理 3 VuGen应用介绍 4 协议的类型及选择方法 5 脚本的创建过程 6 脚本的参数化 7 调试技术 8 Con ...