我的前一篇文章:搜狗地图研究-坐标系对应中提到GPS坐标系和搜狗地图的坐标系的关系,这篇文章着重谈谈怎么离线下载搜狗地图。
搜狗的离线下载算是比较简单的,只要搞清楚坐标系和URL的对应关系即可。
为了得到这个对应算法,分析搜狗的javascript是一种方法。但是由于搜狗已经对js进行了加密,所以解密出来的东西也不怎么看得懂。况且在firebug中获取到的js还不完整,很影响分析。
最后,发现搜狗路书是用flash做的。各位看官看到这里,有经验的就知道把flash下载下来,反编译一下就能看到actionscript的代码。很好,搜狗在这里面没有一丝的模糊,完全高清无码奉送。好了,至于反编译后的代码是怎么回事,各位还是回家自己研究研究吧。在这里就不多废话了。
分析代码发现,在18级的时候,每一个像素代表了0.488281米的距离,每缩放一级就放大一倍,也就是说在第n级的对应有:
BASE_MPP = 0.488281
def getMetersPerPixel(level):
return BASE_MPP * (1 << 18 - level)
地图的图片都是256*256大小的,所以一个图片覆盖的面积是:
def getPicArea(level):
return 256*getMetersPerPixel(level)
得到了面积以后,就可以进行计算了,将ActionScript代码翻译过来,就成了我们的代码了:
def getPicArea(level):
return 256*getMetersPerPixel(level)
def formatWithM(param1):
return ("M" + (-str(param1))) if (param1 < 0) else ("" + str(param1))
LEVELCODE = ["728", "727", "726", "725", "724", "723", "722", "721", "720", "719", "718", "717", "716", "715", "714", "713", "712", "711", "792"]
def getMapURL(sogouLat, sogouLon, level):
mapArea=getPicArea(level)
picsPerFolder = 200;
_loc_9 = int(math.floor(sogouLon / mapArea))
_loc_10 = int(math.floor(_loc_9 / picsPerFolder))
_loc_11 = int(math.floor(sogouLat / mapArea))
_loc_12 = int(math.floor(_loc_11 / picsPerFolder))
_loc_13 = formatWithM(_loc_9)
_loc_14 = formatWithM(_loc_11)
_loc_15 = formatWithM(_loc_10)
_loc_16 = formatWithM(_loc_12)
return "/" + LEVELCODE[level] + "/" + _loc_15 + "/" + _loc_16 + "/" + _loc_13 + "_" + _loc_14
这样,就得到了一部分的URL。
搜狗地图分为三种图:普通地图、卫星图、卫星图上覆盖的简化地图
三种地图分别有基URL与之对应:
根据getMapURL的结果,与你想要的图的基URL一合并,就搞定了。
好了,说多了烦,直接上完整代码,怎么用你就琢磨琢磨吧。
告诉你一个不幸的消息,不要试图将全国18级地图全部下载完,那会消耗上T的空间,而且是很多的T~~~可以下载一部分玩玩咯。
#!/usr/bin/env python
#Author: Derek
#Homepage: http://www.april1985.com
import math
import threading
import os
import urllib
import time
BASE_MPP = 0.488281
LEVELCODE = ["728", "727", "726", "725", "724", "723", "722", "721", "720", "719", "718", "717", "716", "715", "714", "713", "712", "711", "792"]
downType=["Hd","Lw","Map"]
rootPath={"Hd":"http://hbpic1.go2map.com/seamless/0/180",
"Lw":"http://hbpic2.go2map.com/seamless/0/179",
"Map":"http://pic1.go2map.com/seamless/0/174"}
suffix={"Hd":".JPG",
"Lw":".PNG",
"Map":".GIF"}
def getMetersPerPixel(level):
return BASE_MPP * (1 << 18 - level)
def formatWithM(param1):
return ("M" + (-str(param1))) if (param1 < 0) else ("" + str(param1))
def getPicArea(level):
return 256*getMetersPerPixel(level)
def formatWithM(param1):
return ("M" + (-str(param1))) if (param1 < 0) else ("" + str(param1))
def getMapURL(sogouLat, sogouLon, level):
mapArea=getPicArea(level)
picsPerFolder = 200;
_loc_9 = int(math.floor(sogouLon / mapArea))
_loc_10 = int(math.floor(_loc_9 / picsPerFolder))
_loc_11 = int(math.floor(sogouLat / mapArea))
_loc_12 = int(math.floor(_loc_11 / picsPerFolder))
_loc_13 = formatWithM(_loc_9)
_loc_14 = formatWithM(_loc_11)
_loc_15 = formatWithM(_loc_10)
_loc_16 = formatWithM(_loc_12)
return "/" + LEVELCODE[level] + "/" + _loc_15 + "/" + _loc_16 + "/" + _loc_13 + "_" + _loc_14
threadCount=0
class downloadThread(threading.Thread):
def __init__(self, url, file):
threading.Thread.__init__(self)
self.url=url
self.file=file
def run(self):
global threadCount
dir=os.path.split(self.file)[0]
try:
if not os.path.isdir(dir):
os.makedirs(dir)
except:
pass
if not os.path.isfile(self.file):
print "Getting %s" % self.url
urllib.urlretrieve(self.url, self.file)
if(os.path.getsize(self.file)<500):
os.remove(self.file)
threadCount-=1
else:
threadCount-=1
latFrom=40
latEnd=60
lonFrom=80
lonEnd=100
picCount=0
localStorage="D:/map/storage"
for level in range(1,18):
mapArea=getPicArea(level)
lon=lonFrom
lat=latFrom
picCount=0
while(lon20):
time.sleep(0.5)
picCount+=1
lat+=mapArea
lon+=mapArea
print level,picCount