Google地图下载
Google地图下载
谷歌地图是在线地图,然而有些时候我们需要将其下载到本地进行相关操作和使用,截图再拼接固然很好,但是不精确和效率低,本程序将下载指定区域地图到本地。此文将回顾并记录其中下载历程,进行分享。
谷歌地图访问受限,因此地图信息采集集中在八九地图(内有谷歌地图API接口,可查看谷歌地图)
通过审查元素(F12)发现谷歌加载的地图瓦片,一个个瓦片拼接成整个地图。
而且这些瓦片的链接非常规律
https://mt1.google.cn/maps/vt?lyrs=s%40781&hl=zh-CN&gl=CN&x=107915&y=49662&z=17
上述链接是午门东凤翅楼卫星照片,观察可知坐标x=107915, y= 49662,其中的z指的是地图层级,z=17,这是第17层(1-20,越大越清晰)
通过坐标的简单变换和图显示出来的瓦片图分析我们可以看出,这个谷歌地图的坐标轴的指向。它的x轴是像东增西减的,它的外轴是南增北减的。
有了坐标之后,通过对单张瓦片地图的爬取,我们就可以得到我们想要范围内的所有瓦片图。然后进行拼接,就可以得到我们想要范围内的整张地图。
上述就是此程序的基本逻辑和原理。
我用的是urllib进行爬取,因为它一条指令就可以对图片进行爬取和存储,非常方便。
首先提取的是左上角的瓦片的坐标,然后进行相应的迭代循环,从而取得整个想要的范围内的瓦片。每个瓦片图都用其坐标进行命名以便拼接。
爬了一次之后,就遇到了一个大问题,它将我的ip封掉了,我无法查看谷歌地图了(好像两天才会解封)。查了一些资料之后,发现我们需要将我们的爬虫伪装一下,加一个headers。然后里面是一个user agent的一个字典。然后又发现了一个叫fake user agent的一个库,这个库里有很多各式各样的可以模拟各种浏览器的user agent,加入这个之后就畅行无阻了,不会产生相应的问题了。
from fake_useragent import UserAgent
def weizhuanggetmap(x,y):
fakeagent = UserAgent().random
headers = {"User-Agent":fakeagent}
url = "https://mt0.google.cn/maps/vt?lyrs=s%40781&hl=zh-CN&gl=CN&x="+str(x)+"&"+"y="+str(y)+"&z="+cengji
local = mapspath + "\\" + str(x) + str(y) + ".jpg"
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', fakeagent)]
urllib.request.install_opener(opener)
urllib.request.urlretrieve(url,local)
还有一个问题就是我们范围设置的问题,比如说我们想。爬一个东西宽十公里,南北长20千米的一个图,我们需要 多少块,南北爬多少块都是需要计算的。我只爬了16层级的谷歌地图,因此我将以16层级的谷歌地图为例说明。
一块谷歌地图瓦片的像素是256x256像素。
在北纬50°的伦敦,我们通过比例尺计算出它是350米乘350米的一块。
在北纬40°的北京,我们通过比例尺计算出它是450米乘450米的一块。
在北纬34°的洛杉矶,我们通过比例尺计算出它是484米乘484米的一块。
单块儿瓦片所覆盖的米数不同,也就直接导致了相同公里数它所需的瓦片数不一样。在程序内直接进行下映的计算机即可。
程序内还使用了os库来检验文件的下载情况,看看它是否存在。有极少数情况下,有一两张瓦片会下载失败。还有些情况下会因为中途停止。而我们不知道下到了哪里,所以说引入了os库,我们可以接着上面已经下载的继续下载。
全部下载完成之后,我们即将进行图像的拼接,这里使用的是Python的pillow的库。
首先创建同样像素大小的照片作为背景,然后逐个迭代引入我们的瓦片进行粘贴。
但是由于电脑的运行内存限制,超过1万张便会卡顿。**甚至无法运行。于是,超过1万张的我们将对其进行分行粘贴,以多少行为一组进行粘贴,最后再将粘贴好的几张大的卫星图再进行拼接。
有时候地图范围会进入海域,而有谷歌地图的一些深海并没有相应层级的。这时网页是404Error报错,所以这时候需要引入urllib.error,然后进行识别这个错误。识别出这个错误之后进行替换,我们用一张线蓝色的近似于大海颜色的照片进行替换,将这个瓦片进行补全。
import urllib.error
except urllib.error.HTTPError: #关于大海
print("第"+str(i)+"行,第"+str(a)+"张"+"是一片海")
sea = Image.new("RGB",(256,256),(68,88,137)) #创建一张蓝色照片替代
local = mapspath + "\\" + str(x) + str(y) + ".jpg"
sea.save(local,"jpeg")
sea.close()
print("替换完成")
但是还有一个思路是这时候先空过去等到拼接的时候。设置一个海蓝色背景为底,然后拼接的时候用一个try except打不开就直接跳过留下蓝色背景。
关于大图片报错问题
PIL.Image.DecompressionBombError: Image size (778633216 pixels) exceeds limit of 178956970 pixels, could be decompression bomb DOS attack.
这是库里面的源码
def _decompression_bomb_check(size):
if MAX_IMAGE_PIXELS is None:
return
pixels = size[0] * size[1]
if pixels > 2 * MAX_IMAGE_PIXELS:
raise DecompressionBombError(
"Image size (%d pixels) exceeds limit of %d pixels, "
"could be decompression bomb DOS attack." % (pixels, 2 * MAX_IMAGE_PIXELS)
)
if pixels > MAX_IMAGE_PIXELS:
warnings.warn(
"Image size (%d pixels) exceeds limit of %d pixels, "
"could be decompression bomb DOS attack." % (pixels, MAX_IMAGE_PIXELS),
DecompressionBombWarning,
)
可见一旦图片大于一倍或者两倍MAX_IMAGE_PIXELS就会报错,说这可能是DOS攻击。但是我们只是单纯的想打开这张图片,于是我们可以在开头修改这个参数。
Image.MAX_IMAGE_PIXELS = None
这样就不会产生报错,程序得以运行。
样例:
伦敦
链接:https://pan.baidu.com/s/1nkpWU__Jdycgt29nOM0Q5w
提取码:t5jg
阿尔布开克
链接:https://pan.baidu.com/s/1mHgZFECCumSXn7NmIqwm8Q
提取码:43bb
洛杉矶
链接:https://pan.baidu.com/s/13cjoTBsFYEhXZ9EYnr6-iA
提取码:4h5w
源码及样例
链接:https://pan.baidu.com/s/1bGTUjKkGlTUTHTltPbMHxg
提取码:c99l
本文地址:https://blog.csdn.net/victory0431/article/details/107498935
上一篇: 社科基金
下一篇: doctype的意思