Google 谷歌地图(高德地图)瓦片下载/缓存,使用Python实现(二)

第一期: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张图解释

瓦片图层大小与关系
z轴与x,y的对应关系

注:如果下载地址出现问题了:1、URL地址已经更新了;2、需要带上验证的key值

2、代码实现

#!/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、参考链接

1、google地图瓦片地址_谷歌瓦片地图-CSDN博客

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

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用Python爬取高德地图的XYZ瓦片,可以使用以下步骤进行操作: 1. 导入必要的库和模块,包括`requests`用于发送HTTP请求,`Pillow`用于处理图像数据。 2. 构建请求URL。高德地图的XYZ瓦片URL格式为:`http://wprd03.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}`,其中`{x}`表示瓦片的x坐标,`{y}`表示y坐标,`{z}`表示缩放级别。 3. 使用循环遍历需要下载瓦片的x和y坐标,并发送GET请求获取瓦片数据。可以根据具体情况设定循环范围和缩放级别。 4. 将获取到的瓦片数据保存为图片文件。可以使用`Pillow`库的`Image`模块将数据解码为图片,然后保存到本地文件夹中。 下面是一个简单的Python代码示例: ```python import requests from PIL import Image # 构建请求URL url_template = "http://wprd03.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}" # 设置需要下载瓦片的范围和缩放级别 min_x = 0 max_x = 10 min_y = 0 max_y = 10 zoom_level = 10 # 循环遍历需要下载瓦片 for x in range(min_x, max_x+1): for y in range(min_y, max_y+1): # 构建请求URL url = url_template.format(x=x, y=y, z=zoom_level) # 发送GET请求获取瓦片数据 response = requests.get(url) # 将获取到的瓦片数据保存为图片文件 file_name = f"tile_{zoom_level}_{x}_{y}.png" with open(file_name, "wb") as f: f.write(response.content) print("瓦片下载完成。") ``` 上述代码将会下载高德地图的XYZ瓦片,保存为相应的图片文件,图片文件的命名格式为`tile_{缩放级别}_{x坐标}_{y坐标}.png`。根据实际需求,可以调整代码中的循环范围、URL模板、保存文件的路径等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值