Scrapy爬虫频繁被封IP怎么办?GIS数据采集实战技巧(附:反爬策略清单)
Scrapy爬虫频繁被封IP怎么办?GIS数据采集实战技巧(附:反爬策略清单)这类问题,通常不是“换几个代理”就能解决。对于 GIS 数据采集来说,目标网站往往包含行政区划、POI、道路、影像瓦片、地名地址、规划公示等空间相关数据,一旦 Scrapy 请求过快、访问模式异常、字段接口被误用,就很容易触发限流、验证码、403、429,甚至 IP 封禁。
本文从 GIS 数据采集实战角度,讲清楚 Scrapy 爬虫频繁被封 IP 的常见原因、排查方法、合规采集策略、Scrapy 参数配置、代理与重试机制,以及一份可直接用于项目检查的反爬策略清单。

引言: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 工程化采集的关键一步。