Scrapy爬虫频繁被封IP怎么办?GIS数据采集实战技巧(附:反爬策略清单)

编程与开发
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

Scrapy爬虫频繁被封IP怎么办?GIS数据采集实战技巧(附:反爬策略清单)这类问题,通常不是“换几个代理”就能解决。对于 GIS 数据采集来说,目标网站往往包含行政区划、POI、道路、影像瓦片、地名地址、规划公示等空间相关数据,一旦 Scrapy 请求过快、访问模式异常、字段接口被误用,就很容易触发限流、验证码、403、429,甚至 IP 封禁。

本文从 GIS 数据采集实战角度,讲清楚 Scrapy 爬虫频繁被封 IP 的常见原因、排查方法、合规采集策略、Scrapy 参数配置、代理与重试机制,以及一份可直接用于项目检查的反爬策略清单。

Scrapy爬虫频繁被封IP GIS数据采集反爬策略流程图
Scrapy GIS 数据采集被封 IP 的典型排查流程:先确认合规边界,再优化请求行为、限速、重试和代理策略。

引言:GIS 数据采集为什么更容易触发反爬

普通网页爬取可能只是抓取列表和详情页,而 GIS 数据采集经常会访问坐标查询接口、瓦片服务、行政区划接口、POI 分页接口、空间范围检索接口。这类接口通常请求量大、参数规律明显、返回数据结构固定,因此更容易被服务端识别为自动化访问。

例如,采集某城市 POI 时,爬虫可能按网格切片循环请求;下载地图瓦片时,URL 中的 z、x、y 参数高度规律;抓取规划公示时,列表页和详情页访问间隔过短。这些行为都会让 Scrapy 爬虫频繁被封 IP。

Dr.GIS 建议:GIS 数据采集首先要确认数据来源是否合法、是否有开放 API、是否允许自动化访问。技术方案不能绕过网站明确禁止的访问限制,更不能用于未授权的数据抓取。

背景:Scrapy 爬虫频繁被封 IP 的常见表现

在 GIS 项目中,Scrapy 被封 IP 的表现通常有以下几类:

  • HTTP 403:服务端拒绝访问,常见于 User-Agent 异常、Referer 缺失、访问路径敏感。
  • HTTP 429:请求过于频繁,表示触发了限流策略。
  • 验证码页面:返回 HTML 不是目标数据,而是验证码、滑块或安全验证页面。
  • 连接超时:服务器直接丢弃连接,表现为 timeout 或 connection reset。
  • 数据突然为空:接口仍返回 200,但结果为空或字段被隐藏。
  • 账号或 Token 失效:如果接口需要登录,短时间高频访问会导致会话被风控。

很多初学者会误以为“只要换 IP 就能继续爬”。但实际项目中,IP 只是因素之一。请求频率、Header、Cookie、访问顺序、参数范围、并发数量、失败重试方式,都会影响封禁概率。

原理:反爬系统通常如何判断异常请求

要解决 Scrapy 爬虫频繁被封 IP,必须先理解反爬逻辑。网站并不是只看 IP,它通常会综合判断多个特征。

1. 请求频率异常

如果同一个 IP 在几秒内连续访问几百个行政区划接口、POI 接口或瓦片地址,很容易触发限流。GIS 数据采集尤其容易出现这种情况,因为空间网格、分页、瓦片编号天然适合循环。

2. 请求头缺失或过于固定

Scrapy 默认请求头较简单。如果没有合理设置 User-Agent、Accept-Language、Referer 等字段,服务器可以很容易判断请求不是普通浏览器行为。

3. 访问路径过于规律

例如从第 1 页到第 500 页连续访问,或按瓦片 x、y 编号顺序请求,这种模式非常“机器化”。真实用户通常不会如此稳定、连续、无停顿地访问。

4. Cookie 与会话异常

部分 GIS 平台会给首次访问页面的用户写入 Cookie,再由接口验证 Cookie。如果爬虫直接请求接口,不经过页面初始化,就可能被拒绝。

5. 参数越界或接口误用

例如接口本来只支持查询一个区县范围,却被爬虫传入超大 bbox;或者请求页码超过实际页数。这类异常参数也可能被记录为风险访问。

步骤:Scrapy GIS 数据采集的实战优化方案

步骤 1:先确认数据源和采集边界

在写 Scrapy 代码前,先完成数据源检查:

  • 查看网站是否提供开放数据下载入口。
  • 查看是否有官方 API、政务开放数据平台、OGC 服务、ArcGIS REST 服务。
  • 查看 robots.txt、服务条款和版权说明。
  • 确认采集频率是否会影响目标网站正常服务。
  • 只采集项目所需字段,不进行无意义全站扫描。

对于 GIS 数据,很多时候不需要爬网页。可以优先寻找 WFS、WMS、WMTS、ArcGIS REST、GeoJSON、CSV、SHP 下载入口,既稳定又合规。

步骤 2:降低 Scrapy 并发和请求速度

Scrapy 默认并发对普通网站可能已经偏高。GIS 数据接口如果返回较快,短时间请求量会迅速放大。

CONCURRENT_REQUESTS = 4
CONCURRENT_REQUESTS_PER_DOMAIN = 2
DOWNLOAD_DELAY = 2

RANDOMIZE_DOWNLOAD_DELAY = True

AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 2
AUTOTHROTTLE_MAX_DELAY = 15
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0

这些参数的作用是降低单位时间请求数量,让爬虫更接近正常用户访问节奏。对于政务类 GIS 网站,宁可慢一些,也不要让爬虫在几分钟内打出几万次请求。

步骤 3:设置合理的请求头

请求头不是越复杂越好,而是要与访问场景一致。至少应设置稳定、真实的 User-Agent,并根据实际页面来源设置 Referer。

DEFAULT_REQUEST_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/120.0 Safari/537.36",
    "Accept": "application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.9",
}

如果接口依赖 Referer,不要随意伪造与实际访问路径不一致的来源。更好的方式是先访问入口页面,获取 Cookie 和必要参数,再请求接口。

步骤 4:使用 Cookie 和会话保持

Scrapy 默认支持 Cookie。对于需要先打开地图页面再调用接口的 GIS 平台,可以先请求页面,再从页面中提取接口参数或 Cookie。

COOKIES_ENABLED = True

class GisSpider(scrapy.Spider):
    name = "gis_spider"
    start_urls = ["https://example.com/map"]

    def parse(self, response):
        api_url = "https://example.com/api/poi?bbox=..."
        yield scrapy.Request(
            api_url,
            callback=self.parse_api,
            headers={"Referer": response.url}
        )

    def parse_api(self, response):
        data = response.json()
        for item in data.get("features", []):
            yield item

这种方式比直接请求接口更稳定,也更接近真实访问流程。

步骤 5:控制空间网格切片请求

GIS 数据采集经常会按 bbox 网格切片。如果网格太密,请求量会暴涨;如果网格太大,接口可能超时或返回截断结果。

建议按以下原则设计网格:

  • 先用小范围测试接口最大返回数量。
  • 如果接口有 limit,确保每个网格返回数量低于 limit。
  • 网格之间加入随机停顿。
  • 避免连续访问相邻网格,可打乱网格顺序。
  • 记录已完成网格,支持断点续采。
import random
import time

bboxes = [
    (116.30, 39.90, 116.31, 39.91),
    (116.31, 39.90, 116.32, 39.91),
]

random.shuffle(bboxes)

for bbox in bboxes:
    # 构造请求 URL
    time.sleep(random.uniform(1.5, 5.0))

如果是 Scrapy 项目,不建议直接在 spider 中使用 time.sleep 阻塞整个 reactor,更推荐通过 DOWNLOAD_DELAY、AutoThrottle 或调度层控制。

步骤 6:正确处理 403、429 和验证码页面

不要让爬虫在被拒绝后疯狂重试。错误的重试机制会进一步加重封禁。

RETRY_ENABLED = True
RETRY_TIMES = 2
RETRY_HTTP_CODES = [408, 429, 500, 502, 503, 504]

DOWNLOAD_TIMEOUT = 30

对于 403 和验证码页面,通常不建议盲目重试。更合理的做法是暂停任务、记录 URL、降低频率、检查请求头和访问流程。

def parse_api(self, response):
    if response.status == 429:
        self.logger.warning("触发限流:%s", response.url)
        return

    text = response.text
    if "验证码" in text or "安全验证" in text:
        self.logger.warning("疑似验证码页面:%s", response.url)
        return

    data = response.json()
    yield from self.parse_features(data)

步骤 7:代理 IP 的正确使用方式

代理不是万能药。代理质量差、切换过快、多个账号共享异常 IP,反而更容易被识别。GIS 数据采集使用代理时,应把它作为稳定性补充,而不是绕过限制的核心手段。

代理使用建议:

  • 优先降低请求频率,再考虑代理。
  • 不要每个请求都随机换 IP,会造成会话不连续。
  • 按域名、任务或城市分配代理,保持一定时间窗口稳定。
  • 对失败代理做健康检查和熔断。
  • 不要使用来源不明、风险较高的公共代理。

Scrapy 中可以通过 downloader middleware 设置代理:

class ProxyMiddleware:
    def process_request(self, request, spider):
        proxy = spider.settings.get("HTTP_PROXY")
        if proxy:
            request.meta["proxy"] = proxy
DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.ProxyMiddleware": 350,
}

HTTP_PROXY = "http://user:password@proxy.example.com:8000"

步骤 8:把采集状态写入数据库,支持断点续采

GIS 数据采集常常持续数小时甚至数天。被封 IP、网络中断、接口异常都很常见。如果没有断点续采,爬虫重启后会重复请求大量页面,进一步增加封禁风险。

可以把采集任务拆成网格任务表,字段包括 bbox、状态、重试次数、最后请求时间、错误信息。数据结果可以写入 PostGIS,任务状态写入 PostgreSQL 普通表。

CREATE TABLE crawl_grid_task (
    id serial PRIMARY KEY,
    minx double precision,
    miny double precision,
    maxx double precision,
    maxy double precision,
    status text DEFAULT 'pending',
    retry_count integer DEFAULT 0,
    last_error text,
    updated_at timestamp DEFAULT now()
);

这样可以避免重复请求同一片区域,也方便统计哪些空间范围容易失败。

常见坑:为什么你已经加了代理还是被封

坑 1:并发太高,代理只是分摊了异常行为

如果每个代理都以极高频率访问目标站点,反爬系统仍然能识别异常。并发和延迟是第一优先级,代理只是辅助。

坑 2:所有请求头完全一样

多个 IP 使用完全相同的请求头、相同访问顺序、相同时间间隔,会形成明显的自动化特征。可以适度区分请求节奏,但不要伪造不合理的浏览器环境。

坑 3:重试策略导致雪崩

接口返回 429 后,爬虫立即重试,多个请求一起失败、一起重试,最后请求量反而翻倍。遇到 429 应降低速率或暂停,而不是立即猛刷。

坑 4:忽略接口最大返回数量

很多 POI 或空间查询接口会限制单次返回数量。例如最多返回 1000 条,如果 bbox 太大,结果被截断,爬虫虽然没报错,但数据已经不完整。

坑 5:没有检查坐标系和范围

GIS 接口常用 WGS84、GCJ-02、BD-09、Web Mercator 等不同坐标体系。如果 bbox 坐标系传错,可能请求到异常范围,导致接口返回空、报错或触发风控。

方法比较:限速、代理、官方 API、数据下载哪种更适合

方法 适用场景 优点 限制
降低并发与限速 大多数 Scrapy GIS 数据采集任务 稳定、简单、合规风险低 采集时间更长
AutoThrottle 自动限速 目标站点响应速度波动较大 能根据延迟自动调整 仍需设置合理上限
代理 IP 多地区访问、单 IP 限流较严格 提升可用性 质量不稳定,不能替代合规采集
官方 API 有开放平台或授权接口 稳定、字段清晰、可追溯 可能有额度、申请和费用限制
开放数据下载 行政区划、POI、规划、统计数据 最适合批量 GIS 分析 更新频率可能较低
OGC 或 ArcGIS REST 服务 地图服务、要素服务、空间图层 天然适合 GIS 工作流 需要理解服务参数和坐标系

从工程实践看,优先级建议是:开放数据下载或官方 API,其次是标准 GIS 服务,最后才是网页爬取。这样可以减少 Scrapy 爬虫频繁被封 IP 的概率,也能提高数据质量。

检查清单:Scrapy 反爬策略清单

在运行 GIS 数据采集任务前,可以逐项检查:

  • 是否确认网站允许采集或存在开放数据授权。
  • 是否优先查找官方 API、开放数据、WFS、ArcGIS REST 服务。
  • 是否限制了 CONCURRENT_REQUESTS 和 CONCURRENT_REQUESTS_PER_DOMAIN。
  • 是否设置 DOWNLOAD_DELAY 和 RANDOMIZE_DOWNLOAD_DELAY。
  • 是否启用 AutoThrottle。
  • 是否设置合理 User-Agent、Accept、Accept-Language。
  • 是否按真实流程先访问入口页面再访问接口。
  • 是否检查 Cookie、Token、Referer 是否必需。
  • 是否对 403、429、验证码页面做了识别。
  • 是否避免对 403 和验证码页面进行高频重试。
  • 是否记录失败 URL、失败 bbox 和错误原因。
  • 是否支持断点续采,避免重复请求。
  • 是否检查 bbox 坐标系和范围是否正确。
  • 是否确认接口最大返回数量,避免数据截断。
  • 是否把空间网格顺序打散,避免规律请求。
  • 是否对代理做健康检查,而不是盲目随机切换。
  • 是否为采集结果做去重、坐标检查和字段完整性检查。

FAQ:Scrapy 爬虫频繁被封 IP 常见问题

1. Scrapy 爬虫频繁被封 IP,第一步应该改什么?

第一步不是换代理,而是降低并发和请求频率。先设置 DOWNLOAD_DELAY、CONCURRENT_REQUESTS_PER_DOMAIN 和 AutoThrottle,再检查请求头、Cookie 和访问流程。

2. GIS 数据采集一定要用代理 IP 吗?

不一定。很多任务只要使用官方 API、开放数据下载、标准 GIS 服务,或者合理限速,就不需要代理。代理主要用于提升稳定性,不应作为绕过访问限制的手段。

3. 遇到 429 Too Many Requests 怎么办?

429 表示请求过快。应降低并发、增加延迟、暂停一段时间,并检查是否存在重试雪崩。不要在 429 后立即高频重试。

4. 为什么接口返回 200,但采集到的数据是空的?

可能原因包括:Cookie 失效、Token 过期、bbox 坐标系错误、参数越界、触发风控后返回空结果、接口本身限制分页或返回数量。需要保存原始响应进行排查。

5. 采集 POI 时如何避免漏数据?

应先测试接口最大返回数量,再设计合适的空间网格。每个网格返回数量应低于接口上限,并对相邻网格结果做去重。坐标字段建议统一入库到 PostGIS 后用空间索引和唯一键检查。

6. Scrapy 适合下载地图瓦片吗?

技术上可以,但必须确认瓦片服务授权和使用条款。大量下载瓦片很容易触发封禁,也可能违反服务协议。若用于正式项目,应优先使用授权瓦片服务、离线地图包或公开许可数据源。

7. 如何判断是 IP 被封还是请求参数错误?

可以用同一 URL 在浏览器中访问,并对比不同网络环境、不同 Header、不同 bbox 的响应。如果只有某个 IP 失败,可能是 IP 限制;如果所有环境都失败,优先检查参数、坐标系、Token 和接口权限。

结论:解决被封 IP,本质是让采集流程更合规、更稳定

Scrapy 爬虫频繁被封 IP,并不是单一技术问题,而是数据源合规、请求节奏、接口理解、GIS 参数设计和工程稳定性的综合问题。对于 GIS 数据采集,最重要的是先确认数据来源和授权,再选择官方 API、开放数据或标准 GIS 服务。

如果确实需要使用 Scrapy,应优先做好限速、AutoThrottle、请求头、Cookie、错误识别、断点续采和空间网格设计。代理 IP 可以作为辅助,但不能替代合理的采集策略。

真正可靠的 GIS 数据采集方案,不是“跑得最快”,而是“可复现、可验证、不中断、不过度打扰数据源”。这也是从脚本爬虫走向 GIS 工程化采集的关键一步。