亲自实践能够下载的谷歌地图切片url地址谷歌地图数据下载的尝试以及python爬虫实现(代码片段)

nanke_yh nanke_yh     2023-03-11     415

关键词:

目录

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

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

】谷歌地理编码API不如使用地址的谷歌地图准确【英文标题】:googlegeocodingapinotasaccurateasgooglemapsusingaddress【发布时间】:2016-03-1313:28:15【问题描述】:我有很多例子,其中谷歌地图返回确切位置,而地理编码无法找到完全匹配... 查看详情

上面有布局层的谷歌地图

...它上面有一个框架布局。我的要求是我希望我的谷歌地图能够像滑动缩放一样工作,即使我上面有Framelayout也是如此。下面是示例代码<?xmlversi 查看详情

Android 中的谷歌地图本地化

】Android中的谷歌地图本地化【英文标题】:GooglemaplocalizationinAndroid【发布时间】:2019-12-3107:36:17【问题描述】:我正在开发一个android应用程序,我想在GoogleMap中显示用户本地化地址,这与MapsApp相同,其中将显示英文和本地化地... 查看详情

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

...行分组-基本上需要使用标记聚类,如附加url中所示。我能够在Android地图SDK中获得此功能,但我没有找到任何适用于iOS谷歌地图SDK的库。您能 查看详情

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

】使用特定城市的谷歌地图API获取自动完成的地址【英文标题】:FetchautocompletedaddressusinggooglemapAPIforparticularcity【发布时间】:2020-05-2101:10:58【问题描述】:我正在构建一个android应用程序,我在其中使用谷歌地图API来获取位置。... 查看详情

新的谷歌地图标记

】新的谷歌地图标记【英文标题】:NewGoogleMapsMarker【发布时间】:2014-05-2320:29:28【问题描述】:任何人都知道此图标的URL,如果您可以更改最新版本的GoogleMapsAPI的颜色?我想要一个像下面这样的蓝色/绿色图标!编辑---------------... 查看详情

使用文本地址的谷歌地图街景地图

】使用文本地址的谷歌地图街景地图【英文标题】:StreetViewMapwithGoogleMapsUsingTextAddress【发布时间】:2018-04-2113:56:20【问题描述】:我的wordpress单个帖子页面上有一个谷歌地图,它从2个自定义字段中获取地址。它工作正常,但现... 查看详情

带有标记的谷歌地图没有出现地图

】带有标记的谷歌地图没有出现地图【英文标题】:googlemapwithmarkernotappearmap【发布时间】:2020-03-0903:01:33【问题描述】:当我单击地址时,我一直试图在地图上显示一个标记,但地图没有显示。<divclass="gmap_canvas"><divid="g-m... 查看详情

用于场地的谷歌地图地理编码器

】用于场地的谷歌地图地理编码器【英文标题】:GoogleMapsgeocoderforvenues【发布时间】:2011-03-2209:40:09【问题描述】:我正在寻找一种使用谷歌地图对场地进行地理编码的方法。GeocoderAPI仅提供使用地址进行地理编码的能力。但是... 查看详情

如何从 PHP 输入表单中获取城市的谷歌地图?

】如何从PHP输入表单中获取城市的谷歌地图?【英文标题】:HowtogetgooglemapsfromcitygotfromaPHPinputform?【发布时间】:2013-08-1912:50:05【问题描述】:我正在尝试根据表单提交的IP地址地理位置获取显示位置信息的Google地图。下面的PHP... 查看详情

在android中的谷歌地图上绘制点

...述】:我正在将Google地图与我的android应用程序集成。我能够在地图视图中完美地显示地图。现在我需要根据获取方向在该地图上绘制点。任何有效的示例代码都会对我有很大帮助。在这个问题上我需要一些帮助。请指导。谢谢... 查看详情

我需要从使用 msa 和 msid 的谷歌地图 url 中提取经纬度数据

】我需要从使用msa和msid的谷歌地图url中提取经纬度数据【英文标题】:Ineedtoextractlatlongdatafromagooglemapsurlthatusesmsaandmsid【发布时间】:2015-06-0220:35:45【问题描述】:当包装一些网页时,我得到了一个像这样的iframe:<iframeframebord... 查看详情

带有多个标记的谷歌地图自动中心

】带有多个标记的谷歌地图自动中心【英文标题】:Googlemapautocenterwithmultiplemarkers【发布时间】:2018-05-1312:39:35【问题描述】:我创建了一个地图以将我的搜索结果显示为地图上的标记,它几乎可以完美运行,但是自动居中/缩放... 查看详情

无法从android中的谷歌地图获取地点数据

...是当我使用用户的API密钥学习在android中显示地图时,我能够获取数据。)我已经做过的事情:从谷歌云控制台启用MapAPI和PlaceAPI设置结算帐号代码XML文 查看详情

保存要离线加载的谷歌地图图像

】保存要离线加载的谷歌地图图像【英文标题】:SaveImageofGooglemaptobeloadedoffline【发布时间】:2016-12-0605:43:02【问题描述】:我在ipad的Ionic应用程序(连接到NodeJS/Express)中使用Google地图。在应用程序中,我正在为用户提供的地址... 查看详情

如何在新的谷歌地图中找到 panoID?

】如何在新的谷歌地图中找到panoID?【英文标题】:HowtofindpanoIDinanewGooglemaps?【发布时间】:2015-05-1421:26:08【问题描述】:PanoID用于在经典地图的URL中轻松找到Photosphere/GoogleBusinessView镜头。不幸的是,它们不再可用。有谁知道如... 查看详情

从 php 中的谷歌地图获取国家名称

】从php中的谷歌地图获取国家名称【英文标题】:Getcountrynamefromgooglemapsinphp【发布时间】:2018-02-2109:43:58【问题描述】:我有用户IP地址。我想要那个用户的国家名称。我不想在php中使用geoIp(plugin)所以有没有办法在没有JS支持的... 查看详情

使用片段的谷歌地图

】使用片段的谷歌地图【英文标题】:GoogleMapsUsingFragments【发布时间】:2018-12-0619:32:03【问题描述】:我在片段中使用谷歌地图(导航抽屉)。当应用程序启动时,第一个片段与谷歌地图一起显示。我已经在onViewCreated方法中初... 查看详情