第一期:Google 谷歌地图(高德地图)瓦片下载/缓存,使用Python实现(一)_谷歌瓦片地图-CSDN博客
第三期 Google 谷歌地图(高德地图)瓦片下载/缓存,使用Python实现、arcgis.js(三)-CSDN博客
第四期 Google 谷歌地图(高德地图)瓦片下载/缓存,使用Python实现、自定义上传地图瓦片资源(四)-CSDN博客
后面还会出第三期文章,请多多关注
1、分析地图瓦片URL地址
谷歌瓦片地图URL:
https://mt2.google.com/vt?lyrs=s,m&x=1083&y=1666&z=12&hl=zh&gl=cn
分析:
服务器地址:https://mt{num}.google.com/vt?lyrs={lyrs}&x={x}&y={y}&z={z}&hl={hl}&gl={gl}
a) num不同服务器,范围为 0,1,2,3
b) lyrs地图类型:
m:路线图
t:地形图
p:带标签的地形图
s:卫星图
y:带标签的卫星图
h:标签层(路名、地名等)
地图类型可以组合使用,中间使用,(英文逗号)分割
c) hl: host language(interface languages) 本地语言
比如 zh-CN,zh-TW,en
d) gl: 国家码(country code)
比如 cn us
e) x y z 放到高德地图分析一起讲
更多具体的hl,gl参数可以参考:XML API reference appendices | Programmable Search Engine | Google for Developers
高德瓦片地图URL:
https://webst02.is.autonavi.com/appmaptile?style=6&x=423&y=192&z=9
分析:
服务器地址:https://webst{num}.is.autonavi.com/appmaptile?style={style}&x={x}&y={y}&z={z}
a) num不同服务器,范围 01,02,03,04
b)style 地图类型
6:卫星影像
7:矢量底图
8:路网注记
c) x,y,z
z代表地图比例尺,z值越小,地图比例尺越大,z值越大,地图比例尺越小。
z的范围为[0,18]
x,y的取值范围为z有关
z为0,x,y 0
z为1, x,y 0-1
z为2, x,y 0-3
z为3, x,y 0-7
…
z为n,,x,y [0,2^n-1]
下面用2张图解释
注:如果下载地址出现问题了:1、URL地址已经更新了;2、需要带上验证的key值
2、代码实现
注意:很多人发现下载Google地图的时候会报错,这其实是因为访问Google地图是需要科学上网才能够访问的。
HTTPSConnectionPool(host='mt3.google.com', port=443): Max retries exceeded with url:....
这时我们就需要配置好代理端口,使的python的请求工具(requests)可以访问Google地图。
可以在调用下载谷歌地图方法的时候设置 proxies 参数
# 这里的端口号请写你自己软件的软件的端口号,否则也无法下载
proxies = {
"http": "http://127.0.0.1:1234",
"https": "http://127.0.0.1:1234"
}
x1 = 54658
y1 = 26799
z1 = 16
savePath1, urlStr1 = MapDownloadUtils.googleMapDownload(x1, y1, z1,proxies=proxies)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import math
import random
import requests
import os
class MapDownloadUtils(object):
"""
"""
@staticmethod
def requestLoadImg(url, headers=None, proxies=None):
"""
请求加载Img,返回响应字典 response
:param url: 下载地址
:param headers: 请求头
:param proxies: 代理
:return: response 响应字典
"""
if headers is None:
headers = {"Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"}
# 这里就看你自己是否需要开启代理
# 此方法中的googleMap url 下载地址是需要开启代理的
# if proxies is None:
# proxies = {
# "http": "http://127.0.0.1:1234",
# "https": "http://127.0.0.1:1234"
# }
return requests.get(url, stream=True, headers=headers, proxies=proxies)
@staticmethod
def saveFileImg(savePath, fileResponse):
"""
保存图片
:param savePath: 保存路径
:param fileResponse: response 字典
:return: 无,可能会报无权限错误
"""
pathIndex = savePath.rfind("/")
os.makedirs(savePath[0:pathIndex], exist_ok=True)
with open(savePath, 'wb') as img_file:
for chunk in fileResponse.iter_content(chunk_size=1024):
img_file.write(chunk)
@staticmethod
def googleMapDownload(x, y, z, lyrs="s", hl="zh-CN", gl="cn", httpParameter=None, headers=None, proxies=None):
"""
下载google地图
:param x: 坐标
:param y: 坐标
:param z: 坐标
:param lyrs: 地图类型
:param hl: host language(interface languages) 本地语言 ( zh-CN, zh-TW, en)
:param gl: 国家码(country code) (cn,us)
:param httpParameter: 可添加更多参数 &a=1&b=2&...
:param headers: 请求头
:param proxies: 代理
:return:savePath(保存地图), urlStr(请求地址)
"""
if httpParameter is None:
httpParameter = "&lyrs=" + str(lyrs) + "&hl=" + str(hl) + "&gl=" + str(gl)
else:
httpParameter = httpParameter + "&lyrs=" + str(lyrs) + "&hl=" + str(hl) + "&gl=" + str(gl)
return MapDownloadUtils.mapDownload(x, y, z, "googleMap", str(lyrs), httpParameter, headers, proxies)
@staticmethod
def AMapDownload(x, y, z, style="6", httpParameter=None, headers=None, proxies=None):
"""
下载高德地图
:param x: 坐标
:param y: 坐标
:param z: 坐标
:param style: 地图类型
:param httpParameter: 可添加更多参数 &a=1&b=2&...
:param headers: 请求头
:param proxies: 代理
:return:savePath(保存地图), urlStr(请求地址)
"""
if httpParameter is None:
httpParameter = "&style=" + str(style)
else:
httpParameter = httpParameter + "&style=" + str(style)
return MapDownloadUtils.mapDownload(x, y, z, "AMap", style, httpParameter, headers, proxies)
@staticmethod
def mapDownload(x, y, z, mapOrg, subFolderName=None, httpParameter=None, headers=None, proxies=None):
"""
下载高德地图
:param x: 坐标
:param y: 坐标
:param z: 坐标
:param mapOrg: 地图提供商
:param subFolderName: 保存文件夹子路径
:param httpParameter: 可添加更多参数 a=1&b=2&...
:param headers: 请求头
:param proxies: 代理
:return: savePath(保存地图), urlStr(请求地址)
"""
savePath = ""
urlStr = ""
if mapOrg == "googleMap":
serverNum = random.randint(0, 3)
urlStr = f"https://mt{serverNum}.google.com/vt?x={x}&y={y}&z={z}" \
.replace("{serverNum}", str(serverNum)).replace("{x}", str(x)) \
.replace("{y}", str(y)).replace("{z}", str(z))
if httpParameter is not None:
urlStr += httpParameter
elif mapOrg == "AMap":
serverNum = random.randint(1, 4)
urlStr = f"https://webst0{serverNum}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}" \
.replace("{serverNum}", str(serverNum)).replace("{x}", str(x)) \
.replace("{y}", str(y)).replace("{z}", str(z))
if httpParameter is not None:
urlStr += httpParameter
response = MapDownloadUtils.requestLoadImg(urlStr, headers, proxies)
# 检查响应状态码是否正常
if response.status_code == 200:
contentType = response.headers.get('content-type')
fileSuffix = contentType.split("/")[1]
if subFolderName is not None:
savePath = mapOrg + "/" + str(subFolderName) + "/" + str(z) + "/" + str(x) + "/" + str(
y) + "." + fileSuffix
else:
savePath = mapOrg + "/" + "/" + str(z) + "/" + str(x) + "/" + str(y) + "." + fileSuffix
MapDownloadUtils.saveFileImg(savePath, response)
return savePath, urlStr
else:
print(f"response.status_code {response.status_code}")
return savePath, urlStr
# 经纬度转瓦片
@staticmethod
def lnglatToTile(lng, lat, zoom):
"""
WGS-84 坐标系
:param lng: 经度
:param lat: 纬度
:param zoom: 缩放
:return:
"""
tileX = int((lng + 180) / 360 * math.pow(2, zoom))
tileY = int((1 - math.asinh(math.tan(math.radians(lat))) / math.pi) * math.pow(2, zoom - 1))
return tileX, tileY
# 瓦片转经纬度
@staticmethod
def tileToLnglat(tileX, tileY, zoom):
"""
:param tileX:
:param tileY:
:param zoom:
:return: WGS-84 坐标系
"""
lng = tileX / math.pow(2, zoom) * 360 - 180
lat = math.degrees(math.atan(math.sinh(math.pi * (1 - 2 * tileY / math.pow(2, zoom)))))
return lng, lat
# 瓦片坐标的像素坐标转经纬度
@staticmethod
def pixelToLnglat(tileX, tileY, pixelX, pixelY, level):
lng = (tileX + pixelX / 256) / math.pow(2, level) * 360 - 180
lat = math.degrees(math.atan(math.sinh(math.pi - 2 * math.pi * (tileY + pixelY / 256) / math.pow(2, level))))
return lng, lat
if __name__ == '__main__':
x1 = 54658
y1 = 26799
z1 = 16
savePath1, urlStr1 = MapDownloadUtils.googleMapDownload(x1, y1, z1)
print(f"savePath1 {savePath1}")
print(f"urlStr1 {urlStr1}")
savePath1, urlStr1 = MapDownloadUtils.AMapDownload(x1, y1, z1)
print(f"savePath1 {savePath1}")
print(f"urlStr1 {urlStr1}")
lng1 = 116.391135
lat1 = 39.911290
zoom1 = 11
tileX1, tileY1 = MapDownloadUtils.lnglatToTile(lng1, lat1, zoom1)
print(f"tileX1 {tileX1}")
print(f"tileY1 {tileY1}")
lng1, lat1 = MapDownloadUtils.tileToLnglat(tileX1, tileY1, zoom1)
print(f"lng1 {lng1}")
print(f"lat1 {lat1}")
lng1 = 116.3671875
lat1 = 40.044437584608566
tileX11, tileY11 = MapDownloadUtils.lnglatToTile(lng1, lat1, zoom1)
print(f"tileX11 {tileX11}")
print(f"tileY11 {tileY11}")
x1 = tileX1
y1 = tileY1
z1 = zoom1
savePath1, urlStr1 = MapDownloadUtils.AMapDownload(x1, y1, z1)
print(f"savePath1 {savePath1}")
print(f"urlStr1 {urlStr1}")
savePath1, urlStr1 = MapDownloadUtils.googleMapDownload(x1, y1, z1)
print(f"savePath {savePath1}")
print(f"urlStr {urlStr1}")
3、参考链接
https://blog.csdn.net/u010624047/article/details/126346382
2、瓦片地图服务参数与计算_wmts参数:计算瓦片比例尺和分辨率?-CSDN博客
https://blog.csdn.net/u013929284/article/details/53614281
3、瓦片地图服务与地图瓦片原理 - 脉脉 (maimai.cn)
https://maimai.cn/article/detail?fid=1773433535&efid=pauWgeGf66NzgO2snJZnSQ
4、HTTP请求中hl参数和gl参数的含义_链接里边的hl和gl分别是什么意思-CSDN博客
https://blog.csdn.net/wusuopuBUPT/article/details/16886193
5、XML API reference | Programmable Search Engine | Google for Developers
https://developers.google.com/custom-search/docs/xml_results?hl=en&csw=1
6、国内常用地图瓦片源地址汇总 - 知乎 (zhihu.com)
https://zhuanlan.zhihu.com/p/641436984
7、高德地图url简介 - MaxLucio - 博客园 (cnblogs.com)
https://www.cnblogs.com/lucio110/p/17310054.html