从0开始搭建一个疫情地图小程序——数据爬虫篇

前言

其实这个小程序一个月前就已经做好了,但是当时忙着实习和毕设还有一些乱七八糟的事情,所以拖到现在才来做总结。

源代码

数据来源

在春节的时候,疫情地图一开始用的比较多的是丁香医生的疫情地图,我们可以利用爬虫把这些数据获取下来。
在这里插入图片描述

分析请求

我们打开F12,查看页面的请求
在这里插入图片描述

中国地图svg数据

在这里插入图片描述
这个是地图绘制的SVG数据,这个我们后面会使用到。

一些制作好的图片

我们发现一些数据图片并不是动态生成的,而是直接放回数据。
在这里插入图片描述
除此之外都是一些图片和JS文件了,这些页面的数据好像都是服务器渲染的。

从JS文件请求入手

在这里插入图片描述
我们通过搜索http直接去查看页面的请求地址,然后再使用postman去请求看看返回的数据是什么
比如:
1. svg格式在这里插入图片描述
2. 一些连接地址在这里插入图片描述
3. 在这里插入图片描述结合前面的地图数据,这个应该是地图SVG的JSON文件

发现并没有疑似请求数据的接口。就在我不知道怎么进行下去的时候,发现了URL网址有线索。

从url网址发现爬虫接口

由于我是从小程序公众号点击复制到PC端上打开的,所以发现url网址携带了一些参数。
在这里插入图片描述
https://ncov.dxy.cn/ncovh5/view/pneumonia_peopleapp?from=timeline&isappinstalled=0&scene=126&clicktime=1580901335
我们都知道url网址请求,其实是一个get请求,携带的参数有一个clicktime点击时间的描述,后面接的应该是Date.parse()返回的毫秒数。
所以我就修改这个时间,在postman上去请求发现了一个突破口。
在这里插入图片描述
返回的是页面信息,而在<script>标签里发现了携带了每一个地区的疫情数据。
在这里插入图片描述
我们就可以通过修改clicktime去获取最新的疫情数据。
从这里也可以发现,丁香医生这个有可能使用了服务器渲染(我也不是很确定)。

编写爬虫

既然处理的数据是html文件,就可以使用cheerio进行处理数据,使用superagent进行请求。
为了方便预览和调试,我使用了express去搭建一个简单的服务器,把爬下来的结果渲染到页面上去查看。

搭建服务器

const express = require("express");
const app = express();
let server = app.listen(3000, function() {
  let host = server.address().address;
  let port = server.address().port;
  console.log("Your App is running at http://%s:%s", host, port);
});
app.get("/", async (req, res) => {
  let result = await httpGet(); // 爬虫获取数据
  res.send(handleDate(result)); // 展示到页面
});

这里主要是httpGet这个函数,去爬取网页的数据。
在使用handleDate去处理数据。

const cheerio = require("cheerio");// 处理页面的Node元素
const superagent = require("superagent");// 请求
function httpGet() {
  return new Promise((res, rej) => {
    superagent
      .get(
        `https://ncov.dxy.cn/ncovh5/view/pneumonia_peopleapp?from=timeline&isappinstalled=0&scene=126&clicktime=${Date.parse(
          new Date()
        )}`// 请求网页数据
      )
      .end((_err, _res) => {
        if (_err) {
          // 如果访问失败或者出错,会这行这里
          console.log(`爬取出错 - ${_err}`);
          rej(_err);
        } else {
          return res(_res);
        }
      });
  });
}

未处理的数据

在这里插入图片描述
很明显是一个JSON格式的对象,这个对象中的text属性保存着这个页面的html格式,我们输出看看。
在这里插入图片描述
浏览器会自动解析html文件,所以这是一个格式正确的html文件。
并且发现script标签保存了疫情的详细数据
在这里插入图片描述

使用cheerio解析html

script标签也是node元素,所以可以使用cheerio去解析获取里面的数据。
每一个script标签都有一个id属性,我们可以通过这个去定位获取对应的数据
在这里插入图片描述
发现id为getAreaStat是各省各市的数据,我们来获取看看。

function handleDate(res) {
  res = cheerio("script", res.text);
  let reslut = "";//保存最后的结果
  for (let [key, value] of Object.entries(res)) {
      // console.log( typeof value.children, isNaN(key))
      if (isData(key, value) && /getAreaStat/g.test(value.children[0].data)) {
        reslut = value.children[0].data.slice(26, -11);//是数据变成json格式
      }
   }
   return result
}

我们看看最后的结果是什么
在这里插入图片描述
这个是JSON格式的对象,我们只有按照我们想要的格式去处理这些数据即可。
除此之外还有很多数据可以去获取,比如国外的数据,全国各省的数据,每天的数据变化等,只需要修改检测的script的id值就可以。

将这些文件保存到我们需要的格式并且保存为js文件

nodejs本身就有一个fs库操作本地文件,所以我们直接使用就可以。
剩下工作就是调用API了。

保存文件
/**
 * @param {请求的数据} object reslut
 * @param {文件名} string filename
 */
let defaultData = require("./defaultData");
function writeDate(reslut, filename) {
  let date = new Date();
  let r = defaultData;// 我们需要保存的格式
  // 文件名
  let str = `./home/${filename} ${date.getMonth() +
    1}-${date.getDate()} ${date.getHours()} ${date.getMinutes()} ${date.getMilliseconds()}.json`;
  for (let item of reslut) {
  // 将每一个省份保存到对应的属性下
    let name = getCityName(item.provinceShortName);
    if (name) {
      r.data[0][name] = JSON.stringify(item);
    }
  }
  // 设置数据库id 和创建时间
  r.data[0]["id"] = new objecId().toString();
  r.data[0]["created_at"] = Date.parse(date);
  r.data[0]["updated_at"] = Date.parse(date);
  // 写入文件
  fs.writeFileSync(str, JSON.stringify(r));
}

在这里插入图片描述
这个就是我们需要的文件格式。

删除文件

由于我们每天需要最新的文件格式,所以我们每次更新需要把之前的文件删除,我们同样使用fsAPI即可。

// 清空文件夹
// path 是文件夹路径
function delDir(path){
  let files = [];
  if(fs.existsSync(path)){
      files = fs.readdirSync(path);
      files.forEach((file, index) => {
          let curPath = path + "/" + file;
          if(fs.statSync(curPath).isDirectory()){
              delDir(curPath); //递归删除文件夹
          } else {
              fs.unlinkSync(curPath); //删除文件
          }
      });
  }
}
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值