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文件

安装以下依赖

  1. npm i cherrio superagent -D

关于superagentcherrio的介绍

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

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

代码编写

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

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

  1. const cheerio = require("cheerio");
  2. const superagent = require("superagent");
  3. const fs = require("fs");

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

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

superagent

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

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

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

网页元素分析

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

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

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

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

jQuery 遍历拿出数据

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

  1. let hotList = [];
  2. $("#pl_top_realtimehot table tbody tr").each(function (index) {
  3. if (index !== 0) {
  4. const $td = $(this).children().eq(1);
  5. const link = weiboURL + $td.find("a").attr("href");
  6. const text = $td.find("a").text();
  7. const hotValue = $td.find("span").text();
  8. const icon = $td.find("img").attr("src")
  9. ? "https:" + $td.find("img").attr("src")
  10. : "";
  11. hotList.push({
  12. index,
  13. link,
  14. text,
  15. hotValue,
  16. icon,
  17. });
  18. }
  19. });

cheerio 包装请求后的响应体

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

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

写入 json 文件

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

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

完整代码如下:

  1. const cheerio = require("cheerio");
  2. const superagent = require("superagent");
  3. const fs = require("fs");
  4. const weiboURL = "https://s.weibo.com";
  5. const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot";
  6. superagent.get(hotSearchURL, (err, res) => {
  7. if (err) console.error(err);
  8. const $ = cheerio.load(res.text);
  9. let hotList = [];
  10. $("#pl_top_realtimehot table tbody tr").each(function (index) {
  11. if (index !== 0) {
  12. const $td = $(this).children().eq(1);
  13. const link = weiboURL + $td.find("a").attr("href");
  14. const text = $td.find("a").text();
  15. const hotValue = $td.find("span").text();
  16. const icon = $td.find("img").attr("src")
  17. ? "https:" + $td.find("img").attr("src")
  18. : "";
  19. hotList.push({
  20. index,
  21. link,
  22. text,
  23. hotValue,
  24. icon,
  25. });
  26. }
  27. });
  28. fs.writeFileSync(
  29. `${__dirname}/hotSearch.json`,
  30. JSON.stringify(hotList),
  31. "utf-8"
  32. );
  33. });

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

定时爬取

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

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

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


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

数据请求封装

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

  1. function getHotSearchList() {
  2. return new Promise((resolve, reject) => {
  3. superagent.get(hotSearchURL, (err, res) => {
  4. if (err) reject("request error");
  5. const $ = cheerio.load(res.text);
  6. let hotList = [];
  7. $("#pl_top_realtimehot table tbody tr").each(function (index) {
  8. if (index !== 0) {
  9. const $td = $(this).children().eq(1);
  10. const link = weiboURL + $td.find("a").attr("href");
  11. const text = $td.find("a").text();
  12. const hotValue = $td.find("span").text();
  13. const icon = $td.find("img").attr("src")
  14. ? "https:" + $td.find("img").attr("src")
  15. : "";
  16. hotList.push({
  17. index,
  18. link,
  19. text,
  20. hotValue,
  21. icon,
  22. });
  23. }
  24. });
  25. hotList.length ? resolve(hotList) : reject("errer");
  26. });
  27. });
  28. }

node-schedule 详解

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

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

先安装

  1. npm i node-schedule -D

头部引入

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

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

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

规则参数:

  1. * * * * * *


  2. day of week (0 - 7) (0 or 7 is Sun)
  3. └───── month (1 - 12)
  4. └────────── day of month (1 - 31)
  5. └─────────────── hour (0 - 23)
  6. └──────────────────── minute (0 - 59)
  7. └───────────────────────── second (0 - 59, OPTIONAL)

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

  1. 20 20 * * * *

更多规则自行搭配。

定时爬取,写入文件

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

  1. nodeSchedule.scheduleJob("30 * * * * *", async function () {
  2. try {
  3. const hotList = await getHotSearchList();
  4. await fs.writeFileSync(
  5. `${__dirname}/hotSearch.json`,
  6. JSON.stringify(hotList),
  7. "utf-8"
  8. );
  9. } catch (error) {
  10. console.error(error);
  11. }
  12. });

哦对,别忘了 捕获异常

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

  1. const cheerio = require("cheerio");
  2. const superagent = require("superagent");
  3. const fs = require("fs");
  4. const nodeSchedule = require("node-schedule");
  5. const weiboURL = "https://s.weibo.com";
  6. const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot";
  7. function getHotSearchList() {
  8. return new Promise((resolve, reject) => {
  9. superagent.get(hotSearchURL, (err, res) => {
  10. if (err) reject("request error");
  11. const $ = cheerio.load(res.text);
  12. let hotList = [];
  13. $("#pl_top_realtimehot table tbody tr").each(function (index) {
  14. if (index !== 0) {
  15. const $td = $(this).children().eq(1);
  16. const link = weiboURL + $td.find("a").attr("href");
  17. const text = $td.find("a").text();
  18. const hotValue = $td.find("span").text();
  19. const icon = $td.find("img").attr("src")
  20. ? "https:" + $td.find("img").attr("src")
  21. : "";
  22. hotList.push({
  23. index,
  24. link,
  25. text,
  26. hotValue,
  27. icon,
  28. });
  29. }
  30. });
  31. hotList.length ? resolve(hotList) : reject("errer");
  32. });
  33. });
  34. }
  35. nodeSchedule.scheduleJob("30 * * * * *", async function () {
  36. try {
  37. const hotList = await getHotSearchList();
  38. await fs.writeFileSync(
  39. `${__dirname}/hotSearch.json`,
  40. JSON.stringify(hotList),
  41. "utf-8"
  42. );
  43. } catch (error) {
  44. console.error(error);
  45. }
  46. });

各种玩法

  • 以上代码可直接集成进现有的 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. Linux操作系统及调用接口

    Linux操作系统包含以下各子系统: 系统调用子系统:操作系统的功能调用同一入口: 进程管理子系统:对执行程序进行生命周期和资源管理: 内存管理子系统:对系统的内存进行管理.分配.回收.隔离: 文件子 ...

  2. Cacti监控服务

    Cacti监控服务 案例1:部署Cacti监控平台 案例2:构建Cacti监测系统 1 案例1:部署Cacti监控平台 1.1 问题 本案例要求部署一台Cacti监控主机,并安装相关监控组件,为进一步 ...

  3. Spring Framework之事务管理

    目录 问题 数据库事务 事务的定义 事务的目的 事务的特性 事务隔离级别 数据并发问题 事务隔离级别对数据并发问题的作用 快照读 Spring事务管理 事务管理接口 TransactionDefini ...

  4. 给定一个整数数组 nums 和一个目标值 target,求nums和为target的两个数的下表

    这个是来自力扣上的一道c++算法题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案 ...

  5. 家庭记账本app进度之复选框以及相应滚动条的应用

    这次主要是对于android中复选框的相应的操作.以及其中可能应用到的滚动条的相关应用.每一个复选框按钮都要有一个checkBox与之相对应. 推荐使用XML配置,基本语法如下:<CheckBo ...

  6. mybatis源码分析:启动过程

    mybatis在开发中作为一个ORM框架使用的比较多,所谓ORM指的是Object Relation Mapping,直译过来就是对象关系映射,这个映射指的是java中的对象和数据库中的记录的映射,也 ...

  7. Scala函数式编程(六) 懒加载与Stream

    前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...

  8. 10.1 io流--ASCII码表

    day2.8中提到 /* * +: * 做加法运算 * * 字符参与加法运算,其实是拿字符在计算机中存储的数据值来参与运算的 * 'A' 65(B 66...) * 'a' 97(b 98...) * ...

  9. Python——flask漏洞探究

    python的用途是真的多,就连网站也能做,这个有点像Java的Servlet flask基础 hello world 我们先从基础的开始,在网页上打出hello world,python代码如下: ...

  10. Python工业互联网监控项目实战3—websocket to UI

    本小节继续演示如何在Django项目中采用早期websocket技术原型来实现把OPC服务端数据实时推送到UI端,让监控页面在另一种技术方式下,实时显示现场设备的工艺数据变化情况.本例我们仍然采用比较 ...