浏览器页面返回的结果视图:
1. 获取数据:
这里我用到的数据源是:腾讯的疫情实时追踪
(此处获取json数据转载来源:https://blog.csdn.net/xufive/article/details/104093197)
- 深入分析,我们就得到了url地址、请求方法、参数、应答格式等信息。查询参数中,callback是回调函数名,我们可以尝试置空,_应该是以毫秒为单位的当前时间戳。有了这些信息,分分钟就可以抓到数据了。
代码:
import time, json, requests
url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_area_counts&callback=&_=%d'%int(time.time()*1000)
data = json.loads(requests.get(url=url).json()['data'])
print(data)
data显示的结果为[{'country': '中国', 'area': '湖北', 'city': '武汉', 'confirm': 2261, 'suspect': 0, 'dead': 129, 'heal': 51}...}]
2. 数据存储:
将数据存到mysql中,需要自己创建数据库,表,字段。
存下来的结果:
代码:
import time, json, requests
import pymysql
#获取数据源
url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_area_counts&callback=&_=%d'%int(time.time()*1000)
data = json.loads(requests.get(url=url).json()['data'])
for i in data: #遍历data数据 并且分配字段
country = i['country']
area = i['area']
city = i['city']
confirm = i['confirm']
suspect = i['suspect']
dead = i['dead']
heal = i['heal']
conn = pymysql.connect(host="localhost", user="root", password="123456", database="zufang", charset="utf8") #连接数据库
cursor = conn.cursor()
film_dict = {}
film = []
film_dict['country'] = country
film_dict['area'] = area
film_dict['city'] = city
film_dict['confirm']=(int)(confirm)
film_dict['suspect']=(int)(suspect)
film_dict['dead']=(int)(dead)
film_dict['heal']=(int)(heal)
film.append(film_dict)
#此处value前三个{}{}{}需要加上单引号(国家、地区、城市),因为数据源本身自带了‘’
sql = "insert into china(country,area,city,confirm,suspect,dead,heal) value('{}','{}','{}',{},{},{},{})".format(film_dict['country'],film_dict['area'],film_dict['city'],film_dict['confirm'],film_dict['suspect'],film_dict['dead'],film_dict['heal'])
cursor.execute(sql)
conn.commit()
print(sql) #打印出执行sql的结果
cursor.close()
conn.close()
3. 数据可视化
这里我用到的是Flask框架结合Echarts进行可视化操作
flask controller(控制器)后端代码如下:
from blog2 import app
from flask import render_template
from blog2.model.car import China
from sqlalchemy import func
import json
@app.route('/china',methods=['GET'])
def index():
#使用sqlalchemy语句来把同个地区进行分组,用sum来讲confirm也就是这个地区的确诊病例进行整合并用label重命名字段为'China_confirm_sum'
#说明一下,这里重命名,后面写前端中国地图和饼图用得到
china=China.query.with_entities(China.area,func.sum(China.confirm).label('China_confirm_sum')).group_by(China.area).all()
#创建两个列表
#说明一下,这里是柱形图跟折线图用到
a = []
b = []
for i in china:
a.append(i[0])
b.append(i[1])
#传递到前端 这里a的数据是文字,需要转成编码格式, 所以需要 a=json.dumps(a) 进行转换
return render_template('index.html',china=china,a=json.dumps(a),b=b)
前端代码:
这里我前端代码很乱,建议创建js文件把每个视图的代码写到每个js里再引用
说明一下:前端 script type=“text/javascript” 代码中用到自己定义ck再引用数据传到视图所需的data
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>map</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script src="static/china.js"></script>
<style>
*{margin:0;padding:0}
html,body{
width:100%;
height:100%;
}
/*默认长宽比0.75*/
</style>
</head>
<body>
<div id="main" style="width: 930px;height: 470px;float:left;border: 1px solid #ddd"></div>
<div id="main1" style="width: 930px;height: 470px;float:left;border: 1px solid #ddd"></div>
<div id="main2" style="width: 930px;height: 470px;float:left;border: 1px solid #ddd"></div>
<div id="main3" style="width: 930px;height: 470px;float:left;border: 1px solid #ddd"></div>
<script type="text/javascript">
var ck=[{% for i in china %}
{name:'{{i.area | safe}}',value:{{i.China_confirm_sum}}},
{% endfor %}
]
//循环后端传过来的china函数
//var ck=[{% for i in china %}
//name:{{传递地区的数据area | 将数据进行过滤 渲染时不转义},value:{{这里要传的数据就是我刚才要你重命名字段的数据}}}
//{name:'{{i.area | safe}}',value:{{i.China_confirm_sum}}},
//{% endfor %}]
//具体说明:
//i.area 是传递地区数据作为name
//safe 是将数据进行过滤 渲染时不转义
//i.China_confirm_sum 是传递确诊病例的数据作为value
//中国地图!!!
var myChart = echarts.init(document.getElementById('main'));
option = {
title:{
text:'新型冠状病毒肺炎全国分布图',
subtext:'2020/1/30',
left:'center'
},
tooltip: {
formatter:function(params,ticket, callback){
return params.seriesName+'<br />'+params.name+':'+params.value
}//数据格式化
},
visualMap: {
min: 0,
max: 1500,
left: 'left',
top: 'bottom',
text: ['高','低'],//取值范围的文字
inRange: {
color: ['#e0ffff', 'red']//取值范围的颜色
},
show:true//图注
},
geo: {
map: 'china',
roam: false,//不开启缩放和平移
zoom:1.23,//视角缩放比例
label: {
normal: {
show: true,
fontSize:'10',
color: 'rgba(0,0,0,0.7)'
}
},
itemStyle: {
normal:{
borderColor: 'rgba(0, 0, 0, 0.2)'
},
emphasis:{
areaColor: '#F3B329',//鼠标选择区域颜色
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
},
series : [
{
name: '确诊病例',
type: 'map',
geoIndex: 0,
data:ck //上面定义好的ck的数据现在要在这里用到
}
]
};
myChart.setOption(option);
//饼图!!!
var myChart = echarts.init(document.getElementById('main1'))
option = {
title:{
text:'新型冠状病毒肺炎饼图',
subtext:'2020/1/30',
left:'center'
},
tooltip:{
trigger:'item',
formatter:'{a}<br/>{b}:{c}({d}%)'
},
legend:{
orient:'vertical',
left:'left'
},
series:[{
center: ['50%', '60%'],
name:'确诊病例',
type:'pie',
data:ck //上面定义好的ck的数据现在要在这里用到
}]
}
myChart.setOption(option)
//柱形图!!!
var myChart = echarts.init(document.getElementById('main2'))
option = {
color: ['#3398DB'], //设置图形颜色
title: {
text: '新型冠状病毒肺炎柱形图',
subtext: '2020/1/30',
left: 'center' //标题 副标题居中对齐
},
tooltip: { //设置提示工具
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: [
{
axisLabel:{
interval:0, //字体间距
rotate:45 //字体倾斜
},
type: 'category',
data: {{a | safe}}, //jinja2格式传递数据
axisTick: {
alignWithLabel: true //底线对齐柱形
}
}
],
yAxis: [
{
type: 'value'
}
],
legend:{ //设置提示说明
data:['确诊病例'],
left:'left'
},
series: [
{
name: '确诊病例',
type: 'bar',
barWidth: '80%', //柱形间距大小设置
data: {{b}} //jinja2格式传递数据
}
]
};
myChart.setOption(option)
//折线图!!!
var myChart = echarts.init(document.getElementById('main3'))
option = {
color: ['#3398DB'],
title: {
text: '新型冠状病毒肺炎折线图',
subtext: '2020/1/30',
left: 'center' //标题 副标题居中对齐
},
xAxis: {
axisLabel:{
interval:0, //字体间距
rotate:45 //字体倾斜
},
data: {{a | safe}} //jinja2格式传递数据
},
yAxis: {
type: 'value'
},
tooltip: { //设置提示工具
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'line' // 默认为直线,可选为:'line' | 'shadow'
}
},
legend:{ //设置提示说明
data:['确诊病例'],
left:'left'
},
series: [{
name:'确诊病例',
data: {{b}}, //jinja2格式传递数据
type: 'line'
}]
};
myChart.setOption(option)
</script>
</body>
</html>