
简介这是国内六大类交通线路矢量数据的汇总包覆盖高速公路、国道、省道、铁路、县道与乡道面向地理信息从业者、地图制图人员及城乡规划与交通研究人群可直接用于底图叠加、空间查询和专题制图。压缩包共38个文件每一类道路均由shp、shx、dbf、prj、sbn、sbx六类GIS组件构成其中sbn/sbx为空间索引、prj记录坐标系信息另含xml元数据说明支持在ArcGIS、QGIS等主流平台直接打开整体约451.25MB。数据按道路等级分层组织便于按需调取与属性表关联省去自行爬取和配准的繁琐过程。目前已有131人学习下载可充当全国路网底数的重要来源为路网密度分析、区域可达性评估及农村公路末端覆盖研究提供基础数据支撑。1. 全国道路数据包能做什么打开之前先想清楚这三件事做物流路径规划、交通流量热力图或者地图底图展示的人最头疼的不是画图而是找一份干净、分级完整的全国道路数据。这份高速国道省道铁路县道乡道.zip打包的正是按交通等级拆分好的全国道路矢量数据下载解压后可以直接拖进GIS软件做路网分析、路线标注和里程核算。它适合两类人一类是刚接项目需要快速出底图的开发另一类是做交通专题分析要把公路、铁路分开统计的研究者。打开这个压缩包之前先确认三件事你要的是经纬度坐标还是投影坐标、你要不要保留铁路层、你手里的软件支不支持中文路径。这三件事不确认后面加载数据时大概率要翻车。2. 看准数据结构shp四件套、属性表与坐标系才是核心2.1 先摸清文件组成shp、dbf、shx、prj各管什么解压后你会看到一堆同名后缀不同的文件常见的是highway.shp、highway.dbf、highway.shx、highway.prj。这四件是Shapefile的标准组合缺一个都可能让图层加载失败或者属性丢失。.shp几何信息也就是道路线的坐标串它决定路画在哪里、画成什么形状.shx几何索引加载和缩放时用来快速定位坐标数据.dbf属性表存的是每条道路的路名、等级、路线编号、限速等字段.prj坐标系描述文件记录这个图层是用WGS84还是CGCS2000之类的坐标系。这四个文件建议放在同一个文件夹里且文件夹路径不要带中文。否则QGIS或者ArcGIS加载时经常报「无法打开图层」或者属性表读出乱码。我一般解压后第一件事是先用记事本打开.prj文件确认坐标系。如果里面出现GCS_WGS_1984说明是WGS84经纬度如果出现CGCS2000或者Xian_1980那是国内测绘坐标系用的时候要和底图统一。2.2 坐标系选型WGS84经纬度与投影坐标系的取舍这份数据在prj里通常会给出一个基准坐标系。我的习惯是如果只是放在地图上看个大概全用WGS84经纬度如果要做里程统计、缓冲区分析或者面积计算二话不说先转投影坐标系。原因在于经纬度是角度单位用它直接算距离会闹大笑话。比如在北纬45度附近1度经度的实际距离比赤道附近短一半直接拿经纬度字段做距离相加算出来的国道里程能偏出去二三十个百分点。常见做法是转成EPSG:3857Web墨卡托或者EPSG:4326下的UTM分带投影。国内项目我常用EPSG:4547或EPSG:4490这一类CGCS2000的投影带正好对应全国分带不重叠。数据包里如果带.prj一般默认落在WGS84 / Pseudo-Mercator或者CGCS2000 / 3-degree Gauss-Kruger按你项目需求做一次重投影即可。提示如果你不确定该用哪个投影最简单的原则是只做可视化选WGS84做距离和面积分析选和你所在区域匹配的高斯-克吕格投影带。全国尺度的分析优先选Albers等面积投影。2.3 字段清单先过目道路等级、路线编号、方向与限速加载属性表后重点关注四个字段字段名含义典型值level或highway道路等级motorway, trunk, primary, secondary, tertiaryref或route_no路线编号G318, S228, X012name路名京藏高速、沪昆高速maxspeed限速km/h120, 100, 80, 40这里的highway字段是判断级别的关键。motorway对应高速trunk对应高等级国道primary是普通国道secondary是省道tertiary可以对应县道unclassified或者track多是乡道。铁路层一般不在这个字段里而是单独一个railway图层。打开属性表后先看一眼字段值的分布如果全是英文小写字母说明这份数据来自OSM导出的规范如果直接是中文等级值如「高速公路」「国道」说明是经过整理翻译的版本。3. 加载与出图QGIS里把多级道路画成一张可读的地图3.1 QGIS加载shp与按等级分层符号化QGIS里拖入shp文件是最快的打开方式但为了让图面能读需要按道路等级做符号化。右击图层打开「属性 → 符号化」选择「分类」以highway字段为值分类。我给一套常用的设置参数高速motorway红色线宽1.4mm样式实线国道trunk/primary橙色线宽0.8mm省道secondary黄色线宽0.6mm县道tertiary浅灰色线宽0.4mm乡道unclassified/track虚线线宽0.2mm铁路railway黑白相间的scheme线宽0.7mm。符号化时要开「工具提示」显示name和ref字段鼠标悬停能直接看到路名和编号。这个操作在排查断头路时非常实用比反复查属性表快很多。图层加载顺序也有讲究。把铁路放在最底下上面依次是乡道、县道、省道、国道、高速。这样出图时低等级道路不会被高等级道路遮盖图面层次清楚。3.2 标注设置与路线编号显示地图上标注是另一个容易踩坑的点。直接在「标注」标签页选择name字段会发现一堆未命名路段自动标成空串图面全是点。我的做法是标注用ref字段优先没有ref再显示name。具体配置是标注字段选择ref如果ref为空则写name这需要一个简单的表达式。在标注栏里选择「基于表达式标注」写if(ref is not NULL and ref ! , ref, name)这个表达式判断路线编号是否为空为空时退回路名。这样图面不会出现满屏的空白标注。字号按图层级别设置高速标注10pt加粗国道9pt省道8pt县道乡道不标注或按需开启。县道乡道如果全开标注密集区域会互相压盖需要开启「标注避让」并设置间距1.5mm。3.3 按区域裁剪把全国数据切成项目需要的范围全国路网数据全量加载后缩放到一个省或一个市会显得很卡。QGIS中最好的处理是裁剪而不是开图层过滤。开过滤其实没有减少数据量只是不显示了。裁剪用「处理工具箱 → 矢量叠加 → 裁剪」工具输入图层highway.shp 裁剪图层city_boundary.shp 输出highway_city.shp裁剪设置里注意勾选保留几何输出的属性表字段不会丢。裁剪之前先确认两个图层坐标系一致否则裁出来的范围会错位几十公里。我一般先把输入图层重投影到裁剪图层的坐标系再操作。4. 数据拼接与拓扑清洗把断头乡道接回国道4.1 用geopandas读取与合并统一字段、处理空值拿到压缩包里的分图层数据之后第一步是把它读到Python环境里做统一处理。开发环境常用geopandas读取方式如下import geopandas as gpd highway gpd.read_file(./data/highway.shp, encodingutf-8) railway gpd.read_file(./data/railway.shp, encodingutf-8) # 统一字段给铁路加road_type字段避免与公路字段混淆 railway[highway] railway # 合并成一个地理数据框 all_roads gpd.GeoDataFrame( pd.concat([highway, railway], ignore_indexTrue), crshighway.crs ) print(all_roads.shape) print(all_roads[highway].value_counts())这段代码把公路和铁路读进来给铁路加上和公路一致的highway字段值然后拼在一起。关键在于encodingutf-8如果dbf里是GBK编码可以改成encodinggbk不然中文路名会变成乱码。合并前还要检查两边的字段结构不一致的部分用reindex补齐。highway字段的value_counts()输出能让你一眼看出数据包里哪级道路占大头方便后续判断是否缺层。4.2 断头路与相邻层接缝用buffer接上错位端点最常见的拓扑问题是县道线段的端点和国道线段之间差了10来米视觉上断开路径规划时根本拼不起来。这个问题的根源在于多级数据来自不同的采集批次节点没有做吸附。常见做法是设定一个容差值把所有端点附近的线延伸或吸附到邻近线上。用shapely的buffer加geopandas的空间连接实现from shapely.geometry import LineString import numpy as np # 对所有线做端点缓冲容差设50米 buffers all_roads.geometry.buffer(0.002) # 约200米按经纬度估算 # 用空间索引找到断点附近的线对 sjoin gpd.sjoin( all_roads, gpd.GeoDataFrame(geometrybuffers, crsall_roads.crs), howinner, predicateintersects ) # 对交叉点附近的坐标做均值插值 def snap_geometry(row, target): if row.geometry.distance(target) 0.003: coords list(row.geometry.coords) coords[0] target.coords[0] return LineString(coords) return row.geometry all_roads[geometry] all_roads.apply( lambda r: snap_geometry(r, target_nearest[r.name]), axis1 )这里buffer(0.002)是按经纬度粗略对应约200米的距离范围如果你的数据已经投影成米可以直接写buffer(50)。sjoin找出端点与其他线有交集的记录snap_geometry把端点坐标替换成目标线端点。实际项目里我一般把容差控制在50米以内大于50米基本是数据缺层硬接会造出错误拓扑。4.3 属性字段去重与路线合并方向铁路和高速共线的情况也不少见比如高铁线与平行的高速公路在某些路段重叠原因是OSM等数据源把两条线画在了同一条基线上。处理方法是按ref字段分组同一路线内做dissolve合并把同一条国道断成几十段的小线段拼成一条完整线dissolved all_roads.dissolve(byref, aggfuncfirst).reset_index()dissolve会按ref合并几何aggfuncfirst保留了其他属性列的第一个非空值。做完这步一条G318国道通常从几十段变成一段或几段对后续长度统计非常有帮助。合并后要检查是否有跨层合并且字段值不同的情况比如一条乡道ref编号恰好和某条省道重复会导致意外合并。解决办法是先按highway分组再dissolve。5. 避坑排查坐标系偏移、乱码、里程虚高这类翻车现场5.1 地图上整体偏了100多米坐标加密问题现象加载后路网和影像底图对不上整体往东北方向偏移道路落在农田或街区的边上。原因数据在采集源里已经做了非标准坐标偏移处理。常见的是GCJ02坐标它与WGS84之间的偏移在100米到600米不等全国不固定。而卫星底图是WGS84或者Web墨卡托两者之间需要对偏移做纠偏。解决E. 用转换库把线路坐标从GCJ02转到WGS84。Python里可以这样处理from pyproj import Transformer transformer Transformer.from_crs(EPSG:4490, EPSG:4326, always_xyTrue) def correct_line(line): new_coords [transformer.transform(x, y) for x, y in line.coords] return LineString(new_coords) all_roads[geometry] all_roads.geometry.apply(correct_line)这里的EPSG:4490是CGCS2000地理坐标系如果数据标记是GCJ02但prj写的是WGS84那就直接按真实来源做GCJ02到WGS84的高低精度转换。如果你的数据本身就是OSM下载的那不存在这个问题如果是从国内某平台抓的基本就是这种情况。注意用pyproj直接转换不会处理偏移偏转只做坐标系换穿。如果确认是GCJ02需要用专门的坐标纠偏算法。最常见的判断方法是把一条你已知的道路坐标导入地图工具和卫星影像对比偏移量。5.2 路名字段全是问号和乱码代码页没配对现象属性表里name字段显示为????????或者「京藏高速」显示成「浜涵珪抽閫熷」。这是典型的编码读取错误。原因dbf文件用GBK编码创建而读取工具默认用了UTF-8或者反过来。QGIS默认读取容易猜错代码页。解决QGIS加载shp时在弹出的「选择编码」对话框里手动选GBK或者GB18030。Python里则是在gpd.read_file中显式传编码gpd.read_file(./data/highway.shp, encodinggbk)加载后重新导出一次out gpd.read_file(./data/highway.shp, encodinggbk) out.to_file(./data/highway_utf8.shp, encodingutf-8)这样重新编码后的文件再用什么工具打开都不会乱码。规范做法就是拿到数据第一件事先统一编码不然后面做路径检索时匹配不上路名。5.3 里程算出来明显偏大在经纬度下算距离现象用几何长度字段直接加总一条县道算出来的里程比实际路牌标了多了两成。原因图层坐标是经纬度length字段不是米而是十进制度数。直接用它的数值做公里统计没有任何意义。解决先重投影到Albers等面积投影或者UTM投影再计算长度all_roads all_roads.to_crs(EPSG:3857) all_roads[len_km] all_roads.geometry.length / 1000如果是全国范围统计我建议用EPSG:3577这类Albers投影它在全国尺度上的变形比较小。算出来后再和已知高速路段里程参考对比核对偏差在2%~3%以内可接受。5.4 省道与县道接口处有10米缝拓扑容差不够现象省道一条线伸到县城边界就断了县道从边上擦过两条线之间有一小段空隙。原因数据源按行政区边界切了数据边界两侧的采集精度不一致。解决给做路径规划的线路做一次「端点吸附」阈值设30米把间隙补上。具体参考第4.2节的做法把buffer距离从0.003改成0.0003即可。更稳妥的办法是先用gpd.sjoin_nearest做最近线匹配。这个操作的阈值不要超过50米超过就要怀疑是不是数据缺了。5.5 高速和铁路在同一条线上多重几何交织现象查询某条高铁线结果和旁边的高速公路缓冲区重叠了80%。原因数据源在标注铁路时不排除并行公路且共享了同一条几何路径。解决处理方式是给铁路层做负缓冲比如铁路几何buffer(-0.0005)把线向中心收缩一点然后开空间连接删掉与铁路高度重叠的高速路段几何。但更实际的做法是分层维护不合并到同一张表。出总图时让铁路盖在公路下面统计分析时只对单一图层操作。6. 验证与进阶把一条国道抽出来做全流程里程核算数据看懂、坑踩过一轮之后建议做一个完整验证选一条你熟悉的国道从数据包里抽出来核算里程、核对编号、转成开发可用的格式。我习惯拿318国道做基准因为它里程长、跨多个省份数据切分多最容易暴露出拼接问题。g318 all_roads[all_roads[ref] G318].copy() g318 g318.to_crs(EPSG:3577) g318_single g318.dissolve(byref, aggfuncfirst) length_km g318_single.geometry.length.iloc[0] / 1000 print(fG318 长度统计: {length_km:.1f} km)输出结果与公开资料对比误差在±3%之内说明数据拓扑基本可靠。接着把这条线的坐标导出成GeoJSON提供给前端或开发环境g318_single.to_file(./output/G318.geojson, driverGeoJSON)如果目标环境是Android或者车载导航通常需要SQLite或者PostGIS格式可以再导一份g318_single.to_file(./output/g318.sqlite, driverSQLite)这套验证流程价值在于一条路的完整走通相当于给整个压缩包做了一次质量抽检。从那以后我每次拿到新的路网数据都强制先抽一条熟路做里程和断头验证确认没问题再交给下游做服务。希望帮到你。本文还有配套的精品资源点击获取