eCharts及爬虫制作疫情地图

疫情地图实现

项目简介

模仿丁香园实时疫情图,使用原生js结合Echarts,使用node的框架express爬取网站数据,实现疫情效果展示效果

效果展示

你在看到这篇文章时,可能接口已经失效,可以尽量去阅读代码而非效果。不过失效这一天,想必疫情已经结束,也是好事!

项目应用技术

  • 使用ECharts实现中国地图及对应样式

  • 使用node中的superagent及cheerio插件爬取网上数据

  • 使用fetch实现ajax请求并解决其cors跨域问题

爬取网站

https://ncov.dxy.cn/ncovh5/view/pneumonia

数据部分

我们将使用一个简单的爬虫来爬取对应网站上的数据,整个过程分为以下部分

  • 向对应网站发送请求,获得返回的数据并进行处理(返回的是什么格式,找到需要的数据)

  • 数据进行存放

  • 建立服务器,将数据返回

  • 读取文件,获得数据

文件的结构为 server文件夹两个文件分别进行数据的爬取及建立服务器,在index.html文件的script标签中写入请求及eCharts操作(有点偷懒,哈哈)

一.准备工作

我们首先需要下载两个必要的包,再引入自带的两个包,共计四个包。

  • superagent 客户端请求模块

    • 下载:node install superagent --save下载

    • 本质上是promise,会返回一个promise,因此我们可以调用.then方法。

  • cheerio 对dom进行操作

    • 下载:node install cheerio --save

    • 本质上是jQuery的实现,能够操作dom元素,但十分轻量化

  • fs node自带模块,操作文件

  • path node自带模块,操作路径

二.发送请求并处理数据

server端文件处理

  • 发送请求
superagent.get(url).then(data=>{
    
}).catch(err=>{
    throw err;
})

由于superagent本质上是promise,所以我们在then方法中处理数据

  • 处理数据

    我们在返回的data中可以发现需要的数据在data.text中

    cheerio.load可以可以获得对应的html代码

const $ = cheerio.load(data.text);
var result = $('#getListByCountryTypeService1').html()
  • 在获得的html代码中我们可以找到我们需要的数据在id名为getListByCountryTypeService1中,接下来使用.html()方法获取到dom元素的内容

  • 打印result我们可以看到,数据内容在window的一个对象上,由于node环境中没有window,使用正则匹配,替换window

     var dataObj = {};
     eval(result.replace(/window/g,'dataObj'))
    

至此,需要的数据全部存放在dataObj中

三.存放数据

  • 将数据存放在一个json文件中,方便存储及读取
 fs.writeFile(path.join(__dirname,'./data.json'),JSON.stringify(dataObj),(err)=>{
        if(err){
            console.log(err);
            return;
        }
        console.log('文件写入成功');
        
   })

四.建立服务器及接口

建立服务器分为以下三个步骤:

  • 建立服务器
const express = require('express');
const server = express();

server.listen(3000,()=>{
  console.log('running');
})
  • 读取文件内容,作为接口返回
server.get('/api/data',(req, res)=>{
    
    fs.readFile(path.join(__dirname , './data.json'),'utf-8',(err,result)=>{
        if(err){
            console.log(err);
            return
        }
        res.send(result)
    })
})
  • 解决cors跨域

    我们使用fetch发送请求,但无论cors还是XMLHttpReqest都遵循同源策略,只有想同源服务获取资源时才能成功,我们需要设置正确的cors头部,有两种方法

    一:

server.all('*', function(req, res, next) {  
    res.header("Access-Control-Allow-Origin", "*");  
    res.header("Access-Control-Allow-Headers", "X-Requested-With");  
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  
    res.header("X-Powered-By",' 3.2.1')  
    res.header("Content-Type", "application/json;charset=utf-8");  
    next();  
});

二:

var cors = require('cors');
app.use(cors({
    origin:['http://localhost:3000'],
    methods:['GET','POST'],
    alloweHeaders:['Conten-Type', 'Authorization']
}));
  • cors需要下载 npm install cors --save

五.请求数据并获得数据

数据端文件处理

  • 请求数据
    fetch(url).then(result=>
                  result.json()                       
          ).then((result)=>{
                //操作数据  
       });
              
*   使用fetch请求数据,与superagent相同,fetch同样使用了promise,我们使用then方法处理数据

*   fetch请求返回是数据是数据流,我们将其转换为json格式

*   第一层箭头函数没有括号,没有括号的箭头函数默认有返回值,有括号的则没有返回值
  • 数据处理
var dataArr = [];  
const data = result.getListByCountryTypeService1;        
            data.forEach(element => {
                dataArr.push({
                    name:element.provinceShortName,
                    value:element.confirmedCount - element.curedCount,//确诊-治愈=现存确诊人数
                    deadCount:element.deadCount,
                    curedCount:element.curedCount
                })
            });
  • 打印result我们可以发现我们需要的数据在属性getListByCountryTypeService1中

  • 定义一个对象数组,方便对echsrts提供参数。我们遍历数据的每一项,提取出必要的数据统一到一个对象中。

以上是数据处理部分的代码,注意接下来对echarts的操作仍在数据操作层进行,即第二个then方法中

界面部分

https://echarts.apache.org 推荐前往官网主页学习使用教程

使用echart需要以下几个步骤

  • 下载eCharts并引入,方法见官网教程。

  • 创建eCharts实例

  • 操作eCharts实例

引入

  • echarts.min.js:引入此文件,创建echart实例

  • china.js:引入此文件,引入中国地图

  • tips:在引入echarts,in.js时便已获得echarts变量(注意,不是echarts实例)

创建实例

  • 构建一个容器,即一个div

引入了echarts.min.js便获得了echats变量,调用变量上的方法创建实例

const div = document.getElementsByClassName('demo')[0];
const myChart = echarts.init(div);

myChart就是echarts实例

操作eCharts实例

myChart.setOption({
    //操作
})

在setOption中传入一个参数对象,对eCharts进行设置

在开始之前,首先我们需要明确需求,地图都要什么效果?

  • 标题及简介

  • 各省份划分,名称显示

  • 点击出现各省确诊,治愈,死亡数量

  • 根据人数对应不同的地图颜色

一.标题及简介

  title:{
                text:'nCov-2019全国实时疫情数据分布图',//主标题
                subtext:'战斗进行时---他们还在努力',   //副标题            
                left:'center'                      //位置控制
            },

各省份划分,名称显示

 series:[{
                type:'map', //eCharts类型
                map:'china',    //地图类型
                label:{
                    show:true
                },
                //向echart传入的数据
                data:dataArr
            }
        ]
  • 地图中默认不显示省市名称,我们在label中进行改变

点击出现各省确诊,治愈,死亡数量

  tooltip:{
                //信息出现的方式
                triggerOn:'click',
                formatter:function(param){  
          //南海诸岛需要处理,那个地方没有数据会报错              //判断是否有值没有则设置为0
                    return `地区:${param.name }<br/>现存确诊:${param?.value || 0}<br/>治愈:${param.data?.curedCount || 0}<br/>死亡:${param.data?.deadCount || 0}`
                }
            },
  • 在series.data属性中传入过data,则formatter中的param会自动将其作为参数

  • 返回值需要对南海诸岛进行处理,因为南海诸岛作为省市名出现,但接口中不存在其数据

根据人数对应不同的地图颜色

 visualMap:[
                {
                    type:'piecewise',   //颜色形式
                    pieces:[    //设置颜色
                        {gt:9999},
                        {gt:999,lte:9999},
                        {gt:99,lte:999},
                        {gt:9,lte:99},
                        {gt:0,lte:9},
                        {lte:0}
                    ],
                    inRange:{//具体颜色值
                        color:['rgb(255,255,255)','rgb(253,235,207)','rgb(229,90,78)','rgb(203,42,47)','rgb(129,28,36)','rgb(79,7,13)']
                    }
                } ]
  • gt代表>

  • lte代表<=

通过以上代码就可以完成全部echarts的部分了。由于本人的代码能力问题,上文请求获取的数据存在作用域问题,在外部访问会有问题,我就将eCharts部分放入了then方法中。

以上就是疫情地图的全部代码,如果需要完整代码可以访问github:https://github.com/zby1218/jsDemo-practice/tree/master/2020%E7%96%AB%E6%83%85%E5%9C%B0%E5%9B%BE

谢谢你的观看!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350