如何用Python+Google Static Map API获取大范围建筑级缩放地图?
问题解决指南
一、获取精确相邻的建筑级缩放地图
要实现多张地图精确衔接,核心是基于经纬度计算每张地图的中心坐标——用地名做中心无法保证精度,必须转成经纬度来控制偏移。
关键原理
Google Static Map在固定缩放级别下,每张图覆盖的经纬度范围是固定的:
- 缩放级别
zoom时,地球表面被划分为2^zoom × 2^zoom个基础瓦片(256x256像素) - 640x640的地图是2.5倍基础瓦片尺寸,可通过像素与经纬度的换算关系,计算出每张图的偏移量。
实操代码
import requests import math api_key = "YOUR_API_KEY" base_url = "https://maps.googleapis.com/maps/api/staticmap?" # 1. 先通过地理编码获取目标区域中心的经纬度(示例为Binche的坐标) center_lat = 50.4938 center_lon = 4.2822 zoom = 20 # 建筑级缩放 map_size = "640x640" label_style = "&style=feature:all|element:labels|visibility:off" # 2. 计算当前缩放级别下,每张地图的经纬度偏移量 pixel_per_degree_lon = (2 ** zoom) * 256 / 360 pixel_per_degree_lat = (2 ** zoom) * 256 / (360 * math.cos(math.radians(center_lat))) lon_offset = 640 / pixel_per_degree_lon # 横向(经度)偏移 lat_offset = 640 / pixel_per_degree_lat # 纵向(纬度)偏移 # 3. 计算覆盖100km范围所需的瓦片数量(100km≈0.9度经纬度) target_km = 100 lon_range = target_km / 111.32 # 赤道上1度经度≈111.32km lat_range = target_km / 111.32 # 纬度方向1度≈111km num_tiles_lon = math.ceil(lon_range / lon_offset) num_tiles_lat = math.ceil(lat_range / lat_offset) # 4. 循环生成所有相邻地图 for i in range(-num_tiles_lon//2, num_tiles_lon//2 + 1): for j in range(-num_tiles_lat//2, num_tiles_lat//2 + 1): current_lat = center_lat + j * lat_offset current_lon = center_lon + i * lon_offset request_url = f"{base_url}center={current_lat:.6f},{current_lon:.6f}&zoom={zoom}&size={map_size}&key={api_key}{label_style}" response = requests.get(request_url) # 按坐标命名保存,方便后续拼接 filename = f"Binche_zoom{zoom}_lat{current_lat:.4f}_lon{current_lon:.4f}.png" with open(filename, 'wb') as file: file.write(response.content)
二、Google Static Map API的成本评估
这个方案成本极高,完全不适合覆盖100km范围的需求:
- 免费额度仅每月1000次请求,超出后每1000次收费约7美元
- 缩放级别20时,每张640x640地图仅覆盖约0.03km×0.03km的区域,100km×100km的范围需要约110万次请求,总成本超过7000美元。
三、低成本/免费替代方案
1. OpenStreetMap(OSM)公开瓦片服务
完全免费,无请求次数限制(需遵守OSM使用规范:不要批量高频请求),直接获取瓦片后可拼接成大图。
import requests import math def latlon_to_tile(lat, lon, zoom): # 将经纬度转换为OSM瓦片的x、y坐标 lat_rad = math.radians(lat) n = 2.0 ** zoom x = int((lon + 180.0) / 360.0 * n) y = int((1.0 - math.log(math.tan(lat_rad) + 1/math.cos(lat_rad))/math.pi) / 2.0 * n) return x, y zoom = 20 center_lat = 50.4938 center_lon = 4.2822 center_x, center_y = latlon_to_tile(center_lat, center_lon, zoom) # 按需设置需要的瓦片数量(示例取20×20片) tile_count = 20 for x in range(center_x - tile_count//2, center_x + tile_count//2 + 1): for y in range(center_y - tile_count//2, center_y + tile_count//2 + 1): tile_url = f"https://tile.openstreetmap.org/{zoom}/{x}/{y}.png" response = requests.get(tile_url) with open(f"OSM_tile_{zoom}_{x}_{y}.png", 'wb') as file: file.write(response.content)
可使用PIL库将多张256x256的瓦片拼接成完整大图。
2. 本地离线渲染地图
如果需求极大,建议下载OSM离线数据(从Geofabrik获取分区数据),用Mapnik、TileMill等工具本地渲染瓦片,完全免费且不受请求限制。
3. Mapbox Static Tiles
适合商业项目,每月有50000次免费请求,超出后收费较低,逻辑与OSM类似,通过经纬度转瓦片坐标获取相邻区域。
内容的提问来源于stack exchange,提问作者Zartox29
相关产品推荐
相关产品推荐

