[Python抓取网站数据_1]——之离散天地图瓦片爬取
1. 写在前面
需求:
- 获取各层级天地图矢量、影像瓦片数据;
- 满足后续Geoserver地图发布服务;
- 可针对某重点区域进行定期更新
技术难点:
- 地图为海量级,如何确定下载范围并便于后续地图更新服务
2. 天地图网站解析
2.1 天地图服务
天地图地图服务采用OGC WMTS标准,具体使用方法请参考OGC WMTS标准 中GetCapabilities 和GetTile(此内容后续会更新)。其官网对外提供了地图服务的API天地图API (tianditu.gov.cn)。并且针对不同的地图服务,提供了供开发人员使用的服务地址,如下图:
并且为开发人员提供了地图瓦片获取的请求示例:
2.2 解析天地图元数据
基于天地图公开的元数据,我们可以获取天地图坐标投影(ESPG::900913)、地图范围、各层级瓦片数量与瓦片大小,以及各层级的缩放比例。
通过元数据中瓦片不同层级下的Tile数量,不难看出随着层级的增加,天地图瓦片数量从1至18级呈几何倍数在增长,如下图:
2.3 天地图网站后台解析
2.3.1 矢量底图
通过解析天地图网站后台,可以看出在该服务请求下对应的内容。
【对应请求网址】——矢量:
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”
【对应请求网址】—影像:
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. 天地图瓦片规则
基于以上介绍,我们已经能顺利获取到不同层级下,不同行列的矢量瓦片、矢量标注、影像瓦片以及影像标注。但如何将获取的瓦片有序进行整理并组合为一幅完整的地图,这需要对天地图瓦片规则进行分析。
如下图所示,天地图瓦片行列排列是从左上角开始:
具体效果如图:
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()