欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Google地图下载

程序员文章站 2023-08-11 18:59:33
Google地图瓦片下载,本地拼接,文末给出源码...

Google地图下载

谷歌地图是在线地图,然而有些时候我们需要将其下载到本地进行相关操作和使用,截图再拼接固然很好,但是不精确和效率低,本程序将下载指定区域地图到本地。此文将回顾并记录其中下载历程,进行分享。

谷歌地图访问受限,因此地图信息采集集中在八九地图(内有谷歌地图API接口,可查看谷歌地图)
Google地图下载

通过审查元素(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,越大越清晰)
Google地图下载

Google地图下载

通过坐标的简单变换和图显示出来的瓦片图分析我们可以看出,这个谷歌地图的坐标轴的指向。它的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

相关标签: 笔记