亲自实践能够下载的谷歌地图切片url地址谷歌地图数据下载的尝试以及Python爬虫实现

Posted nanke_yh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了亲自实践能够下载的谷歌地图切片url地址谷歌地图数据下载的尝试以及Python爬虫实现相关的知识,希望对你有一定的参考价值。

目录

0、前言

1、地图下载工具的尝试

1.1、全能电子地图下载器

1.2、Global Mapper

2、地图获取原理

3、python爬取谷歌瓦片地图数据

3.1、python关键代码

3.2、代码的优化和结果

3.3、python完整工程代码和展望

 4、Python工程生成exe以及调用

4.1、工程外部参数输入改写

 4.2、exe生成和调用


谷歌地图数据获取

0、前言

        地图的获取主要是指通过网络获取到那些高精度的卫星图、街道图、瓦片以及综合图。这些数据资源主要集中在国家和大型的地理信息企业手里,而普通人往往也用不上这么庞大的数据。但有时相关行业的人员也需要用到部分数据,如此就需要通过相关的途径获取这些数据了。

        目前,普通人能够获取地图来源主要是百度、高德、腾讯和谷歌了。这些公司作为地理信息行业的巨头吧。基本把各自的产品和数据做大做强了。那么知道获取的对象,那么需要如何获取呢?市面上或者网上都能看到不少的自动地图下载器,比如全能电子地图下载器、Bigemap、水经注、91卫图、Global Mapper等等。这些并非免费,且免费有水印,授权使用等受到限制。有时我们就只是想要一幅高清影像图就要下载各种软件工具把电脑弄的乱七八糟,最后还无法搞定,那就比较苦恼了。那么,在知道这些工具也是获取以上大厂的资源数据后,我们转而了解地图获取原理结合编程实现不就能搞定了嘛!

1、地图下载工具的尝试

        对于地图下载工具,我主要尝试了全能电子地图下载器和Global Mapper两种。

1.1、全能电子地图下载器

        对于网上提供的全能电子地图下载器下载安装文章,只能说当下很多虚假,然后高版本的下载器无法破解,需要付费授权,免费的话有水印。这里弄了个低版本破解软件进行尝试,参考全能电子地图下载器-获取离线地图瓦片的工具_浩星的博客-CSDN博客_全能电子地图下载器,下载安装1.9.5版本。

        选择下载地区可以选择坐标范围(左上点经纬度和右下点经纬度)和选择行政区划两种操作;选择地图类型,则在菜单栏中地图下选择自己需要的数据来源和类型。

        最后操作发现谷歌等一些数据源无法下载数据,能够下载数据的仅百度、高德等。由于软件已被卸载,这里不贴图说明。

1.2、Global Mapper

        Global Mapper软件网上就存在破解版,我们可以直接使用,其下载地址为:Global Mapper下载 - Global Mapper 23.1.0 64位破解版 - 微当下载。或者这在网盘中下载,链接:https://pan.baidu.com/s/1Vb4VVRFBRYawt3MT-5gYOw提取码:sxdj

安装破解之后,打开软件:

 然后点击地球,connect数据源,就能够打开谷歌的地图(当然这里的谷歌图源需要自己添加):

        从上面可以看到,谷歌数据能够访问了。那么重要的谷歌url是什么呢?估计这个才是大家都关心的了。我也是在B站中别人分享视频中发现的,视频链接:公益直播回放(5.10日抖音直播):谷歌影像及历史影像下载_哔哩哔哩_bilibili 谷歌影像及历史影像下载_哔哩哔哩_bilibili。其中有提到两个图源链接,这里也分享给大家。

1)谷歌图源:OSM服务

http://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&x=%x&y=%y&z=%z

2)历史影像图源:WMTS服务

https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/default028mm/MapServer/tile/10/%7Blevel%7D/%7Brow%7D/%7Bcol%7D

        图源在Global Mapper软件上的具体用法,可去看视频,这里不详细叙述。

        拿到图源链接了,那我们当然要访问一下数据了,下面我们分别看看数据内容吧。可以看到,分别能够访问到数据的。

  

         Global Mapper软件更注重GIS软件的功能。从这里能够下载单景高分辨率的影像。对于繁多的瓦片数据估计还是得依靠爬虫。总体而言这个软件对于GISer来说还是有用的。

2、地图获取原理

        网上有不少文章分析了地理坐标系、投影坐标系的原理,还有各大地图网站瓦片的分割方式,还有提供的下载网址。然而发现这些文中的地图url地址在2021年谷歌被国家封禁后其链接均失效了。之所以执着于谷歌数据一般是因为项目终以前接口使用数据为谷歌地图,后面也必须下载同源数据,其次是谷歌数据要比其他数据源放大层级更高,数据多一些。

        针对上面知道的谷歌地图切片url地址,那么我们可以对其进行解析:

http://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&x=%x&y=%y&z=%z

url地址中的 lyrs 表示的是图层类型,即瓦片类型,比如卫星图、路线图等。

m:路线图
t:地形图
p:带标签的地形图
s:卫星图
y:带标签的卫星图
h:标签层(路名、地名等)

x,y,z则分别是瓦片坐标的x、y和缩放级别z,z取0-22。但测试发现卫星图最大只能取到20。不过即使是路线图,到20级也就足够用了。

主要参考文章如下:
客户端地图拼图算法解析
WGS84经纬度坐标与web墨卡托之间的转换【转】
国内主要地图瓦片坐标系定义及计算原理
Google 地图切片URL地址解析
腾讯与百度地图瓦片规则分析

如何用Python批量下载卫星地图 - 原始锋芒 - 博客园 (cnblogs.com)

3、python爬取谷歌瓦片地图数据

        在有了地图切片url地址后,为了获得大量的谷歌瓦片地图数据,唯有通过python爬虫技术来实现了。本文使用的python版本为3.7.0,可以用 urllib.request 库进行图片的下载。下面代码主要参考:

Python爬取谷歌地图切片、天地图切片_机智的根号三的博客-CSDN博客_爬取谷歌地图

3.1、python关键代码

# 经纬度反算切片行列号 3857坐标系
def deg2num(lat_deg, lon_deg, zoom):
    lat_rad = math.radians(lat_deg)
    n = 2.0 ** zoom
    xtile = int((lon_deg + 180.0) / 360.0 * n)
    ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
    return (xtile, ytile)
# 下载图片

def getimg(Tpath, Spath, x, y):

    global count

    count = 0 #清零

    try:

        f = open(Spath, 'wb')

        req = urllib.request.Request(Tpath)

        req.add_header('User-Agent', random.choice(agents))  #换用随机的请求头

        pic = urllib.request.urlopen(req, timeout=60)



        f.write(pic.read())

        f.close()

        print(str(x) + '_' + str(y) + '下载成功')

    except Exception:

        print(str(x) + '_' + str(y) + '下载失败,重试')#存在一直失败不跳出的bug

        getimg(Tpath, Spath, x, y)

        count = count + 1

        if count > 100:

           return
def download(k,LTlat,LTlon,RBlat,RBlon):

    zoom = k  #下载切片的zoom

    LT_lat = LTlat

    LT_lon = LTlon

    RB_lat = RBlat

    RB_lon = RBlon

    lefttop = deg2num(LT_lat, LT_lon, zoom)  # 下载切片的左上角角点

    rightbottom = deg2num(RB_lat, RB_lon, zoom)

    print(str(zoom))     

    print(str(lefttop[0]))

    print(str(rightbottom[0]))

    print(str(lefttop[1]))

    print(str(rightbottom[1]))

    print("共" + str(lefttop[0] - rightbottom[0]))

    print("共" + str(lefttop[1] - rightbottom[1]))

    rootDir = "D:\\\\satellite\\\\"

    for x in range(lefttop[0], rightbottom[0]):

        path = rootDir + str(zoom) + "\\\\" + str(x)#文件夹检查

        if not os.path.exists(path):

            os.makedirs(path)

        for y in range(lefttop[1], rightbottom[1]):

            #谷歌地图url

            tilepath = "http://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&x="+ str(x) + "&y=" + str(y) + "&z=" + str(zoom)

            filepath = path + "\\\\" + str(y) + ".png"#文件检查

            if not os.path.isfile(filepath):

                getimg(tilepath, os.path.join(path, str(y) + ".png"), x, y)

    print('完成')

3.2、代码的优化和结果

        基于参考文章中的demo,其中存在一些问题,这里进行了一些优化:首先,代码固定,参数都需要手动调整。我这里进行了简单封装,并且对其中的区域范围坐标、数据层级别等参数进行传参处理。其次,getimg函数中递归运用存在一直失败不跳出的bug,这里增加了全局计数变量,使之失败一定次数后强制退出。最后,下载过程中断后,如果重新下载文件重复检查跳过下载,节省时间。

3.3、python完整工程代码和展望

import urllib.request

import os

import random

import math

import sys

count = 0  #用于getimg异常次数过多退出计数

agents = [

    'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/60.0.3112.101 Safari/537.36',

    'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5',

    'Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9',

    'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7',

    'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14',

    'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14',

    'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27',

    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1']



# 经纬度反算切片行列号 3857坐标系

def deg2num(lat_deg, lon_deg, zoom):

    lat_rad = math.radians(lat_deg)

    n = 2.0 ** zoom

    xtile = int((lon_deg + 180.0) / 360.0 * n)

    ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)

    return (xtile, ytile)



# 下载图片

def getimg(Tpath, Spath, x, y):

    global count

    count = 0 #清零

    try:

        f = open(Spath, 'wb')

        req = urllib.request.Request(Tpath)

        req.add_header('User-Agent', random.choice(agents))  #换用随机的请求头

        pic = urllib.request.urlopen(req, timeout=60)



        f.write(pic.read())

        f.close()

        print(str(x) + '_' + str(y) + '下载成功')

    except Exception:

        print(str(x) + '_' + str(y) + '下载失败,重试')#存在一直失败不跳出的bug

        getimg(Tpath, Spath, x, y)

        count = count + 1

        if count > 100:

           return



def download(k,LTlat,LTlon,RBlat,RBlon):

    zoom = k  #下载切片的zoom

    LT_lat = LTlat

    LT_lon = LTlon

    RB_lat = RBlat

    RB_lon = RBlon

    lefttop = deg2num(LT_lat, LT_lon, zoom)  # 下载切片的左上角角点

    rightbottom = deg2num(RB_lat, RB_lon, zoom)

    #35.56450, 108.17130/34.58190, 109.10290

    print(str(zoom))     

    print(str(lefttop[0]))

    print(str(rightbottom[0]))

    print(str(lefttop[1]))

    print(str(rightbottom[1]))

    print("共" + str(lefttop[0] - rightbottom[0]))

    print("共" + str(lefttop[1] - rightbottom[1]))



    rootDir = "D:\\\\satellite\\\\"



    for x in range(lefttop[0], rightbottom[0]):

        path = rootDir + str(zoom) + "\\\\" + str(x)#文件夹检查

        if not os.path.exists(path):

            os.makedirs(path)

        for y in range(lefttop[1], rightbottom[1]):

            #谷歌地图url

            tilepath = "http://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&x="+ str(x) + "&y=" + str(y) + "&z=" + str(zoom)

            #天地图的url(不知能否使用)

            #tilepath = "http://t3.tianditu.gov.cn/DataServer?T=cva_w&x=" + str(x) + "&y=" + str(y) + "&l=" + str(zoom)                     

            #getimg(tilepath, os.path.join(path, str(x) + "_" + str(y) + ".png"), x, y)

            filepath = path + "\\\\" + str(y) + ".png"#文件检查

            if not os.path.isfile(filepath):

                getimg(tilepath, os.path.join(path, str(y) + ".png"), x, y)

    print('完成')



arg1 = sys.argv[1]

arg2 = sys.argv[2]

#34.7,108.5/34.3,109.5

LT_lat = 34.7

LT_lon = 108.5

RB_lat = 34.3

RB_lon = 109.5



level1 = int(arg1)

level2 = int(arg2)



for i in range(level1,level2):  

    delta_lat = LT_lat - RB_lat

    delta_lon = RB_lon - LT_lon

    #print(str(delta_lat))

    #print(str(delta_lon))

    if i > 15:

        print(str(i))

        LT_lat = LT_lat - delta_lat * 1/4

        LT_lon = LT_lon + delta_lon * 1/4

        RB_lat = RB_lat + delta_lat * 1/4

        RB_lon = RB_lon - delta_lon * 1/4

    print(str(LT_lat))

    print(str(LT_lon))

    print(str(RB_lat))

    print(str(RB_lon))

    download(i,LT_lat,LT_lon,RB_lat,RB_lon)

        对于瓦片这样海量的数据来说,层级越高,数据量越大,消耗的时间越多。从上面函数中可见提供了一种策略:15层以后,每层数据规模缩小到上一层的1/4(这个根据需求删减)。

        其中也只是放开了两个参数,控制需要下载的层级数目,完善的软件则可以放开七个参数,即把区域范围坐标点以及数据类型也可以通过外部传入(后续完善后会上传资源)。

        最后,下载海量的数据耗时仍然十分严重,可以考虑采取多线程的方式优化代码(未实现)。当然,如果不考虑范围的话,为了提高时间效率,也是可以手动开启多个下载任务的呀(如下图,会节省一些时间)。这就离不开python代码生成exe在cmd上调用了。

 4、Python工程生成exe以及调用

         具体参考:https://blog.csdn.net/nanke_yh/article/details/120811243

4.1、工程外部参数输入改写

        这里主要只是放开了两个参数,控制需要下载的层级数目。我们也可以放开六个参数,即把区域范围坐标点也可以通过外部传入。

        当然,对于下载中断后(网络原因),需要重新继续下载的,那么直接根据切片的x、y取值范围以及层级等参数,直接继续获取即可。

 4.2、exe生成和调用

        打包exe:Pyinstaller -F filename.py

        Cmd中调用(exe路径下,参数有几个后面按顺序加上,中间空格隔开):

        filename.exe arg1 arg2

以上是关于亲自实践能够下载的谷歌地图切片url地址谷歌地图数据下载的尝试以及Python爬虫实现的主要内容,如果未能解决你的问题,请参考以下文章

在浏览器中打开带有特定地址的谷歌地图[关闭]

谷歌地理编码 API 不如使用地址的谷歌地图准确

使用适用于 iOS 的谷歌地图 SDK 进行标记聚类?

使用特定城市的谷歌地图 API 获取自动完成的地址

HTC g14自带的谷歌手机地图的文件夹是那一个?我想下下载一个全国离线地图包要怎么安装才能使用?

上面有布局层的谷歌地图