目录
在这篇文章当中呢,这是一份价值上千的python数据分析实战,我们获取到了我们所需要的数据,并在命令行页面进行了简单的数据分析,那么今天呢,突发奇想能不能将数据应用在网页上并进行展示,这就会使数据更加可视化,而且我们还可以拿来生活中进行实际应用,毕竟数据就是为人服务的。
过程
那该如何将获取到的数据与实际接轨应用呢?由于上篇文章我们获取到的数据是美团上火锅店的分析,那我们可以将每个火锅店在地图上进行筛选展示,有了想法那么实践起来就比较简单了。首先这样接着这样然后这样最后这样,不就完成了吗?所以只要软件的需求清晰,一切做起来都事半功倍了。至于能不能实现那是技术层面的问题了。ヽミ ´∀`ミノ<
好了好了,不皮了,下面进行整体项目分析。
首先呢
我获取到的数据有火锅店的地址,那能不能根据地址形成一个列表然后传入一个网页进行批量展示呢?由于没有在这方面玩过,尝试在网上搜了下,发现百度地图API好像可以应用, 有了方向那又更好办了。不用说,调用人家接口肯定需要先去注册一波,获取密钥,唉,面向接口编程还真没话可说。
接着呢
密钥有了,数据有了,该怎么展示呢?这时候我们就要去看官方文档了,不过像这样的大东西,Demo肯定一堆,不出所料,看的眼花缭乱,这里我选择的是多点信息窗口显示,也就是下图这样。
为啥选择这个呢,因为这个跟我们所要实现的需求一模一样 ,地点列表,店铺信息展示!而我们只需要一点点点javascript知识就能完美应用,不过美中不足的是该Deom不能进行地图缩放,浏览了几个Demo后我发现只要调用它那里的几个函数就能实现,所以成了,我们将前端改改,加几个筛选输入框,最终网页代码如下。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
<style type="text/css">
body, html {width: 100%;height: 100%;margin:0;font-family:"微软雅黑";}
#allmap{width:100%;height:100%;}
</style>
<script src="//libs.baidu.com/jquery/1.9.0/jquery.js"></script>
<script type="text/javascript"
src="http://api.map.baidu.com/api?v=2.0&ak=你的密钥"></script>
<title>广州火锅分布筛选</title>
</head>
<body>
<div style="width:100%;text-align:center">
<form action="/saixuan" method="post" >
<p>筛选:
<input size="36" name="pf" type="text" placeholder="评分大于(默认4分 最高5分,最低1分)">
<input size="33" name="pl" type="text" placeholder="评论大于(默认1000 均值100-5000)">
<input size="30" name="xf" type="text" placeholder="消费小于(默认50 均值40-150)">
<button type="subbmit">提交(请确保输入框内为数字类型)</button>
</p>
</form>
</div>
<div id="allmap">
</div>
</body>
</html>
<script type="text/javascript">
// 百度地图API功能
map = new BMap.Map("allmap");
map.centerAndZoom(new BMap.Point(113.2737244489343,23.12851066584807), 11.5);//默认中心地址 15是缩放级别
map.enableScrollWheelZoom(); //启用滚轮放大缩小,默认禁用
map.enableContinuousZoom(); //启用地图惯性拖拽,默认禁用
var data_info = eval('{{data_new_map|safe }}');
<!-- console.log(data_info);-->
var opts = {
width : 250, // 信息窗口宽度
height: 150, // 信息窗口高度
title : "商家信息窗口" , // 信息窗口标题
enableMessage:true//设置允许信息窗发送短息
};
for(var i=0;i<data_info.length;i++){
var marker = new BMap.Marker(new BMap.Point(data_info[i][0],data_info[i][1])); // 创建标注
var content = data_info[i][2];
map.addOverlay(marker); // 将标注添加到地图中
addClickHandler(content,marker);
}
function addClickHandler(content,marker){
marker.addEventListener("click",function(e){
openInfo(content,e)}
);
}
function openInfo(content,e){
var p = e.target;
var point = new BMap.Point(p.getPosition().lng, p.getPosition().lat);
var infoWindow = new BMap.InfoWindow(content,opts); // 创建信息窗口对象
map.openInfoWindow(infoWindow,point); //开启信息窗口
}
</script>
然后呢
前端有了,就来后台玩玩了,网站框架不用说,肯定是flask大法好啊,可塑性高。但是问题又来了,前端js上使用经纬度列表展示的,而我这里是中文地址,没办法,又只能将地址转为经纬度了。所以百度的地址解码派上用场了,代码如下。
def getlnglat(address):
url = 'http://api.map.baidu.com/geocoding/v3/'
params = {
'city': '广州市',
'output': 'json',
'ak': '你的密钥',
'address': address
}
req = requests.get(url, params=params)
result = req.text
temp = json.loads(result)
time.sleep(0.03)
lng = float(temp['result']['location']['lng'])
lat = float(temp['result']['location']['lat'])
return lng,lat
a=meituan_showAll()
# print(getlnglat('嘉禾望岗')[0])
# (1, '164631746', 'https://gz.meituan.com/meishi/164631746', '十七门重庆老火锅(钟村店)', '5', '番禺区钟村街钟村市场二楼', '1874', '81')
for i in a:
address=i[5]
#由于地址长度限制,我们进行切割
if len(address)>20:
address=address[0:21]
#地址解码并返回元组(经度,纬度)
a=getlnglat(address)
meituans_insertData(i[1],i[2],i[3],i[4],i[5],i[6],i[7],a[0],a[1])
time.sleep(0.02)
print('%s ok'%i[0])
print('ok')
我事先新建一个新的数据库,并在前面的数据库格式中添加经度纬度两列,然后前面数据分析所用的数据库复制到这个新的数据库当中,并在复制的同时将经度纬度通过地址解码返回的结果一同写入数据库,为啥要这样呢?因为我发现打开网页的同时去调用地址解码并返回数据量大时会直接让用户等到两眼翻白,而数据在本地数据库时,就算全部商店进行展示也只不过1秒左右。
最后呢
数据有了,就要将数据格式化成js所需要的列表了。
def chiose(pf,pl,xf):
"""
(4,1000,100)
评分大于 4,评论数大于 1000,消费小于 100
:param pf: 店铺评分
:param pl: 店铺评论数
:param xf: 平均消费
:return: 符合要求的店铺列表嵌套字典
"""
allinfo = meituan_showAll()
first = []
for i in allinfo:
info_dict = {}
if float(i[4]) >= pf and float(i[6]) >= pl and float(i[7]) <= xf:
info_dict['商家名字'] = i[3]
info_dict['商家地址'] = i[5]
info_dict['商家评分'] = i[4]
info_dict['商家评论数'] = i[6]
info_dict['平均个人消费'] = i[7]
info_dict['lng'] = i[8]
info_dict['lat'] = i[9]
first.append(info_dict)
# print(len(first))
return first
def getlnglat(pf,pl,xf):
data_info = []
for i in chiose(pf,pl,xf):
strs = "商家名字:%s<br/>商家地址:%s<br/>评分:%s<br/>评论数:%s<br/>平均消费:%s" % (
i['商家名字'], i['商家地址'], i['商家评分'], i['商家评论数'], i['平均个人消费'])
a = []
a.append(i['lng'])
a.append(i['lat'])
a.append(strs)
data_info.append(a)
return data_info
我们将数据库查询到的数据进行清洗,并按筛选条件形成一个字典,然后遍历字典转化格式成前端js所需要的列表。然后将列表传参到js形成前后端交互,我们先默认一个数据,然后筛选的时候将表单提取再进行重定向到筛选条件下的页面,为了防止输入框错误,我们进行异常处理,直接传回默认数据,最后flask代码如下。
from flask import *
from get_meituan_meishi import *
import json
# 首页
@app.route('/')
def index():
pf=4
pl=1000
xf=50
data_new_map = getlnglat(pf,pl,xf)
return render_template('baidu_map.html', data_new_map=json.dumps(data_new_map))
@app.route("/saixuan",methods=['POST']) #请求方式为post
def saixuan():
try:
pf = float(request.form['pf'])
pl = float(request.form['pl'])
xf = float(request.form['xf'])
data_new_map = getlnglat(pf, pl, xf)
return render_template('baidu_map.html', data_new_map=json.dumps(data_new_map))
except:
data_new_map = getlnglat(4, 1000, 50)
return render_template('baidu_map.html', data_new_map=json.dumps(data_new_map))
if __name__ == '__main__':
app.run(debug=True)
成果
默认筛选数据
进行数据筛选 参数:5,1000,80
后记
其实还可添加更多功能,比如浏览器定位自己当前位置,选择店铺进行两点导航, 或者调用百度地图导航,这样就比较实用了,我觉得美团还真可以添加这个功能,方便用户筛选并查看离自己比较近的店铺,不过这只是一个菜鸟的瞎想,溜了溜了。
已经将该网页导入自己的博客,毕竟有时候还真可以用用,有兴趣的同学可以去我网站留言,我会将该数据弄成一个接口,供大家学习使用。
对了,期间我遇到一个问题就是flask与js的传参问题,在js处进行以下处理就可以了,按flask与网页传参差不多,都是{{参数名}}。
var data_info = eval('{{data_new_map|safe }}');