Fork me on GitHub

[Python抓取网站数据_1]——之离散天地图瓦片爬取

1. 写在前面

需求

  • 获取各层级天地图矢量影像瓦片数据
  • 满足后续Geoserver地图发布服务;
  • 可针对某重点区域进行定期更新

技术难点

  • 地图为海量级,如何确定下载范围并便于后续地图更新服务

1662533534945

2. 天地图网站解析

2.1 天地图服务

天地图地图服务采用OGC WMTS标准,具体使用方法请参考OGC WMTS标准 中GetCapabilities 和GetTile(此内容后续会更新)。其官网对外提供了地图服务的API天地图API (tianditu.gov.cn)。并且针对不同的地图服务,提供了供开发人员使用的服务地址,如下图:

1662533601021

并且为开发人员提供了地图瓦片获取的请求示例:

1662533648608

2.2 解析天地图元数据

基于天地图公开的元数据,我们可以获取天地图坐标投影(ESPG::900913)、地图范围、各层级瓦片数量与瓦片大小,以及各层级的缩放比例。

1662533697093

1662533702610

通过元数据中瓦片不同层级下的Tile数量,不难看出随着层级的增加,天地图瓦片数量从1至18级呈几何倍数在增长,如下图:

1662533798180

2.3 天地图网站后台解析

2.3.1 矢量底图

通过解析天地图网站后台,可以看出在该服务请求下对应的内容。

1662534268077

【对应请求网址】——矢量

https://t3.tianditu.gov.cn/vec/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL=52162&TILEROW=27130&TILEMATRIX=16&tk={My tk}

【对应请求网址】——矢量注记

https://t3.tianditu.gov.cn/cva/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL=52162&TILEROW=27130&TILEMATRIX=16&tk={My tk}

通过分析可以看出该请求主要有如下关键信息:

  • <t*>: 表示天地图地图服务二级域名包括t0-t7,可以随机选择使用
  • : 图层内容(详见上述地图服务列表
  • : 瓦片行数
  • : 瓦片列数
  • 瓦片层级
  • : 需要本人通过开发者

因此,仅需要更改[ TILECOL, TILEROW, TILEMATRIX]便可获取不同瓦片。

2.3.2 影像底图

影像底图也类似于矢量底图。只不过将修改为“img”

1662535336397

【对应请求网址】—影像

https://t6.tianditu.gov.cn/img/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL=104327&TILEROW=54261&TILEMATRIX=17&tk={My tk}

【对应请求网址】—影像注记

https://t6.tianditu.gov.cn/cia/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL=104327&TILEROW=54261&TILEMATRIX=17&tk={My tk}

3. 天地图瓦片规则

基于以上介绍,我们已经能顺利获取到不同层级下,不同行列的矢量瓦片、矢量标注、影像瓦片以及影像标注。但如何将获取的瓦片有序进行整理并组合为一幅完整的地图,这需要对天地图瓦片规则进行分析。

如下图所示,天地图瓦片行列排列是从左上角开始

1662534066378

具体效果如图:

1662536093803

4. 天地图爬取

在bilibili这么多之后,最重要的是要将数据爬取下来,供我们后续的使用。

由于天地图后台增加了许多反爬虫机制,因此在外部我们无法直接通过上述的请求网站进行直接访问。

  • 首先需要先定义访问头:
headers = {
 'Host': "t0.tianditu.gov.cn",
 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47",
 'Cookie': "HWWAFSESID=44a6d8b1b8eb7d6335; HWWAFSESTIME=1660715969030; TDTSESID=rBACBGL8g8RStC+/gJUJAg==",
 'Referer': 'https://www.tianditu.gov.cn/'
}

其中可根据自己网站访问后天进行更换。

  • 最后获取请求:
src = f'http://t0.tianditu.gov.cn/{layer}_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER={layer}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={col}&TILEROW={row}&TILEMATRIX={level}&tk={tk}'

# 获取请求
response = requests.get(src, headers=headers)

附录

在这里,我把本次天地图爬取的主要代码放在下面,供大家交流与使用~~

## 获取请求
@retry(wait=wait_fixed(1))
def custom_get(col, row, level, layer):
    """
    输入下载行列、缩放等级
    下载瓦片数据(注记,cva;矢量图,vec)
    """
    level = level + 3
    tk = choice(tianTokens)
    
    src = f'http://t0.tianditu.gov.cn/{layer}_w/wmts?  SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=  {layer}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={col}&TILEROW={row}&TILEMATRIX={level}&tk={tk}'
    response = requests.get(src, headers=headers)
    assert response.status_code == 200
    return response

## 下载前校验
def checkFile(path, file):
    """
    下载前校验文件夹中是否存在该文件
    """
    # 不存在文件夹则创建文件夹,并返回false
    if not os.path.exists(path):
        os.makedirs(path)
        return False
    # 存在文件夹但不存在文件,返回false
    elif not os.path.exists(path+file):
        return False
    # 存在文件夹且存在文件,返回true
    else:
        return True

def downloadTwo(path, col, row, level, layer):
    """
    传入下载路径(path)、瓦片行列数(x,y)、层级(z)
    """
    path = path + "{level}\\".format(level = level)
    file = "{col}_{row}.png".format(col=col, row=row)
    
    if(checkFile(path, file)):
        return
    
    # 下载街道地图、或者文字注记
    img_response = custom_get(col, row, level, layer)
    # 保存图片
    
    with open(path+file, "wb") as f:
            
            f.write(img_response.content)
            f.close()
posted @ 2022-09-07 15:57  chZZZwx  阅读(2242)  评论(0)    收藏  举报