百度地图瓦片下载工具:离线地图瓦片抓取与MBTiles打包实战

发布时间:2026/10/20 6:51:29

百度地图瓦片下载工具:离线地图瓦片抓取与MBTiles打包实战 简介百度地图瓦片下载工具是一套面向离线地图开发者与GIS应用人员的实用资源用于批量获取百度地图瓦片数据解决无网络环境下地图底图缺失、加载缓慢的问题。工具围绕坐标转换、范围选择、级别设定与批量下载等环节设计可依据经纬度或行政区域自动计算对应级别的瓦片并支持将零散图片整合为完整离线地图适用于离线导航、地图应用开发、地理数据分析及应急救援等场景。压缩包共3个文件包含1个可执行jar程序、1个properties配置文件和1个使用说明txt整体约5.05MB体积轻便解压后即可按说明配置运行。目前已有5544人学习下载说明其在离线地图数据获取方面具备一定参考价值。读者可借此了解瓦片组织逻辑与坐标转换思路快速搭建本地地图数据源降低开发与调试成本。1. 地图瓦片下载工具到底在解决什么问题做 GIS 可视化、离线地图或者内网环境部署的同行大概率都遇到过同一个尴尬项目现场没有外网或者带宽小得可怜地图底图加载转圈转到让人怀疑人生。这时候「百度地图瓦片下载工具.zip」这类东西就会被翻出来。它本质上不是某个官方产品而是一类把在线地图按瓦片规则抓下来、存成本地目录或 MBTiles 的小工具集合。核心价值就一句话把「联网才能看的地图」变成「断网也能用的本地瓦片库」。它适合三类人一是做内网 GIS 系统的开发者二是需要离线底图做演示或应急的集成人员三是想研究瓦片金字塔结构、自己写下载器的学习者。但这里有个前提必须先说清楚——瓦片下载涉及地图服务的使用条款个人学习和小范围内部测试是一回事公开分发或商用是另一回事动手前先确认自己的使用场景是否合规。这篇笔记只讲技术实现路径不替任何人做合规判断。2. 瓦片金字塔与百度地图的坐标规则先搞懂再动手2.1 瓦片编号是怎么算出来的在线地图的底图不是一张大图而是按层级切好的正方形小图标准是 256×256 像素。层级 z 从 0 开始z0 时整个世界就是一张瓦片z1 变成 2×2z2 变成 4×4到 z18 时瓦片数量已经是 2^18 × 2^18量级非常恐怖。每一张瓦片用 (z, x, y) 三个整数唯一标识x 是列号从左往右y 是行号从上往下。百度地图的瓦片编号和通用的 Web 墨卡托也就是常说的 XYZ 方案不完全一样。通用方案里 y 是从上往下递增原点在左上角百度地图在部分层级和区域上做了偏移处理而且它的投影是 BD-09 坐标系下的墨卡托变体。这意味着你直接拿通用 XYZ 的公式去拼百度瓦片 URL下载下来的图大概率是错位的——这是新手最容易翻车的地方。常见做法是先确定你要下载的区域经纬度范围转成百度自己的瓦片编号再拼 URL。百度瓦片 URL 的典型形式是http://maponline{0-3}.bdimg.com/tile/?qttilex{x}y{y}z{z}stylespl其中{0-3}是负载均衡的服务器编号stylespl表示底图样式。这个 URL 结构会随服务调整变化所以工具里一般会把它做成可配置项而不是写死。2.2 经纬度转瓦片编号的代码实现下面这段 Python 是经纬度转百度瓦片编号的核心逻辑我一般会把它单独抽成一个模块方便复用和调试。import math # 百度地图瓦片编号计算 # 输入经度 lon、纬度 lat、层级 zoom # 输出该点所在的瓦片 (x, y) def lnglat_to_tile(lon, lat, zoom): # 百度地图的墨卡托投影参数 # 先把经纬度转成百度墨卡托米制坐标 x lon * 20037508.34 / 180.0 y math.log(math.tan((90.0 lat) * math.pi / 360.0)) / (math.pi / 180.0) y y * 20037508.34 / 180.0 # 根据层级计算瓦片分辨率 # 百度在 zoom 层级下的分辨率是 2^(18 - zoom) 米/像素 resolution 2 ** (18 - zoom) tile_size 256 # 每张瓦片 256 像素 # 瓦片编号 米制坐标 / (分辨率 * 瓦片像素) tile_x int((x 20037508.34) / (resolution * tile_size)) tile_y int((20037508.34 - y) / (resolution * tile_size)) return tile_x, tile_y # 测试北京某点层级 12 if __name__ __main__: tx, ty lnglat_to_tile(116.404, 39.915, 12) print(f瓦片编号: x{tx}, y{ty})这段代码的关键在resolution 2 ** (18 - zoom)这一行。百度地图在 zoom18 时分辨率是 1 米/像素每降一级分辨率翻倍所以 zoom12 时是 64 米/像素。tile_size固定 256两者相乘就是一张瓦片覆盖的实际米数。tile_x和tile_y的公式里x 方向加偏移量是因为墨卡托坐标原点在中心y 方向用减法是因为瓦片行号从上往下递增而墨卡托 y 轴向上为正。参数说明lon和lat必须是 BD-09 坐标如果你手里是 WGS-84 或 GCJ-02得先做坐标转换否则会有几十到几百米的偏差。zoom的取值范围一般是 3 到 18再高百度也不提供底图了。这个函数返回的是浮点运算后的整数截断边界情况正好落在瓦片分割线上可能差一张实际下载时建议对范围各外扩一张瓦片。2.3 下载范围怎么确定从矩形区域到瓦片列表确定了单点转瓦片的逻辑接下来要把一个矩形区域转成瓦片列表。思路很简单取区域左上角和右下角两个点分别算出它们的瓦片编号然后双重循环遍历。def tile_range(min_lon, min_lat, max_lon, max_lat, zoom): # 左上角对应 x 最小、y 最小 x_min, y_min lnglat_to_tile(min_lon, max_lat, zoom) # 右下角对应 x 最大、y 最大 x_max, y_max lnglat_to_tile(max_lon, min_lat, zoom) tiles [] for x in range(x_min, x_max 1): for y in range(y_min, y_max 1): tiles.append((zoom, x, y)) return tiles # 下载北京五环内某区域层级 14 tiles tile_range(116.20, 39.80, 116.55, 40.05, 14) print(f共需下载 {len(tiles)} 张瓦片)这里有个估算公式要记住瓦片总数 ≈ (x_max - x_min 1) × (y_max - y_min 1)。层级每加 1两个方向的瓦片数各翻倍总数变成 4 倍。层级 14 的一个小区域可能几百张层级 18 的同样区域就是几万张。下载前先用这个公式估一下量别贸然开跑。3. 下载器的工程实现并发、去重与断点续传3.1 单线程下载为什么不够用最朴素的下载器就是遍历瓦片列表逐个请求、逐个保存。写起来十行代码但实际跑起来你会想砸键盘——假设一张瓦片平均 200 毫秒一万张就是 2000 秒半个多小时。而且网络请求大部分时间在等 IOCPU 闲着纯属浪费。所以实际工具都会上并发。Python 里最省事的是concurrent.futures.ThreadPoolExecutor因为下载是 IO 密集型任务线程池足够用不用上多进程。并发数一般设 8 到 16再高容易被服务端限流甚至封 IP。我一般从 8 开始试观察有没有大量超时或 403再决定要不要往上加。import os import requests from concurrent.futures import ThreadPoolExecutor, as_completed # 瓦片保存根目录 TILE_ROOT ./baidu_tiles # 并发线程数建议 8-16 MAX_WORKERS 8 # 请求头模拟浏览器 HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64), Referer: http://map.baidu.com/ } def download_tile(tile): z, x, y tile # 按层级和行列组织目录方便后续发布 save_dir os.path.join(TILE_ROOT, str(z), str(x)) os.makedirs(save_dir, exist_okTrue) save_path os.path.join(save_dir, f{y}.png) # 断点续传文件已存在且非空则跳过 if os.path.exists(save_path) and os.path.getsize(save_path) 0: return fskip {z}/{x}/{y} # 轮询四台服务器分散压力 server_id (x y) % 4 url fhttp://maponline{server_id}.bdimg.com/tile/?qttilex{x}y{y}z{z}stylespl try: resp requests.get(url, headersHEADERS, timeout10) if resp.status_code 200 and len(resp.content) 0: with open(save_path, wb) as f: f.write(resp.content) return fok {z}/{x}/{y} else: return ffail {z}/{x}/{y} status{resp.status_code} except Exception as e: return ferror {z}/{x}/{y} {str(e)} def batch_download(tiles): ok, skip, fail 0, 0, 0 with ThreadPoolExecutor(max_workersMAX_WORKERS) as executor: futures {executor.submit(download_tile, t): t for t in tiles} for future in as_completed(futures): result future.result() if result.startswith(ok): ok 1 elif result.startswith(skip): skip 1 else: fail 1 print(result) # 打印失败详情便于排查 print(f完成: 成功 {ok}, 跳过 {skip}, 失败 {fail})这段代码有几个设计点值得说。第一目录结构按z/x/y.png组织这是绝大多数地图客户端和瓦片服务器认的标准结构后面直接拿个静态服务器指向TILE_ROOT就能用。第二断点续传靠的是「文件存在且非空就跳过」简单但有效中断后重跑不会重复下载。第三server_id (x y) % 4把请求分散到四台服务器降低单台被限流的概率。第四失败不重试只打印因为批量重试容易雪崩我一般跑完一轮后单独对失败列表再跑一次。参数说明MAX_WORKERS是并发上限设太大反而慢因为服务端会限速timeout10是单请求超时网络差的环境可以调到 20Referer头有些时候不加也能下但加上更稳。3.2 失败重试与日志记录上面代码把失败直接打印了实际用的时候建议写进日志文件跑完一轮后读日志里的失败瓦片列表单独重试。重试次数一般设 2 到 3 次每次间隔递增比如 1 秒、3 秒、5 秒避免短时间内反复冲击同一台服务器。import time import logging logging.basicConfig( filenamedownload.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) def download_with_retry(tile, max_retry3): for attempt in range(max_retry): result download_tile(tile) if result.startswith(ok) or result.startswith(skip): return result # 失败后等待间隔递增 time.sleep(1 attempt * 2) logging.error(f最终失败: {tile}) return ffinal_fail {tile}重试逻辑要克制。如果某个瓦片连续三次都失败大概率不是网络抖动而是这个瓦片本身有问题比如该层级该区域没有数据再试也是白费。所以重试次数别超过 3失败的就记下来人工看一眼是不是 URL 规则或者区域范围搞错了。3.3 瓦片合并成 MBTiles 还是保持目录结构下载完之后有两种存法。一种是保持z/x/y.png的目录结构优点是直观、任何静态服务器都能直接托管缺点是文件数量巨大几万个小文件在 Windows 上复制粘贴能卡到崩溃。另一种是合并成 MBTiles本质是一个 SQLite 数据库把所有瓦片塞进一张表里单文件、易迁移、支持随机读取。MBTiles 的表结构很简单tiles(zoom_level, tile_column, tile_row, tile_data)其中tile_data是瓦片的二进制内容。注意 MBTiles 规范里的tile_row是 TMS 方案y 轴从下往上和百度瓦片的 y 轴方向相反写入时需要做一次翻转tms_y 2^z - 1 - y。这个翻转如果忘了地图加载出来就是上下颠倒的属于经典血泪坑。import sqlite3 def pack_to_mbtiles(tile_root, output_path): conn sqlite3.connect(output_path) cur conn.cursor() cur.execute( CREATE TABLE IF NOT EXISTS tiles ( zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_data BLOB ) ) cur.execute(CREATE UNIQUE INDEX IF NOT EXISTS tile_index ON tiles (zoom_level, tile_column, tile_row)) count 0 for z_dir in os.listdir(tile_root): z_path os.path.join(tile_root, z_dir) if not os.path.isdir(z_path): continue z int(z_dir) for x_dir in os.listdir(z_path): x_path os.path.join(z_path, x_dir) if not os.path.isdir(x_path): continue x int(x_dir) for y_file in os.listdir(x_path): y int(y_file.split(.)[0]) # TMS 翻转 tms_y (2 ** z) - 1 - y with open(os.path.join(x_path, y_file), rb) as f: data f.read() cur.execute( INSERT OR REPLACE INTO tiles VALUES (?, ?, ?, ?), (z, x, tms_y, data) ) count 1 conn.commit() conn.close() print(f打包完成共 {count} 张瓦片)这个打包脚本跑几万张瓦片大概几十秒比想象中快。打包完的.mbtiles文件可以直接被很多 GIS 客户端和地图引擎读取迁移时只拷一个文件省心。4. 避坑与排查下载瓦片时最容易翻车的五件事4.1 下载下来的图是错位的或者拼不上现象瓦片能下下来但在地图客户端里加载后相邻瓦片对不上或者整体偏移了几百米。原因坐标系统没统一。百度瓦片用的是 BD-09 坐标系下的墨卡托投影如果你输入的经纬度是 WGS-84GPS 原始坐标或 GCJ-02国测局坐标直接套公式算出来的瓦片编号就是错的。解决先做坐标转换。WGS-84 转 GCJ-02 有一套公开的偏移算法GCJ-02 转 BD-09 再叠一层偏移。工具里最好把转换函数内置输入时明确标注坐标系。我一般会在配置里加一个coord_type字段支持wgs84、gcj02、bd09三种内部统一转成 BD-09 再算瓦片。4.2 下载到一半大量 403 或超时现象前几百张正常后面开始大面积失败日志里全是 403 或 timeout。原因并发太高或者请求太密集触发了服务端的限流。也可能是Referer或User-Agent缺失被当成异常流量。解决把并发数降到 4 到 8在请求之间加随机延迟比如 50 到 200 毫秒补全请求头。如果还是不行就换时间段再跑别硬刚。另外注意四台服务器轮询的分配要均匀别让某一台承担过多请求。4.3 层级 18 下载量爆炸磁盘直接写满现象设了层级 18 下载一个大区域跑了一会儿发现磁盘满了或者进度条几乎不动。原因层级 18 的瓦片数量是层级 14 的 256 倍。一个城市范围在层级 18 可能是几百万张瓦片每张平均 20KB算下来几十 GB。解决下载前先用第 2 章的估算公式算总量再乘以单张平均大小底图一般 15 到 30KB得出预估磁盘占用。层级超过 16 的区域下载一定要先缩范围或者降层级。实际项目里层级 14 到 16 通常已经够用了再高就是浪费。4.4 MBTiles 打包后地图上下颠倒现象目录结构下地图正常打包成 MBTiles 后加载出来上下翻转。原因忘了做 TMS 的 y 轴翻转。MBTiles 规范用的是 TMS 方案y 从下往上而百度瓦片和大多数 XYZ 方案 y 从上往下。解决写入时执行tms_y 2^z - 1 - y。这个公式在第 3 章的打包代码里已经写了但很多人自己写的时候会漏掉。验证方法很简单打包后随便查一条记录看tile_row的值是不是和原始 y 加起来等于2^z - 1。4.5 断点续传失效重跑后重复下载现象中断后重新跑明明文件已经存在还是重新下载了一遍。原因判断文件存在的逻辑写错了比如只判断了目录存在没判断文件或者文件大小为 0 也算存在。还有一种情况是保存路径的命名规则变了导致找不到旧文件。解决判断条件用「文件存在且大小大于 0」保存路径的命名规则一旦定下就不要改。如果中途改了目录结构要么手动迁移旧文件要么接受重复下载。我一般会在下载前先扫一遍已有文件生成一个已完成集合下载时先查集合再发请求比每次读磁盘快。5. 从下载到发布让本地瓦片真正跑起来下载和打包只是前半程瓦片最终要能被地图客户端加载才算闭环。这里说两个最常用的验证方式。第一个是用静态服务器直接托管目录结构。Python 自带的http.server就能干这事# 在瓦片根目录下启动静态服务 cd ./baidu_tiles python -m http.server 8080然后在地图引擎里把瓦片地址模板配成http://localhost:8080/{z}/{x}/{y}.png。注意这里的{z}/{x}/{y}顺序要和你的目录结构一致。如果用的是 Leaflet 这类库还要注意它默认的 y 轴方向和百度是否一致不一致的话得自定义getTileUrl做翻转。第二个是直接读 MBTiles。很多桌面 GIS 工具和移动端地图 SDK 都支持 MBTiles 作为离线源配置时只需要指定文件路径和图层名。验证 MBTiles 是否正确的快速方法是用 SQLite 客户端打开随便查几张瓦片看二进制内容能不能正常显示成图片。关于值不值得做我的判断是如果你只是临时看个离线地图用现成工具下个小区域就够了如果你要做内网部署、需要长期维护离线底图那自己掌握这套下载、打包、发布的流程是值得的因为现成工具往往在并发控制、断点续传、坐标转换这些细节上不够透明出了问题不好排查。自己写的脚本虽然糙但每一行都知道在干什么改起来也方便。最后说个我自己的习惯每次下载前先拿一个极小的区域比如层级 10 的一张瓦片跑通全流程确认坐标没错、URL 能通、保存路径对、打包后能加载再放大范围。这个「小步验证」的习惯帮我省了无数次重跑几万张瓦片的后悔药。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/20 6:46:29

从零手写单头注意力:QKV与缩放点积的代码实现与调试

注意力机制这几个字,但凡碰过Transformer的人都不可能绕开。它既是整个架构的灵魂,也是绝大多数模型面试必问的点,更是很多人从看懂架构图到真正手写实现之间,最大的一道坎。这篇内容打算聊透注意力机制的第一阶段:把数…

2026/10/20 6:46:29

大模型注意力机制详解:MHA、MQA、GQA、MLA原理与KV Cache优化

如果你在准备大模型方向的面试,注意力机制这一段基本绕不开。MHA、MQA、GQA、MLA 这四个缩写,几乎每轮都会出现至少一个,而且面试官往往不是简单问你知不知道,而是让你从原理讲到推理优化,再追问几个为什么。我整理这篇…

2026/10/20 6:46:29

固定翼无人机着陆纵向控制与串级PID仿真解析

简介:面向固定翼无人机纵向控制与着陆场景的研究者、飞控开发者和相关专业学生,这份zip资源包围绕PID控制策略,提供了着陆路径规划、高度跟踪与动力学建模的完整实现。包内共8个文件,包含4个MATLAB脚本(m文件&#xff…

2026/10/20 10:58:07

2026排课调课在教培系统后台怎么设置

排课是教培机构教务最头疼的事。老师时间冲突、教室被占、班级学员时间对不上,Excel拉来拉去还是撞课。2026年了,后台排课系统能按空闲智能排课、自动检测冲突,调课在课节里改、靠排课和上课提醒触达家长,这篇讲清楚怎么在后台把排…

2026/10/20 10:58:07

C++数据结构实战:从链表到哈希表,掌握选型与实现核心

数据结构是一门非常容易被低估的课。很多同学觉得它不就是一堆链表、树、图吗,背一背就完事,结果一到手写代码就卡住,要么指针把你绕晕,要么递归根本看不出返回值在干嘛。也有朋友工作两三年后回来补课,才发现以前写的…

2026/10/20 10:58:07

MATLAB代理模型工具箱:Kriging/RBF/SVR工程优化加速实战

简介:代理模型工具箱tools.rar面向在MATLAB环境下从事工程优化、仿真分析与机器学习的研究生、工程师及科研人员,用于解决复杂模型计算代价高、迭代优化耗时长的问题。资源共289个文件,以263个m脚本、18个mat数据文件为主,另含3份…

2026/10/20 10:58:07

影刀RPA进阶教程:Excel图表自动生成——采集数据直接变可视化

影刀RPA进阶教程:Excel图表自动生成——采集数据直接变可视化 数据采回来只是一列列数字,老板要的是一眼能看懂的图。每周手工选中区域、插入图表、调坐标轴,重复劳动到怀疑人生。这篇进阶教程讲怎么用影刀RPA把这一步自动化:采集…

2026/10/20 10:53:06

AI应用开发为何越来越难:模型爆炸时代的工程化困局

1. 这不是错觉:AI应用开发的“倒退感”正在真实发生你有没有这种感觉?三年前,用几行代码调个开源模型就能做出一个能跑通的AI小工具;两年前,搭个Gradio界面、配个Hugging Face Space,一天就能上线一个可交互…

2026/10/19 18:06:35

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/20 1:05:37

单片机C运行时从启动到多任务:中断安全与共享资源冲突

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:05:37

GCC编译四步详解:预处理、编译、汇编、链接实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:05:37

FIW线是什么?FEP注塑线与普通氟塑料线的区别及应用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑