js+python实现百度离线地图

zcz 4662 0

1.加载离线地图


Demo工程文件百度网盘下载: baidumapv2.0_js_offline_V1_V1.0.0.rar

<!DOCTYPE html>  
<html>  
    <head>  
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
        <title>百度离线版2.0 DEMO</title>  
        <script type="text/javascript" src="js/apiv2.0.min.js"></script>  
        <link rel="stylesheet" type="text/css" href="css/bmap.css"/>  
    </head>  
    <body>  
        <div style="width:520px;height:340px;border:1px solid gray" id="container"></div>  
    </body>  
</html>  
  
<script type="text/javascript">  
    // 百度地图API功能  
    var map = new BMap.Map("container");                    //创建Map实例  
    map.centerAndZoom(new BMap.Point(118.00323, 36.81635), 13); //初始化地图,设置中心点坐标和地图级别  
    //map.addControl(new BMap.MapTypeControl());            //添加地图类型控件 离线只支持电子地图,卫星/三维不支持  
    //map.setCurrentCity("北京");                         //设置地图显示的城市 离线地图不支持  
    map.enableScrollWheelZoom(true);                        //开启鼠标滚轮缩放  
    map.addControl(new BMap.NavigationControl());           //缩放按钮  
</script>  

QQ截图20180325184946.png
基于百度官方的js+html展现地图


2.获取地图瓦片

2.1 瓦片存放规则

离线地图是由一张张256×256的图片拼接而成的,同一地点在每一级缩放下的坐标都不同,缩放越大坐标值也越大。

读取离线瓦片的规则在文件夹命名中有所体现,../tiles/13/1605/532.png代表缩放层级为13级,x=1605,y=532的瓦片。

百度存放这些贴片的url为
http://online3.map.bdimg.com/onlinelabel/?qt=tile&x=%d&y=%d&z=%d&styles=pl&udt=20180321&scaler=1&p=1

所以只需要请求贴片对应的url,下载下来,按照坐标规则分文件夹存放就行了。

2.2 瓦片坐标获取

这是关键和难点所在,我参考了 百度地图API详解之地图坐标系统 - jz1108 - 博客园 的方法。

原博中实现了点击地图上的点,显示经纬度和瓦片坐标等信息,但点击一次只能显示所处一个层级的瓦片坐标。

因为同一个点的经纬度是始终不变的,所以可以在点击一次之后获取到此点的经纬度坐标,再利用经纬度进行i=3;i<20;i++的循环请求(百度地图层级为3-19),已经能实现点击一次得到此点所有层级的瓦片坐标了。

QQ截图20180325190028.png

那么要实现的离线地图必定是一个区域,可以用两个点确定(左下和右上,东经北纬右上坐标为区域上限,左下为下限)

得到这些瓦片坐标后,需要拼接出url进行下载并归类命名,查了很多资料没有发现js的实现方法,想办法用python实现..

python无法直接获取到console中输出的内容,只能想办法用js直接输出txt文件就可以了。

查了很久发现了一个方法 利用Javascript生成txt文本文件 - CSDN博客 

QQ截图20180325190000.png

QQ截图20180325190104.png

js代码

<script>
function tilexy(x,y){
var xs = '';var ys = ''
for (var i=3;i<20;i++){
var map =new BMap.Map('map_container2', {defaultCursor: 'default'});

map.centerAndZoom(new BMap.Point(118.003, 36.816), i);

var TILE_SIZE =256;

var projection =map.getMapType().getProjection();
  
var worldCoordinate = projection.lngLatToPoint(new BMap.Point(x, y));
  
var pixelCoordinate =new BMap.Pixel(Math.floor(worldCoordinate.x * Math.pow(2, map.getZoom() -18)), 
                                       Math.floor(worldCoordinate.y * Math.pow(2, map.getZoom() -18)));
 
var tileCoordinate =new BMap.Pixel(Math.floor(pixelCoordinate.x /256),
                                 Math.floor(pixelCoordinate.y /256));
var tileCoordStr ="坐标:"+ tileCoordinate.x +", "+ tileCoordinate.y;
  
console.log(i +","+ tileCoordinate.x +","+ tileCoordinate.y);
xs = xs + tileCoordinate.x+" ";ys = ys + tileCoordinate.y+" ";
};
var blob = new Blob([xs+'\r\n'+ys], {type: "text/plain;charset=utf-8"});  
saveAs(blob, "xys.txt"); 
};
</script>


<script>
var map =new BMap.Map('map_container1', {defaultCursor: 'default'});
map.centerAndZoom(new BMap.Point(118.003, 36.816), 11);
map.enableScrollWheelZoom();

var TILE_SIZE =256;

map.addEventListener('click', function(e){
  var projection =this.getMapType().getProjection();
  
  var lngLat = e.point;  
  var lngLatStr ="经纬度:"+ lngLat.lng +", "+ lngLat.lat;
  
  tilexy(lngLat.lng,lngLat.lat);
});
</script>


2.3 瓦片下载存放

得到瓦片坐标剩下的就很简单了,完全变成了python爬虫的问题

python代码

import urllib.request
import os

#创建文件夹
def mkdir(path):  
  
    folder = os.path.exists(path)  
  
    if not folder:
        os.makedirs(path)

#此文件所在目录
dirpath = os.getcwd().replace('\\','/')

print('-----------------Py地图瓦片下载器------------------')
print('')
print('')
print('                                  Powerd by SDUTzcz')
print('')
        
#设置需要的地图层级
a = input('最小层级[>=3]:')
b = input('最大层级[<=19]:')

#调取js获取到的瓦片坐标
with open('xys.txt','r',encoding='utf-8') as f1:
    mintile = f1.read().encode('utf-8').decode('utf-8-sig').split()

with open('xys (1).txt','r',encoding='utf-8') as f2:
    maxtile = f2.read().encode('utf-8').decode('utf-8-sig').split()

#按坐标规则分文件夹下载瓦片
for z in range(int(a),int(b)+1):
    mkdir('./tiles/'+str(z))
    for x in range(int(mintile[z-3]),int(maxtile[z-3])+1):
        mkdir('./tiles/'+str(z)+'/'+str(x))
        for y in range(int(mintile[z-3+17]),int(maxtile[z-3+17])+1):
            urllib.request.urlretrieve('http://online3.map.bdimg.com/onlinelabel/?qt=tile&x=%d&y=%d&z=%d&styles=pl&udt=20180321&scaler=1&p=1'%(x,y,z),dirpath+'/tiles/%d/%d/%d.png'%(z,x,y))


最后用pyinstaller打包成exe文件就可以了

QQ截图20180325190412.png
直接设置需要下载的层级

QQ截图20180325190200.png
最终文件

QQ截图20180325190245.png
下载的部分瓦片

QQ截图20180325190338.png
效果图

发表评论
表情 图片 链接 代码