Google Map Tile 下载脚本
转 http://bbs.esrichina-bj.cn/ESRI/viewthread.php?tid=65904 (我没有用过,有环境的朋友可以试试)
早就写了,一直都有问题没好意思放出来,自己最近这段时间着迷于python编程,但进步缓慢,昨晚看《可爱的python》,得到启发,还是拿出来让大家一起帮忙修改完善。
毛病很多,比如:线程,不太会用,下载进度计数上面有问题;又如:不能暂停下载后接着下载。
总之希望大家多多交流,把这个小工具修改完善。
dmc.py源代码:
代码
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的都默认安装了这个版本。
执行以上脚本可以在同目录下新建一个批处理文件,内容如下:
- python dmc.py "118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 16 10 c:\caches\jn 20
- pause
"118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 是待下载的区域范围
16 10 是下载的等级范围
c:\caches\jn 是存储目录
20 是线程数 我的python版本是2.5,装过ArcMap的都默认安装了这个版本。
执行以上脚本可以在同目录下新建一个批处理文件,内容如下:
- python dmc.py "118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 16 10 c:\caches\jn 20
- pause
"118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 是待下载的区域范围
16 10 是下载的等级范围
c:\caches\jn 是存储目录
20 是线程数