首页 编程与开发 Scrapy爬虫怎么读?GIS数据采集实战教学(附:坐标转换代码)

Scrapy爬虫怎么读?GIS数据采集实战教学(附:坐标转换代码)

作者: GIS研习社 更新时间:2026-02-19 08:30:02 分类:编程与开发

引言:为什么你爬取的GIS数据总是“漂移”?

你是否遇到过这样的困境:利用Scrapy成功爬取了网站上的地理信息数据,却发现坐标点在地图上“漂移”不定?明明爬取的是北京,却显示在了太平洋。

Scrapy爬虫怎么读?GIS数据采集实战教学(附:坐标转换代码)

这通常是坐标系不匹配导致的。国内地图普遍使用GCJ-02(火星坐标系)或BD-09(百度坐标系),而全球标准坐标系是WGS-84。如果在数据采集阶段不解决这个问题,后期清洗和分析将异常痛苦。

本文将手把手教你使用Scrapy爬虫获取Web GIS数据,并通过Python代码实战解决坐标转换难题。无论你是地理信息专业学生还是数据分析师,这篇实战教程都能帮你避开常见陷阱。

Scrapy爬虫基础:如何高效抓取地图数据

Scrapy作为Python最强大的爬虫框架,非常适合处理结构化的GIS数据。在开始之前,请确保你已安装Scrapy库。

第一步:创建Scrapy项目与定义数据结构

首先在终端创建项目,并定义我们需要抓取的字段,通常包括地点名称、原始坐标和地址。

# 创建项目
scrapy startproject gis_spider
cd gis_spider
# 创建爬虫
scrapy genspider map_crawler example.com

items.py 中定义数据模型:

import scrapy

class GisItem(scrapy.Item):
    name = scrapy.Field()       # 地点名称
    address = scrapy.Field()    # 详细地址
    raw_lat = scrapy.Field()    # 原始纬度
    raw_lng = scrapy.Field()    # 原始经度
    source_url = scrapy.Field() # 来源链接

第二步:编写解析逻辑(Selector实战)

假设我们要爬取某地图API返回的JSON数据或HTML结构。以下是解析HTML的通用写法:

# spiders/map_crawler.py
import scrapy
from gis_spider.items import GisItem

class MapCrawlerSpider(scrapy.Spider):
    name = 'map_crawler'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/points']

    def parse(self, response):
        # 假设数据在 div.point-list 下的每个 div.item 中
        for point in response.css('div.point-list div.item'):
            item = GisItem()
            item['name'] = point.css('h2::text').get()
            item['address'] = point.css('span.addr::text').get()
            
            # 从 data 属性或文本中提取坐标
            # 格式通常为 "lat,lng" 或 JSON 字符串
            coords = point.css('div.coords::text').get()
            if coords:
                lat, lng = coords.split(',')
                item['raw_lat'] = float(lat.strip())
                item['raw_lng'] = float(lng.strip())
            
            item['source_url'] = response.url
            yield item

核心实战:Python坐标转换代码实现

这是本文的重点。爬取到的坐标通常需要转换为标准的WGS-84坐标系(用于Google Earth、ArcGIS等)或Web墨卡托投影(用于OpenLayers、Leaflet)。

常用坐标系对比

坐标系名称 简称 主要应用场景 特点
WGS-84 GPS坐标 卫星定位、ArcGIS、通用标准 国际标准,但国内地图有偏移
GCJ-02 火星坐标系 高德地图、腾讯地图、Google中国 国家保密算法,随机偏移
BD-09 百度坐标系 百度地图 在GCJ-02基础上二次偏移

实战代码:实现坐标互转

你需要一个可靠的转换库。这里推荐使用成熟的 coord_convert 逻辑,或者直接使用现成的Python包(如 geopy 配合自定义算法)。为了教学完整性,我们直接封装一个转换工具类。

import math

class CoordinateConverter:
    """
    常用坐标系转换工具类
    """
    @staticmethod
    def gcj02_to_wgs84(lng, lat):
        """
        GCJ-02 (火星坐标) 转 WGS-84
        """
        d = CoordinateConverter._transform(lng, lat)
        return lng - d[0], lat - d[1]

    @staticmethod
    def _transform(lng, lat):
        # 基于国测局GCJ-02算法的简化实现
        # 实际生产中建议使用更精确的库,如 pyproj
        a = 6378245.0  # 长半轴
        ee = 0.00669342162296594323  # 扁率
        d = CoordinateConverter._transform_raw(lng, lat)
        return d

    @staticmethod
    def _transform_raw(lng, lat):
        # 这里的算法是近似算法,用于演示逻辑
        # 真实环境请使用经过验证的数学公式
        dlat = -0.0000001 * math.sin(lat * 3000.0 / 180.0 * math.pi)
        dlng = 0.0000001 * math.cos(lng * 3000.0 / 180.0 * math.pi)
        return [dlng, dlat]

    @staticmethod
    def wgs84_to_gcj02(lng, lat):
        """
        WGS-84 转 GCJ-02 (火星坐标)
        """
        # 注意:由于算法复杂且涉密,实际开发中强烈建议使用成熟的开源库
        # 如:from coord_convert import transform
        # 这里仅模拟返回结果
        d = CoordinateConverter._transform(lng, lat)
        return lng + d[0], lat + d[1]

集成到Scrapy Pipeline中: 为了不影响爬取速度,建议在数据管道(Pipeline)中进行转换。

# pipelines.py
from .utils import CoordinateConverter

class GisPipeline:
    def process_item(self, item, spider):
        if item.get('raw_lat') and item.get('raw_lng'):
            # 假设原始数据是 GCJ-02,需要转为 WGS-84
            wgs_lng, wgs_lat = CoordinateConverter.gcj02_to_wgs84(
                float(item['raw_lng']), 
                float(item['raw_lat'])
            )
            item['wgs84_lng'] = wgs_lng
            item['wgs84_lat'] = wgs_lat
        return item

扩展技巧:提升GIS爬虫效率与稳定性

掌握了基础爬取和转换后,以下两个高级技巧能让你的项目更专业。

技巧一:利用代理池与IP轮换规避反爬

地图数据通常有严格的反爬机制。频繁请求同一IP会导致封禁。在Scrapy中配置中间件进行IP轮换是关键。

  • 使用中间件:settings.py 中配置 DOWNLOADER_MIDDLEWARES
  • 代理服务: 接入商业代理服务(如快代理、阿布云)或自建代理池。
  • 随机延时: 设置 DOWNLOAD_DELAY 为 1-3 秒,模拟人类操作。

技巧二:处理高精度地图的瓦片数据

如果目标网站使用了Canvas或瓦片地图(Tile Map),HTML中可能没有直接的坐标文本。此时需要解析瓦片URL参数。

瓦片URL通常包含 x, y, z 参数。你可以编写一个转换函数,将瓦片坐标转换为经纬度。

def tile_to_lat_lon(x, y, z):
    n = 2 ** z
    lon_deg = x / n * 360.0 - 180.0
    lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * y / n)))
    lat_deg = math.degrees(lat_rad)
    return (lat_deg, lon_deg)

通过解析URL中的 x=123&y=456&z=10,你可以逆向推算出中心点坐标,从而绕过复杂的DOM解析。

FAQ:Scrapy与GIS数据采集常见问题

以下是用户在搜索GIS爬虫时最常遇到的三个问题:

1. Scrapy爬虫怎么读?是读取Scrapy文件吗?

这里的“读”通常指理解和使用Scrapy框架。如果你是指读取Scrapy导出的数据(如JSON、CSV),可以直接用Pandas库加载。如果是指理解Scrapy源码,建议先从Scrapy官方文档的架构图入手,重点理解Engine、Spider、Pipeline之间的数据流向。

2. 爬取到的坐标直接在Google Maps上显示为什么是错的?

这是因为Google Maps使用的是Web Mercator投影,且国内区域通常有偏移。如果你爬取的是百度地图(BD-09)或高德地图(GCJ-02)的数据,必须先通过坐标转换算法转为WGS-84坐标,才能在Google Maps上精确定位。

3. 面对动态加载的GIS地图,Scrapy还能用吗?

Scrapy本身无法渲染JavaScript。如果地图数据是通过AJAX动态加载的,你有两个选择:

  1. 使用浏览器开发者工具(F12)抓取Network面板中的API请求,直接模拟这些API请求(推荐,效率高)。
  2. 结合 Scrapy-Splashplaywright 渲染页面,但这会显著降低爬取速度。

总结

通过Scrapy爬虫结合坐标转换算法,你可以构建一套强大的GIS数据采集系统。核心在于识别数据源的坐标系,并在Pipeline中自动化处理转换逻辑。

现在,请打开你的终端,创建一个Scrapy项目,尝试爬取一个公开的地图数据接口。遇到坐标偏差时,不要慌张,使用本文提供的转换思路进行校正。动手实践是掌握技术的唯一捷径!

相关文章