一、简介
如题,通过深圳市政府数据开放平台查询到的疫情分布点地址数据,批量请求高德API,将查询到坐标显示到网页地图上,先上效果(挺愕然的,本主自己的住处附近就有好几个点),如下:
二、实现工具:
(1)开发语言:python、javascript
(2)开发环境:python3.6
(3)开发工具:pcharm
三、实现方法:
1.阅读相关API(重点)
此处放链接,方便查阅:
(1)深圳市政府数据开放平台确诊患者曾逗留过的场所名单数据接口API:
<调用API需要注册、新建应用获取appKey,参考API调用指南↓>
https://opendata.sz.gov.cn/data/api/toApiDetails/29200_01503669
(2)高德地图Web服务API:
<调用需要注册、新建应用后获取apikey>
https://lbs.amap.com/api/webservice/summary/
2.使用django框架编写脚本请求上面的API,将地址和坐标返回前端
3.前端JS处理坐标数据,调用高德地图回显
四、实现步骤
1、编写python脚本调用API
(1)调用深圳市政府数据开放平台API
通过浏览器调试可以看到请求头,请求参数、请求地址、返回数据
python模拟请求代码实现(可以不加headers):
# 查询数据量
rows = '175'
req_url = 'https://opendata.sz.gov.cn/data/catalog/selectDataCatalogByResId'
data = {'resId': '29200/01503669'}
res_data = requests.get(url=req_url, params=data)
res_data = json.loads(res_data.text)
rows = res_data['recordTotal']
# API地址
url = "https://opendata.sz.gov.cn/api/29200_01503669/1/service.xhtml"
page = '1'
params = {"page": page, "rows": rows, "appKey": "50798b9a560a489e9f111ffa47b9ec29"}
res = requests.get(url=url, params=params)
res = json.loads(res.text)
total = res["total"]
print("总共:", res["total"])
pos_list = []
for x in res["data"]:
# print(x["xzqh"],x["xqmc"],x["fbsj"])
pos_list.append(x["xzqh"]+x["xqmc"])
(2)高德地图地理编码API
这里要做一些处理,该API最多支持10个地址进行批量查询,所有要根据地址数量计算次数,每次10个地址
python根据地址数批量请求地理编码API代码实现:
apiurl = 'https://restapi.amap.com/v3/geocode/geo'
apikey = '08892c38dddc0e2e68cb7ac1de2b670b'
# 计算要查询的次数
time = 0
remain = total % 10
if remain == 0:
time = int(total/10)
else:
time = int(total/10) + 1
index = 0
print('查询次数',time)
location = []
while index < time:
req_data = ""
range = None
# if len(pos_list) < 10: # 查询长度小于10
# range = pos_list[index: len(pos_list) -1]
if index == time -1: # 最后一次查询
range = pos_list[index*10: index*10 + remain]
else: # 第index次查询(index不是最后一次)
range = pos_list[index*10: index*10 + 10]
for pos in range:
req_data = req_data + '|' + pos
# print(req_data)
data = {'address': req_data, 'output': 'json', 'key': apikey, 'batch': 'true'}
req = requests.get(url=apiurl, params=data)
pos_res = json.loads(req.text)
for x in pos_res["geocodes"]:
location.append(x["location"].encode('utf8'))
index += 1
(3)把脚本搬到django框架,方便前端页面请求,操作方法:
新建工程: python django-admin startproject shenzhen
创建应用: python manage.py startapp ncovMap
生成的目录结构:
修改配置文件settings.py,在关键位置添加划线部分,如下:
urls.py添加相关代码如下:
from django.contrib import admin
from django.urls import path
from ncovMap import views
urlpatterns = [
path('admin/', admin.site.urls),
path('ncovmap/', views.show_map),
]
(4)添加网页文件
从高德地图JS API示例中 直接扣皮一个下来↓
https://lbs.amap.com/api/javascript-api/example/marker/adaptive-show-multiple-markers放到如下目录(没有目录就新建一个templates):
配置文件settings.py里引入:
顺便在配置文件末尾加上:
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
OK,基本配置到这就差不多了,后面修改views.py添加请求内容,再扣皮下来的网页JS部分代码(重点):
views.py(此处的show_map 对应上面urls.py配置的函数):
from django.shortcuts import render
from .shenzhen import *
def show_map(request):
print('正在处理请求')
total,pos_list = get_location()
points = get_map_point(total, pos_list)
data = {'point': points, 'pos':pos_list}
return render(request, 'map.html', data)
修改map.html的JS代码如下:
<script type="text/javascript">
var data = "";
var pos_data = "";
var points = [];
var pos_list = [];
window.onload=function(){
console.log('正在请求数据。。。');
data = '{{ point }}';
pos_data = '{{ pos }}';
//console.log(data);
var str = data.split("'");
for(var index=0; index<str.length; index++){
if(str[index].trim()!="," && str[index]!="[b" && str[index]!="]" && str[index].trim()!=", b")
points.push(str[index]);
}
var str = pos_data.split("'");
for(var index=0; index<str.length; index++){
if(str[index].trim()!="," && str[index]!="[b" && str[index]!="[" && str[index]!="]" && str[index].trim()!=", b")
pos_list.push(str[index]);
}
console.log("请求完毕,获取的数据量为:"+points.length);
for(var i=0; i<points.length; i++){
console.log(i,points[i]);
}
console.log(pos_list);
var map = new AMap.Map('container', {
resizeEnable: true,
center: [114.215567,22.684234],
zoom: 13,
viewMode: '3D',
pitch: 60,
});
map.clearMap(); // 清除地图覆盖物
var markers = [];
var index = 1;
points.forEach(function(point) {
var pos = [];
if(index == 1){
var origin = {
icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-1.png',
position:[114.215567,22.684234] //这里可以替换成高德地理编码API查询到的自己的坐标
};
markers.push(origin);
index = 0;
}
pos.push(point.split(",")[0]);
pos.push(point.split(",")[1]);
var obj = {'position': pos };
markers.push(obj);
});
var infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
// 添加一些分布不均的点到地图上,地图上添加三个点标记,作为参照
var count = 0;
var pos_index = 0;
// for(var i=0;i<markers.length;i++){
// console.log(markers[i]);
// }
markers.forEach(function(marker) {
if(count==0){
// var markerContent = '' +
// '<div class="custom-content-marker">' +
// ' <img src="//a.amap.com/jsapi_demos/static/demo-center/icons/dir-via-marker.png">' +
// '</div>';
mark = new AMap.Marker({
map: map,
icon: '{% static 'img/dir-via-marker.png' %}',
// content: markerContent,
position: [marker.position[0], marker.position[1]],
// 以 icon 的 [center bottom] 为原点
offset: new AMap.Pixel(-13, -30)
});
// 设置label标签
// label默认蓝框白底左上角显示,样式className为:amap-marker-label
mark.setLabel({
offset: new AMap.Pixel(20, 20), //设置文本标注偏移量
content: "<div class='info'>我的狗窝(2020)</div>", //设置文本标注内容
direction: 'right' //设置文本标注方位
});
// 设置点标记的动画效果,此处为弹跳效果
mark.setAnimation('AMAP_ANIMATION_BOUNCE');
count =1;
}else{ //第一个点不是,后面都是else
mark =new AMap.Marker({
map: map,
icon: '{% static 'img/red2.png' %}',
position: [marker.position[0], marker.position[1]],
offset: new AMap.Pixel(-13, -30)
});
mark.content = '<h3>'+pos_list[pos_index]+'</h3>';
mark.content += '<div>经度:'+marker.position[0]+'</div>';
mark.content += '<div>纬度:'+marker.position[1]+'</div>';
mark.on('mouseover', infoOpen);
//注释后打开地图时默认关闭信息窗体
//marker.emit('mouseover', {target: marker});
mark.on('mouseout', infoClose);
mark.on('click', newMAp);
pos_index += 1;
}
});
//鼠标点击事件,设置地图中心点及放大显示级别
function newMAp(e) {
//map.setCenter(e.target.getPosition());
map.setZoomAndCenter(15, e.target.getPosition());
var infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
infoWindow.setContent(e.target.content);
infoWindow.open(map, e.target.getPosition());
}
function infoClose(e) {
infoWindow.close(map, e.target.getPosition());
}
function infoOpen(e) {
infoWindow.setContent(e.target.content);
infoWindow.open(map, e.target.getPosition());
}
var center = map.getCenter();
var centerText = '当前中心点坐标:' + center.getLng() + ',' + center.getLat();
document.getElementById('centerCoord').innerHTML = centerText;
document.getElementById('tips').innerHTML = '成功添加'+points.length+'个点标记';
// 添加事件监听, 使地图自适应显示到合适的范围
AMap.event.addDomListener(document.getElementById('setFitView'), 'click', function() {
var newCenter = map.setFitView();
document.getElementById('centerCoord').innerHTML = '当前中心点坐标:' + newCenter.getCenter();
document.getElementById('tips').innerHTML = '通过setFitView,地图自适应显示到合适的范围内,点标记已全部显示在视野中!';
});
}
</script>
最后运行: python manage.py runserver 0.0.0.0:8000