Scrapy爬取的GIS数据坐标总是偏移?教你用Proj4进行投影转换(附:坐标系速查表)
Scrapy爬取的GIS数据坐标总是偏移?教你用Proj4进行投影转换(附:坐标系速查表)这类问题,本质上通常不是 Scrapy 抓取错了,而是网页接口返回的坐标系与你在 GIS 软件、WebGIS 地图底图或数据库中使用的坐标系不一致。
很多同学用 Scrapy 抓取 POI、地块边界、轨迹点、行政区边界时,发现经纬度看起来“差不多”,但加载到 QGIS、ArcGIS Pro、Leaflet 或 PostGIS 后,总是偏几百米、几公里,甚至直接跑到另一个城市。本文用一个实用流程讲清楚:如何判断坐标系、如何用 Proj4 做投影转换,以及如何建立一张常用坐标系速查表,避免 Scrapy 爬取 GIS 数据坐标偏移。
引言:Scrapy爬取GIS数据为什么会出现坐标偏移
Scrapy 只负责从网页、接口或文件中提取数据。它不会自动知道某个字段是 WGS84 经纬度、GCJ-02 火星坐标、BD-09 百度坐标,还是 Web Mercator 米制坐标。
常见现象包括:
- 经纬度字段看起来正常,例如 116.397, 39.908,但叠加到底图后偏移。
- 坐标值很大,例如 12958000, 4852000,在 QGIS 中按经纬度加载后位置完全错误。
- 同一批数据在高德地图上位置正确,在 OpenStreetMap 或 ArcGIS Pro 中偏移。
- 接口文档没有写坐标系,只给了字段名,例如
lng、lat、x、y。
解决 Scrapy 爬取 GIS 数据坐标偏移,核心不是反复改字段名,而是先确认源坐标系,再转换到目标坐标系。

背景:网页接口中的GIS坐标不一定是WGS84
很多入门教程会默认“经纬度就是 WGS84”。这个说法在 GPS、GeoJSON、OpenStreetMap 场景中比较常见,但在中文互联网地图和业务系统中并不总是成立。
Scrapy 爬取 GIS 数据时,可能遇到以下坐标来源:
- 政府公开数据接口:可能是 CGCS2000、地方投影坐标系、WGS84 或自定义坐标。
- 商业地图接口:可能是 GCJ-02、高德坐标、腾讯坐标、BD-09 百度坐标。
- WebGIS 瓦片服务:常见为 EPSG:3857,即 Web Mercator。
- 旧系统导出的坐标:可能是北京54、西安80、高斯克吕格投影坐标。
- GeoJSON 或 Shapefile:需要查看元数据、PRJ 文件或接口说明。
如果你把 GCJ-02 当成 WGS84 加载,就会出现国内常见的地图偏移。如果你把 EPSG:3857 的米制坐标当成经纬度,位置会完全错误。如果你把地方投影坐标缺少中央经线信息直接转换,也会得到看似合理但实际错误的结果。
原理:Proj4投影转换解决的是什么问题
Proj4 是一种描述坐标参考系统和投影参数的文本格式,也常被用来泛指基于 PROJ 库的坐标转换能力。它可以描述椭球、投影方式、中央经线、单位、基准面等信息。
一个典型的 WGS84 经纬度 Proj4 字符串如下:
+proj=longlat +datum=WGS84 +no_defs
一个常见的 Web Mercator Proj4 字符串如下:
+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs
Proj4 投影转换主要解决的是:
- 经纬度坐标与投影平面坐标之间的转换。
- 不同椭球和基准面之间的坐标表达转换。
- 同一空间位置在不同坐标参考系统中的数值变化。
但要注意:Proj4 不能直接解决所有互联网地图“加偏”问题。例如 GCJ-02 和 BD-09 属于带有加密偏移规则的坐标体系,不能只靠普通 EPSG 投影参数完成严格转换,通常需要专门的纠偏算法或合规的数据服务。
步骤:用Proj4处理Scrapy爬取GIS数据坐标偏移
步骤1:先观察坐标值范围
拿到 Scrapy 抓取结果后,不要直接导入 GIS。先抽样查看坐标字段。
| 坐标值特征 | 可能坐标系 | 判断建议 |
|---|---|---|
| 经度约 -180 到 180,纬度约 -90 到 90 | WGS84、GCJ-02、BD-09 或其他地理坐标系 | 需要进一步叠加底图验证是否偏移 |
| x、y 为数百万到上千万 | Web Mercator 或投影坐标系 | 不要按经纬度加载,应检查 EPSG 或投影参数 |
| x 为 3 开头或 4 开头的六七位数,y 为数百万 | 高斯克吕格、地方投影 | 需要确认带号、中央经线和基准面 |
| 经纬度在国内,但叠加 OSM 偏移几百米 | GCJ-02 或 BD-09 | 需判断来源是否为高德、腾讯或百度 |
步骤2:从接口和网页脚本中找坐标系线索
Scrapy 抓取页面时,坐标系线索经常藏在接口参数、JavaScript 变量或地图初始化代码里。
可以重点搜索这些关键词:
epsgcrsprojectionwkidspatialReferenceEPSG:4326EPSG:3857BD09GCJ02
如果接口返回类似下面的内容,说明数据坐标系已经写在响应里:
{
"geometry": {
"x": 12958175.0,
"y": 4852834.0,
"spatialReference": {
"wkid": 3857
}
}
}
这里的 wkid: 3857 表示 Web Mercator,不能直接当成 WGS84 经纬度使用。
步骤3:安装Python中的Proj4相关库
在 Python 项目中,通常不直接手写底层 Proj4 转换,而是使用 pyproj。它是 PROJ 的 Python 接口,适合与 Scrapy、GeoPandas、Shapely、PostGIS 工作流衔接。
pip install pyproj
如果后续需要写出 GeoJSON、Shapefile 或 GeoPackage,也可以安装:
pip install geopandas shapely
步骤4:将EPSG:3857转换为WGS84经纬度
假设 Scrapy 抓取到的接口坐标是 EPSG:3857,目标是转换为 WGS84,也就是 EPSG:4326,可使用以下代码:
from pyproj import Transformer
transformer = Transformer.from_crs("EPSG:3857", "EPSG:4326", always_xy=True)
x = 12958175.0
y = 4852834.0
lon, lat = transformer.transform(x, y)
print(lon, lat)
这里必须注意 always_xy=True。它表示输入输出顺序固定为 x、y,也就是经度、纬度或东坐标、北坐标。很多坐标转换错误并不是公式错,而是经纬度顺序被调换了。
步骤5:在Scrapy管道中统一转换坐标
实际项目中,建议不要在 Spider 的解析函数里到处写转换逻辑,而是放到 Scrapy Pipeline 中统一处理。
from pyproj import Transformer
class CoordinateTransformPipeline:
def __init__(self):
self.transformer = Transformer.from_crs(
"EPSG:3857",
"EPSG:4326",
always_xy=True
)
def process_item(self, item, spider):
x = float(item["x"])
y = float(item["y"])
lon, lat = self.transformer.transform(x, y)
item["lon_wgs84"] = lon
item["lat_wgs84"] = lat
item["source_crs"] = "EPSG:3857"
item["target_crs"] = "EPSG:4326"
return item
然后在 Scrapy 的配置中启用 Pipeline:
ITEM_PIPELINES = {
"your_project.pipelines.CoordinateTransformPipeline": 300,
}
这样做的好处是:坐标转换逻辑集中、结果字段清晰、后续检查方便,也避免不同 Spider 使用不同转换规则。
步骤6:把转换结果导入QGIS验证
坐标转换完成后,不要只看代码输出。应导出 CSV 或 GeoJSON,在 QGIS 中叠加底图验证。
推荐验证流程:
- 导出字段:
name、lon_wgs84、lat_wgs84、source_crs。 - 在 QGIS 中选择“添加分隔文本图层”。
- x 字段选择
lon_wgs84,y 字段选择lat_wgs84。 - 坐标参考系统选择 EPSG:4326 – WGS 84。
- 叠加 OpenStreetMap 或天地图等底图检查位置。
如果点位仍然偏移,应回头检查源坐标系是否判断错误,或者数据是否本身来自 GCJ-02、BD-09。
常见坑:Scrapy爬取GIS数据坐标偏移排查重点
把GCJ-02当成WGS84
国内许多商业地图坐标不是标准 WGS84。高德、腾讯常见 GCJ-02,百度常见 BD-09。如果把这些坐标直接放到 QGIS 的 WGS84 图层中,通常会出现肉眼明显的偏移。
判断方法很简单:如果数据来自高德、腾讯、百度地图接口,而接口没有明确说明返回 WGS84,就不要默认它是 WGS84。
把EPSG:3857当成经纬度
Web Mercator 是米制坐标,常用于网页瓦片地图。它的 x、y 数值一般很大。如果你看到坐标值超过经纬度范围,却仍按 EPSG:4326 加载,结果一定会错。
经纬度顺序写反
有些接口返回 lng, lat,有些返回 lat, lng。GeoJSON 标准坐标顺序通常是 [longitude, latitude]。如果顺序反了,中国区域的点可能跑到异常位置。
只转换坐标,不记录源坐标系
很多项目后期无法复查,就是因为只保存了转换后的经纬度,没有保存源坐标、源坐标系、转换时间和转换方法。建议至少保留:
x_sourcey_sourcesource_crslon_wgs84lat_wgs84transform_method
地方坐标系缺少参数
部分政府或工程数据使用地方独立坐标系,仅凭 EPSG:4326 或 EPSG:3857 无法正确转换。此时需要向数据提供方确认中央经线、投影带、椭球、七参数或转换网格等信息。
方法比较:Proj4、GeoPandas、GDAL和PostGIS怎么选
| 方法 | 适用场景 | 优点 | 注意事项 |
|---|---|---|---|
| pyproj / Proj4 | Scrapy 抓取后逐条转换点坐标 | 轻量、代码清晰、适合 Pipeline | 必须明确源 CRS 和目标 CRS |
| GeoPandas | 批量处理 GeoJSON、Shapefile、GeoPackage | 适合矢量数据表处理 | 需要正确设置原始 CRS 后再 to_crs |
| GDAL / ogr2ogr | 命令行批量转换空间文件 | 稳定,适合自动化数据生产 | 参数较多,新手容易混淆源 CRS 与目标 CRS |
| PostGIS ST_Transform | 数据已入库,需要数据库内转换 | 适合空间查询和服务发布 | 几何字段必须有正确 SRID |
如果你的核心流程是 Scrapy 抓取接口数据,推荐优先使用 pyproj 在 Pipeline 中转换。如果数据已经整理成空间文件,再用 GeoPandas 或 GDAL。如果数据已经进入 PostGIS,则使用 ST_SetSRID 和 ST_Transform。
GeoPandas批量转换示例
import geopandas as gpd
from shapely.geometry import Point
rows = [
{"name": "point_a", "x": 12958175.0, "y": 4852834.0},
{"name": "point_b", "x": 12959000.0, "y": 4853000.0}
]
gdf = gpd.GeoDataFrame(
rows,
geometry=[Point(row["x"], row["y"]) for row in rows],
crs="EPSG:3857"
)
gdf_wgs84 = gdf.to_crs("EPSG:4326")
gdf_wgs84.to_file("scrapy_points_wgs84.geojson", driver="GeoJSON")
PostGIS转换示例
如果原始坐标是 EPSG:3857,表中已有 x、y 字段,可以先构造几何,再转换为 EPSG:4326。
ALTER TABLE poi ADD COLUMN geom_3857 geometry(Point, 3857);
ALTER TABLE poi ADD COLUMN geom_4326 geometry(Point, 4326);
UPDATE poi
SET geom_3857 = ST_SetSRID(ST_MakePoint(x, y), 3857);
UPDATE poi
SET geom_4326 = ST_Transform(geom_3857, 4326);
注意:ST_SetSRID 只是声明坐标系,不会改变坐标值;ST_Transform 才会真正进行坐标转换。
检查清单:坐标系速查表与项目落地建议
下面这张表可以作为 Scrapy 爬取 GIS 数据后的坐标系速查表。它不能替代正式数据说明,但能帮助你快速缩小排查范围。
| 名称 | 常见标识 | 坐标特征 | 常见来源 | 处理建议 |
|---|---|---|---|---|
| WGS84 经纬度 | EPSG:4326 | 经度 -180 到 180,纬度 -90 到 90 | GPS、OSM、标准 GeoJSON | 可直接用于多数 GIS 分析,但要确认是否真为 WGS84 |
| Web Mercator | EPSG:3857 | x、y 为米制大数值 | WebGIS 瓦片、在线地图底图 | 用 Proj4、pyproj 或 ST_Transform 转 EPSG:4326 |
| GCJ-02 | 火星坐标 | 看似经纬度,但在 WGS84 底图上偏移 | 高德、腾讯等国内地图 | 需使用合规纠偏方法,不能只靠普通投影转换 |
| BD-09 | 百度坐标 | 相对 GCJ-02 还有二次偏移 | 百度地图 | 通常需先转 GCJ-02,再视需求转 WGS84 |
| CGCS2000 | EPSG:4490 或投影分带 | 可为经纬度,也可为投影坐标 | 国内测绘、自然资源数据 | 确认是地理坐标还是高斯投影坐标 |
| 西安80 / 北京54 | 地方历史坐标 | 常见于老工程、规划、地籍数据 | 历史测绘资料 | 需要精确转换参数,不能盲转 |
项目中建议按下面的清单执行:
- 确认接口来源:政府平台、商业地图、WebGIS 服务还是文件下载。
- 检查字段名:
lng、lat、x、y不等于坐标系说明。 - 检查坐标范围:先判断是经纬度还是投影坐标。
- 查找接口文档:优先相信官方 CRS、EPSG、WKID、PRJ 信息。
- 统一转换代码:推荐放入 Scrapy Pipeline,而不是分散在解析函数中。
- 保留源坐标:不要只保存转换结果。
- 用 QGIS 叠加底图验证:至少抽样检查城市中心、道路交叉口、行政边界。
- 遇到 GCJ-02、BD-09、地方坐标系时,不要假装它们是普通 EPSG 转换。
FAQ:Scrapy爬取GIS数据坐标偏移常见问题
Scrapy爬取的经纬度为什么在QGIS中偏几百米?
最常见原因是源坐标不是 WGS84,而是 GCJ-02 或 BD-09。QGIS 默认按 EPSG:4326 加载后,会与标准底图产生偏移。应先确认数据来源,再选择对应转换方法。
Proj4能不能把百度坐标直接转成WGS84?
普通 Proj4 投影参数不能直接表达 BD-09 的加密偏移规则。BD-09 到 WGS84 通常需要专门算法或合规服务。Proj4 更适合处理标准坐标参考系统之间的投影转换,例如 EPSG:3857 到 EPSG:4326。
EPSG:4326和WGS84是一回事吗?
在多数 GIS 软件中,EPSG:4326 通常表示 WGS84 地理坐标系,单位为度。但实际项目仍要注意坐标顺序和数据来源,不能仅凭字段名判断。
为什么pyproj转换结果经纬度顺序不对?
可能是轴顺序导致的。建议在 Transformer.from_crs 中设置 always_xy=True,让输入输出始终按 x、y 顺序处理,也就是经度在前、纬度在后。
Scrapy抓到的坐标值是12900000这种大数,应该怎么处理?
这通常不是经纬度,而可能是 EPSG:3857 Web Mercator 或其他投影坐标。应先确认接口中的 wkid、epsg 或地图初始化参数,再用 Proj4、pyproj、GDAL 或 PostGIS 转换到目标坐标系。
没有接口文档时,怎么判断坐标系?
可以结合坐标数值范围、网页地图类型、JS 初始化代码、网络请求参数、底图服务地址和抽样叠加验证来判断。若仍无法确定,应把“坐标系未知”作为数据质量风险记录下来,不要直接进入正式分析。
结论:先识别坐标系,再谈Proj4投影转换
Scrapy 爬取 GIS 数据坐标偏移,通常不是爬虫本身的问题,而是源坐标系、目标坐标系和地图底图之间没有对齐。正确流程应是:先识别坐标值特征和接口坐标系,再用 Proj4、pyproj、GeoPandas、GDAL 或 PostGIS 做标准转换,最后在 QGIS 或 WebGIS 中叠加验证。
对于 EPSG:3857、EPSG:4326、CGCS2000 等标准坐标参考系统,Proj4 投影转换非常适合自动化处理。对于 GCJ-02、BD-09 和地方独立坐标系,则必须额外确认转换规则和数据合规要求。只要把源坐标、目标坐标、转换方法和验证过程记录清楚,Scrapy 抓取 GIS 数据后的坐标偏移问题就能被系统性排查和解决。