本片介绍python爬虫抓取天地图离线瓦片并在cesium里离线调用。
1.天地图数据:先看天地图数据的格式:图片来源于关于天地图的瓦片下载
一、用QGIS抓取瓦片
1、安装Qtiles
2、下载瓦片
下载完成
3、制作 tilemapresource.xml 文件
tilemapresource.xml没有也能运行,但是会提示缺少该文件。可以自己做一份。
用json文件里的边界替换tilemapresource.xml文件里的边界和原点,原点是左下角。分辨率不够可以再加,比例尺参考geoserver就知道了。
<?xml version="1.0" encoding="utf-8"?>
<TileMap version="1.0.0" tilemapservice="http://tms.osgeo.org/1.0.0">
<Title>world</Title>
<Abstract></Abstract>
<SRS>EPSG:3857</SRS>
<BoundingBox minx="-180.0" miny="-85.0511287798066" maxx="180.0" maxy="85.0511287798066"/>
<Origin x="-180.0" y="-85.0511287798066"/>
<TileFormat width="256" height="256" mime-type="image/png" extension="png"/>
<TileSets profile="mercator">
<TileSet href="1" units-per-pixel="78271.51695000000473" order="1"/>
<TileSet href="2" units-per-pixel="39135.75847500000236" order="2"/>
<TileSet href="3" units-per-pixel="19567.87923750000118" order="3"/>
<TileSet href="4" units-per-pixel="9783.93961875000059" order="4"/>
<TileSet href="5" units-per-pixel="4891.96980937500030" order="5"/>
<TileSet href="6" units-per-pixel="2445.98490468750015" order="6"/>
<TileSet href="7" units-per-pixel="1222.99245234375007" order="7"/>
<TileSet href="8" units-per-pixel="611.49622617187504" order="8"/>
<TileSet href="9" units-per-pixel="305.74811308593752" order="9"/>
<TileSet href="10" units-per-pixel="152.87405654296876" order="10"/>
<TileSet href="11" units-per-pixel="76.43702827148438" order="11"/>
<TileSet href="12" units-per-pixel="38.21851413574219" order="12"/>
<TileSet href="13" units-per-pixel="19.10925706787109" order="13"/>
<TileSet href="14" units-per-pixel="9.55462853393555" order="14"/>
<TileSet href="15" units-per-pixel="4.77731426696777" order="15"/>
</TileSets>
</TileMap>
如下
4、加载地图
viewer.scene.imageryLayers.addImageryProvider(
new Cesium.TileMapServiceImageryProvider({
url: "http://localhost:3000/tdt2/Mapnik/",
minimumLevel: 0,
maximumLevel: 5,
//tilingScheme: new Cesium.WebMercatorTilingScheme({
// numberOfLevelZeroTilesX : 1,
// numberOfLevelZeroTilesY : 1
//}),
})
);
二、自己爬虫抓取瓦片
1\以影像为例,数据可以抓取1-18级的,但最好不要级别太高否则内存溢出!!!。更高级的将为空。对于地形只能是1-14级且地形的比较特别就是每张地形切片对应的t0-t7会不一样,估计就是为了反扒才这样设计吧。处理办法还是循环url里t后面的数字,当返回状态不成功时改变数字。
2.爬虫:python2.7网上其他人也有但要注意python2还是3的版本因为urllib的使用是不一样的,被误导还好小编精通爬虫能看出问题
# coding=utf-8
import re
import urllib
import os
import random
import math
import urllib2
import sys
sys.setrecursionlimit(10000)
agents = [
'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5',
'Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7',
'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1']
def deg2num(lat_deg, lon_deg, zoom):
lat_rad = math.radians(lat_deg)
n = 2.0 ** zoom
xtile = int((lon_deg + 180.0) / 360.0 * n) #计算列col X
ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n) #计算行row Y
return (xtile, ytile)
for zoom in range(1,4):
#地图级别级左上右下角范围"bounds": "-180.0,-85.0511287798066,180.0,85.0511287798066"
lefttop = deg2num(85.0511287798066, -180, zoom)
rightbottom = deg2num(-85.0511287798066, 180, zoom)
print(lefttop)
print(rightbottom)
i = 0
for x in range(lefttop[0], rightbottom[0]):
for y in range(lefttop[1], rightbottom[1]+1):#+1非常重要否者会少一行
imgUrl = "http://t0.tianditu.com/DataServer?T=img_w&x=" + str(x) + "&y=" + str(y) + "&l=" + str(zoom) + "&tk=自己的密钥"
print(imgUrl )
i+=1
if not os.path.exists( "D:\\tianditu\\img_w\\"+ str(zoom) +"\\"+str(x)):
os.makedirs( "D:\\tianditu\\img_w\\"+ str(zoom) +"\\"+str(x) )
try:
header = {
'User-Agent': random.choice(agents),
'Cookie': 'AspxAutoDetectCookieSupport=1',
}
request = urllib2.Request(imgUrl, None, header)
response = urllib2.urlopen(request)
imgName = str(y) + ".png"
os.chdir(r"D:/tianditu/img_w/"+ str(zoom)+"/"+str(x))
f = open( imgName , 'wb')
f.write(response.read())
f.close()
except Exception:
print( imgUrl )
print(str(i))
print('end')
成功后如下
3.离线调用:
调用可以本地也可以用tomcat或iis或者nigix代理。最简单的还是本地。没啥不同就是质疑url路径写正确就ok。
var viewer = new Cesium.Viewer('cesiumContainer', {
geocoder: false, //是否显示地名查找控件
infoBox: false,
animation: true, //是否显示动画控件(左下方那个)
timeline: true, //是否显示时间线控件
shadows: false, // 阴影是否被太阳投射
showldAnimate: true, //让场景中的动画自动播放
sceneModePicker: false, //是否显示投影方式控件
fullscreenButton: false, //全屏按钮不显示
homeButton: false,
navigationHelpButton: false,//帮助按钮
sceneMode: Cesium.SceneMode.SCENE3D, //设定3维地图的默认场景模式:Cesium.SceneMode.SCENE2D、Cesium.SceneMode.SCENE3D、Cesium.SceneMode.MORPHING
scene3DOnly: true,//如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
baseLayerPicker: false, //是否显示图层选择控件
imageryProvider: _bingMap,
imageryProvider:new Cesium.UrlTemplateImageryProvider({
url:'../../../tianditu/img_w/{z}/{x}/{y}.png',
fileExtension : "png",
maximumLevel: 18,
//tilingScheme: new Cesium.WebMercatorTilingScheme({
// numberOfLevelZeroTilesX : 1,
// numberOfLevelZeroTilesY : 1
//}),
}),
// terrainProvider: cesiumTerrainProvider
});
如果你想tomcat也很简单,把文件夹放到tomcat的webpack目录下,怎么允许跨域小编就不教你。
三、注意
1、方法一比方法二抓取瓦片速度要快很多。推荐方式一稳定不出错
2、方法二没写图片保存失败重新保存,当网络不好可能会出现丢失瓦片现象。
3、一定注意两种方式的瓦片组织结构不一样,加载方式也不同。因为两种方式的行号Y(row是相反的)加载结果一致
4、方式二的范围是:"bounds": "-180.0,-85.0511287798066,180.0,85.0511287798066"
5、生成的文件没有tilemapresource.xml,可以按上面自己修改也可以在qgis里切一份瓦片然后去修改。