Google Map Tile 下载脚本

本文提供了一个Python脚本,用于下载指定区域和等级范围内的Google地图切片,并在本地创建相应的缓存目录结构。脚本支持线程下载和错误记录,适用于GIS和地图应用的离线使用。

http://bbs.esrichina-bj.cn/ESRI/viewthread.php?tid=65904 (我没有用过,有环境的朋友可以试试)

早就写了,一直都有问题没好意思放出来,自己最近这段时间着迷于python编程,但进步缓慢,昨晚看《可爱的python》,得到启发,还是拿出来让大家一起帮忙修改完善。
毛病很多,比如:线程,不太会用,下载进度计数上面有问题;又如:不能暂停下载后接着下载。
总之希望大家多多交流,把这个小工具修改完善。
dmc.py源代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码

   
1 # coding=utf-8
2
3 # Filename:dmc.py
4
5 import cmath,urllib,os,math,random,sys,time,threading
6
7
8
9 class Cdt:
10
11 def __str__ (self):
12
13 return ' {x = %s,y = %s} ' % (self.x,self.y)
14
15
16
17 def createName(num,type):
18
19 # '''创建文件夹/文件名称'''
20
21 temp = ' 00000000 ' + str(hex(int(num)))[ 2 :]
22
23 return type + temp[:: - 1 ][0: 8 ][:: - 1 ]
24
25
26
27 def getPixelFromCdt(x,y,z):
28
29 # '''根据经纬度坐标以及缩放等级获取像素坐标'''
30
31 pixel = Cdt()
32
33 sinLatitude = cmath.sin(y * cmath.pi / 180 )
34
35 pixel.x = ((x + 180 ) / 360 ) * 256 * ( 2 ** z)
36
37 temp = cmath.log(( 1 + sinLatitude) / ( 1 - sinLatitude))
38
39 pixel.y = abs(( 0.5 - temp / ( 4 * cmath.pi)) * 256 * ( 2 ** z))
40
41 return pixel
42
43
44
45 def getTileFromPixel(pixel):
46
47 # '''根据像素坐标获取切片'''
48
49 tile = Cdt()
50
51 tile.x = math.floor(pixel.x / 256 )
52
53 tile.y = math.floor(pixel.y / 256 )
54
55 return tile
56
57
58
59 def getTileFromCdt(x,y,z):
60
61 # '''根据经纬度坐标以及缩放等级获取切片'''
62
63 return getTileFromPixel(getPixelFromCdt(x,y,z))
64
65
66
67 def downloadTile(remoteFile,localFile):
68
69 # '''下载远程文件到本地'''
70
71 urllib.urlretrieve(remoteFile,localFile)
72
73
74
75 def createDir(dirPath):
76
77 # '''创建文件夹'''
78
79 if not os.path.exists(dirPath):
80
81 os.makedirs(dirPath)
82
83
84
85 def createRemoteUrl(x,y,z):
86
87 # '''创建远程tile地址'''
88
89 port = str(random.randint(0, 3 ))
90
91 x = str(x)
92
93 y = str(y)
94
95 z = str(z)
96
97 return ' http://mt ' + port + ' .google.cn/vt/v=w2.115&hl=zh-CN&gl=cn&x= ' + x + ' &s=&y= ' + y + ' &z= ' + z
98
99
100
101 def createLocalFile(x,y,z,lvRange,cacheDir):
102
103 # '''创建缓存本地路径'''
104
105 # 计算<等级目录>名称
106
107 i = int(z) - lvRange[0]
108
109 l = ''
110
111 if i < 10 :
112
113 l = ' L0 ' + str(i)
114
115 elif i >= 10 and i <= lvRange[len(lvRange) - 1 ]:
116
117 l = ' L ' + str(i)
118
119 # 计算<行目录>和<(列)图片>名称
120
121 r = createName(y, ' R ' )
122
123 c = createName(x, ' C ' )
124
125 # 拼装本地路径
126
127 return cacheDir + os.sep + l + os.sep + r + os.sep + c + ' .png '
128
129
130
131 def createCacheDir(rowName,lv,row,xRange):
132
133 # '''创建缓存目录'''
134
135 createDir(rowName) # 创建行文件夹
136
137 for col in xRange:
138
139 # localTile = rowName + os.sep + createName(col,'C') + '.png'
140
141 tempTask.append( ' %s,%s,%s ' % (lv,row,col))
142
143
144
145 def createLvCache(extent,lv,dir):
146
147 # '''创建某一等级下一行cache'''
148
149 startTile = getTileFromCdt(extent[0],extent[ 1 ],lv)
150
151 endTile = getTileFromCdt(extent[ 2 ],extent[ 3 ],lv)
152
153 xRange = range(int(startTile.x),int(endTile.x))
154
155 yRange = range(int(startTile.y),int(endTile.y))
156
157 for row in yRange:
158
159 rowName = dir + os.sep + createName(row, ' R ' )
160
161 createCacheDir(rowName,lv,row,xRange)
162
163
164
165 def createCacheStruc(extent,lvRange,cacheDir):
166
167 # '''创建缓存目录结构及计算tile'''
168
169 global tempTask
170
171 tempTask = [] # 存储cache下载列表
172
173 count = 0
174
175 print ' 创建Cache目录及计算tile数目... '
176
177 for lv in lvRange:
178
179 lvName = ' L0 ' + str(count) # lvName:等级文件夹名
180
181 createDir(cacheDir + os.sep + lvName) # 创建lv等级的文件夹,例如:lv01,lv02...
182
183 createLvCache(extent,lv,cacheDir + os.sep + lvName) # 创建完等级文件夹后,添加该等级的行文件夹,例如:R000001a0
184
185 count += 1
186
187
188
189 def loadErrorFile(url):
190
191 '''
192
193 加载错误任务
194
195 '''
196
197 os.rename(url,url + ' bak ' )
198
199 f = open(url + ' bak ' )
200
201 return f.readlines()
202
203
204
205
206
207 def loadTask(task,threadNum):
208
209 global failureTask
210
211 failureTask = []
212
213 tasksize = len(task)
214
215 threadTask = tasksize // int(threadNum) # 取整除 返回商的整数部分
216
217 print ' 待下载Tile总计:%s,下载线程数:%s ' % (tasksize,sys.argv[ 5 ])
218
219
220
221 for i in range(len(task)):
222
223 # log('开启线程:%s'%i,False)
224
225 st = i * int(threadTask)
226
227 ed = st + int(threadTask) + 1
228
229 if ed > len(task) - 1 :
230
231 download = Download(task[st:len(task) - 1 ])
232
233 download.start()
234
235 break
236
237 download = Download(task[st:ed])
238
239 download.start()
240
241 time.sleep( 0.5 )
242
243
244
245
246
247 class Download(threading.Thread):
248
249 sucessCount = 0
250
251 failureCount = 0
252
253 def __init__ (self,tasks):
254
255 threading.Thread. __init__ (self)
256
257 self.tasks = tasks
258
259 self.lock = threading.RLock()
260
261 def run(self):
262
263 # log('start download',False)
264
265 for task in self.tasks:
266
267 valueAry = task.split( " , " )
268
269 lv = valueAry[0]
270
271 row = valueAry[ 1 ]
272
273 col = valueAry[ 2 ]
274
275 remoteFile = createRemoteUrl(col,row,lv)
276
277 localFile = createLocalFile(col,row,lv,lvRange,cacheDir)
278
279 try :
280
281 downloadTile(remoteFile,localFile)
282
283 self.lock.acquire()
284
285 Download.sucessCount += 1
286
287 log( ' 已经下载:%s / %s ,失败: %s / %s ' % (Download.sucessCount,len(tempTask),Download.failureCount,len(failureTask)),False)
288
289 self.lock.release()
290
291 except :
292
293 logStr = ' %s,%s,%s ' % (lv,row,col)
294
295 f = file(cacheDir + os.sep + ' error.log ' , ' a ' ) # 在日志文件中打印失败记录
296
297 f.write(logStr + ' \n ' )
298
299 f.close()
300
301 self.lock.acquire()
302
303 Download.failureCount += 1
304
305 self.lock.release()
306
307 failureTask.append(logStr)
308
309
310
311 def log(event,b):
312
313 # '''打印消息或日志'''
314
315 try :
316
317 logStr = str(event)
318
319 if b: # 在日志文件中打印消息
320
321 f = file(cacheDir + os.sep + str(time.strftime( ' %Y%m%d%H ' )) + ' .log ' , ' a ' )
322
323 f.write(logStr + ' \n ' )
324
325 f.close()
326
327 sys.stdout.write( ' \r ' + logStr) # 在控制台中打印消息
328
329 sys.stdout.flush()
330
331 except :
332
333 pass
334
335
336
337
338
339 if __name__ == ' __main__ ' :
340
341
342
343 extent = sys.argv[ 1 ]
344
345 maxLv = sys.argv[ 2 ]
346
347 minLv = sys.argv[ 3 ]
348
349
350
351 global extAry,lvRange,cacheDir,threadNum
352
353 ext = [float(i) for i in extent.split( ' ' )]
354
355 extAry = [ext[0],ext[ 3 ],ext[ 2 ],ext[ 1 ]] # 区域范围
356
357 lvRange = range(int(minLv),int(maxLv) + 1 ) # 等级范围
358
359 cacheDir = sys.argv[ 4 ] # 下载目录
360
361 threadNum = sys.argv[ 5 ] # 下载线程
362
363
364
365 if sys.argv[ 1 ] == ' loadError ' :
366
367 errorTask = loadErrorFile(sys.argv[ 2 ] + os.sep + ' error.log ' )
368
369 loadTask(tempTask,sys.argv[ 3 ])
370
371 else :
372
373 createCacheStruc(extAry,lvRange,cacheDir) # 创建缓存目录结构
374
375 loadTask(tempTask,threadNum) # 下载
376
377

 

我的python版本是2.5,装过ArcMap的都默认安装了这个版本。
执行以上脚本可以在同目录下新建一个批处理文件,内容如下:

  1. python dmc.py "118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 16 10 c:\caches\jn 20
  2. pause
复制代码

"118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 是待下载的区域范围
16 10 是下载的等级范围
c:\caches\jn 是存储目录
20 是线程数 我的python版本是2.5,装过ArcMap的都默认安装了这个版本。
执行以上脚本可以在同目录下新建一个批处理文件,内容如下:

  1. python dmc.py "118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 16 10 c:\caches\jn 20
  2. pause

"118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 是待下载的区域范围
16 10 是下载的等级范围
c:\caches\jn 是存储目录
20 是线程数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值