做爬虫这行干了三四年,最让我头疼的事从来不是写解析逻辑,而是IP一换就掉线、一跑就封。去年有个做电商价格监控的朋友找我吐槽,他用了某家号称"百万IP池"的服务,结果跑不到两小时,请求成功率从95%掉到40%,最后整条流水线全停。我一看他的配置,问题根本不在IP数量,而在于他压根没搞懂代理IP该怎么用。
2026年了,各家代理服务商的营销话术越来越花哨,什么"无限IP"、"秒级刷新",听着都挺唬人。但真正跑过项目的人都知道,稳不稳,看的不是池子有多大,而是你整个链路怎么设计的。今天就把我这些年踩坑攒下来的实战经验摊开来讲,不整虚的,全是能直接落地的东西。
先搞清楚:你的爬虫到底为什么"不稳"
很多人一遇到请求失败,第一反应就是"IP被ban了,赶紧换"。但实际情况往往更复杂。我总结下来,爬虫不稳定基本就三类原因:
第一,IP本身质量不行。有些廉价代理池里混了大量机房IP、过期IP,甚至已经被目标站点标记过的"脏IP"。你拿这种IP去请求,等于还没进门就被保安拦住了。所以选服务商的时候,别光看它宣传多少万IP,要看IP纯度和可用率这两个硬指标。我目前长期用的是神龙HTTP,它家走的是国内三大运营商正规授权,IP纯度标称99.8%,实际跑下来可用率确实能到99.9%左右,这点我比较放心。
第二,请求节奏没控制好。哪怕IP再干净,你一秒发两百个请求,目标站点的风控系统也会把你识别成异常流量。这不是IP的问题,是你自己的策略问题。
第三,代理池管理太粗糙。很多人就是写个for循环,每次请求随机取一个IP,用完就扔。没有健康检查、没有失败重试、没有IP生命周期管理。这种写法在测试环境跑跑还行,一上生产环境就原形毕露。
选IP这件事,别被"数量"忽悠了
我见过太多人选型的时候,张口就是"你们有多少个IP?"好像IP越多就越安全。说实话,3000万和30000万对你一个日请求量十万的项目来说,体验上没有任何区别。真正该关注的是下面这几个维度:
IP的时效性。动态IP的存活时间是3分钟还是30分钟,直接影响你的任务能不能跑完。如果你抓的是一个需要登录态的页面,3分钟的IP根本不够你完成整个请求链路。
地域覆盖和定位精度。有些业务需要指定城市甚至区县的IP出口,这时候"全国混播"就没什么意义了。神龙HTTP这块做得比较细,300+城市级精准定位,你可以指定到具体城市,这对做区域化数据采集的场景很实用。
协议支持。现在大部分目标站点都上了HTTPS,如果你的代理只支持HTTP,那等于白搭。神龙HTTP支持HTTP/HTTPS/SOCKS5三种协议,这点是基础配置,但确实有些小服务商只给HTTP,用的时候会很别扭。
延迟和并发能力。这个指标在宣传页上经常被一笔带过,但实际跑起来差距很大。我对比过几家,同样一个城市节点的IP,有的延迟能控制在30ms以内,有的能到150ms以上。如果你要做实时性要求高的采集,这个差距会直接体现在你的吞吐量上。
短效动态和长效静态,到底该用哪个
这是被问得最多的问题。没有标准答案,取决于你的业务场景。我直接上对比,省得你来回翻:
| 对比维度 | 短效动态IP | 长效静态IP | 固定IP |
|---|---|---|---|
| 存活时间 | 3/5/10/15/30分钟(可定制) | 1/4/8/12/24小时(可定制) | 长期有效,按个数售卖 |
| IP更换频率 | 高频轮换,每次请求可换新 | 中频,一个IP用几小时 | 基本不换,一个IP长期绑定 |
| 适合场景 | 大规模公开数据采集、多城市轮询 | 需要一定持续性的采集任务、多步骤流程 | 需要稳定出口IP的API对接、长期监控 |
| IP纯净度 | 每日更新去重,3000万+资源池 | 每日去重量10万+,纯净度有保障 | ISP正式分配,纯净度99.83% |
| 计费方式 | 包量/包时 | 包量/包时 | 按个数+包时 |
| 典型用户 | 个人开发者、中小团队 | 有持续采集需求的企业 | 追求很高稳定性的企业用户 |
我的经验是:如果你的任务是"抓完就走",短效动态IP够用且成本最低。神龙HTTP的短效动态IP池,3分钟到30分钟可选,3000万+资源每日更新去重,延迟很低,对于大多数公开数据采集场景来说,性价比是最高的。但如果你有一个多步骤的采集流程,比如先访问列表页、再进详情页、最后抓数据,整个过程需要5-10分钟,那短效IP可能中途就过期了,这时候用长效静态IP(比如4小时或8小时档)会更从容。
还有一种情况,比如你要对接某个第三方API,对方要求你的请求必须来自同一个IP,或者你要做一个长期运行的监控任务,那固定IP就是独特选择。神龙HTTP的固定IP是基于高性能云主机构建的,全部来自ISP正式分配,高连通率、高稳定性,按个数买、包时计费,适合IP需求量不大但要求"一个IP用到底"的场景。
代码里代理池怎么管,才是真正拉开差距的地方
前面说的都是"选什么IP",但真正决定你爬虫稳不稳的,是代码层面怎么管理这些IP。我见过太多人把代理IP当成一个字符串往requests里一塞就完事了,这种写法在demo里能跑,上生产就是灾难。
下面这套代理池管理逻辑是我实际项目里用了很久的,核心思路是:健康检查 + 失败惩罚 + 自动轮换 + 并发控制。不追求花哨,追求的就是"别挂"。
import random
import time
import threading
from collections import deque
from concurrent.futures import ThreadPoolExecutor, as_completed
import requests
class ProxyPool:
"""
代理IP池管理器
核心原则:
1. 每个IP有健康状态和失败计数
2. 连续失败的IP进入冷却期
3. 请求失败自动换IP重试,但不无限重试
"""
def __init__(self, api_url, max_workers=10, max_retries=3):
self.api_url = api_url 神龙HTTP的API提取接口
self.max_workers = max_workers
self.max_retries = max_retries
self._pool = deque()
self._lock = threading.Lock()
self._failed = {} ip -> (fail_count, cooldown_until)
self._cooldown_seconds = 60 失败后冷却60秒
def fetch_proxies(self, count=50, city=None, duration="15"):
"""
从神龙HTTP API批量提取代理IP
city: 指定城市,如"杭州",不指定则混播
duration: 短效IP存活时间(分钟)
"""
params = {
"num": count,
"protocol": "https",
"duration": duration
}
if city:
params["city"] = city
resp = requests.get(self.api_url, params=params, timeout=10)
resp.raise_for_status()
proxies = resp.json().get("data", [])
with self._lock:
for p in proxies:
if p not in self._pool:
self._pool.append(p)
return len(proxies)
def get_proxy(self):
"""取一个健康IP,跳过冷却中的"""
with self._lock:
now = time.time()
清理已过期冷却的IP
expired = [ip for ip, (_, until) in self._failed.items() if now >= until]
for ip in expired:
del self._failed[ip]
从池中取一个不在冷却期的
tried = 0
while self._pool and tried < len(self._pool):
ip = self._pool[0]
self._pool.rotate(1)
if ip not in self._failed:
return ip
tried += 1
return None
def mark_failed(self, ip):
"""标记IP失败,连续3次进入冷却"""
with self._lock:
count, _ = self._failed.get(ip, (0, 0))
count += 1
if count >= 3:
self._failed[ip] = (count, time.time() + self._cooldown_seconds)
else:
self._failed[ip] = (count, 0)
def mark_success(self, ip):
"""请求成功,清除失败记录"""
with self._lock:
self._failed.pop(ip, None)
def request_with_proxy(self, url, method="GET", kwargs):
"""
带代理的请求,自动重试+换IP
"""
last_error = None
for attempt in range(self.max_retries):
proxy = self.get_proxy()
if not proxy:
池子空了,补充一批
self.fetch_proxies(count=30)
proxy = self.get_proxy()
if not proxy:
raise Exception("代理池耗尽,无法获取可用IP")
proxies = {
"http": f"http://{proxy}",
"https": f"http://{proxy}"
}
try:
resp = requests.request(
method, url,
proxies=proxies,
timeout=(5, 15), 连接超时5s,读取超时15s
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/125.0.0.0 Safari/537.36"
},
kwargs
)
if resp.status_code == 200:
self.mark_success(proxy)
return resp
elif resp.status_code in (403, 429, 503):
被风控了,换IP
self.mark_failed(proxy)
last_error = f"HTTP {resp.status_code}"
time.sleep(random.uniform(1, 3))
else:
self.mark_success(proxy)
return resp
except (requests.ConnectionError, requests.Timeout) as e:
self.mark_failed(proxy)
last_error = str(e)
time.sleep(random.uniform(0.5, 2))
raise Exception(f"重试{self.max_retries}次后仍失败: {last_error}")
使用示例
if __name__ == "__main__":
pool = ProxyPool(
api_url="https://api.shenlongip.com/get", 替换为你自己的API地址
max_workers=8,
max_retries=3
)
初始化:提取一批杭州的15分钟短效IP
pool.fetch_proxies(count=100, city="杭州", duration="15")
并发采集
urls = [f"https://example.com/page/{i}" for i in range(50)]
with ThreadPoolExecutor(max_workers=pool.max_workers) as executor:
futures = {}
for url in urls:
future = executor.submit(pool.request_with_proxy, url)
futures[future] = url
for future in as_completed(futures):
url = futures[future]
try:
resp = future.result()
print(f"[OK] {url} -> {resp.status_code}")
except Exception as e:
print(f"[FAIL] {url} -> {e}")
控制节奏,别把目标站点打崩
time.sleep(random.uniform(0.3, 1.2))
几个关键点说一下:
超时设置一定要分开。连接超时和读取超时是两回事。我一般设连接5秒、读取15秒。如果你把两个都设成30秒,一个慢IP就能把你的线程卡死半分钟,并发量直接腰斩。
重试次数别超过3次。我见过有人设了10次重试,结果一个坏IP被反复请求,目标站点的风控直接把你整个IP段都标记了。3次够了,还不行就换下一个IP。
请求间隔加随机数。别用固定的sleep(1),用random.uniform(0.3, 1.2)这种。固定间隔在流量分析里太明显了,随机间隔能模拟正常用户的访问节奏。
池子要动态补充。短效IP是有生命周期的,你不可能一开始提100个IP就够跑一整天。代码里要监控池子剩余量,低于阈值就自动从API再提一批。神龙HTTP的API接口支持HTTP/HTTPS/SOCKS5,兼容Python、Java、Go这些主流语言,集成起来不复杂,文档里也有现成的示例代码可以参考。
我踩过的几个坑,你大概率也会遇到
坑一:所有请求用同一个User-Agent。你换了100个IP,但UA全是"Python-requests/2.28",目标站点的风控一看,这100个IP的行为特征一模一样,直接判定为同一来源。我的做法是维护一个UA池,每次请求随机取一个,至少准备20个以上不同的UA。
坑二:忽略HTTP/HTTPS的代理协议差异。有些代理在HTTP下正常,切到HTTPS就握手失败。神龙HTTP支持HTTPS协议,但你在代码里配置代理的时候,代理地址本身用http://前缀就行,别写成https://代理地址,否则TLS握手会出问题。这个坑我当年调了整整一个下午。
坑三:不做IP使用量的监控。你买了1000个IP的额度,跑了三天发现只用了200个,剩下800个在池子里过期作废了。或者反过来,你以为够用,结果第三天下午突然池子空了,整个任务停摆。神龙HTTP个人中心有可视化的数据统计面板,IP使用量、使用趋势、异常告警都能看,建议至少每天扫一眼,别等任务挂了才发现问题。
坑四:把代理IP当万能药。有些站点的风控不是看IP,是看请求头里的Cookie、看TLS指纹、看行为轨迹。你IP换得再勤,如果每次请求都带着上一轮的Cookie去访问,照样被识别。该清Cookie清Cookie,该模拟正常浏览路径就模拟,代理IP解决的是"来源"问题,不是"行为"问题。
常见问题
Q1:我的项目日请求量大概50万,用短效动态IP够吗?需要买多少量?
50万日请求量,按每个IP 15分钟存活、平均每个IP能承载50-80次有效请求来算,你同时在线需要的IP数大概在600-1000个左右。神龙HTTP短效动态IP池是3000万+资源每日更新去重,这个量级完全覆盖。计费上支持包量和包时两种,你可以根据自己是"持续跑"还是"跑完就停"来选。如果拿不准,可以先买个小包时套餐跑两天,看看实际消耗再决定。
Q2:我指定了某个城市的IP,但有时候拿到的IP延迟特别高,正常吗?
偶尔出现一两个高延迟IP是正常的,运营商线路本身就有波动。但如果你发现某个城市节点持续高延迟(比如超过200ms),那大概率是线路拥堵或者节点故障。这时候建议做两件事:一是代码里加一个延迟检测,超过阈值的IP直接标记为不可用;二是联系神龙HTTP的技术支持,他们7×24小时在线,可以帮你排查具体节点的情况。如果你的业务对延迟敏感,可以在提取IP的时候同时拉两个相邻城市的节点做备选。
Q3:短效IP 3分钟和30分钟,价格差多少?我该怎么选?
具体价格差取决于你选的计费方式(包量还是包时),但总体规律是存活时间越长,单价越高。选择逻辑很简单:看你的单次任务链路需要多长时间。如果你就是发一个GET请求拿个数据,3分钟绰绰有余,没必要为30分钟多花钱。但如果你要"访问列表→点进详情→翻页→抓数据"这种多步骤流程,整个链路要跑个两三分钟,那至少选10分钟或15分钟的档位,给流程留点余量。别卡着边界选,IP快过期了请求还在路上,体验会很差。
Q4:我同时跑多个采集任务,共用一个代理池会不会互相影响?
会。这是很多人忽略的问题。两个任务共用一个池子,A任务把IP用完了,B任务就取不到IP;A任务请求失败把IP标记为冷却,B任务本来用这个IP好好的,结果也被拉黑了。我的建议是每个独立任务用独立的代理池实例,哪怕底层API是同一个。在代码层面就是每个任务初始化自己的ProxyPool对象,各自管理自己的IP队列和失败记录。如果任务量很大、管理起来麻烦,可以找神龙HTTP的大客户经理聊聊,他们能根据你的业务特点做定制化的资源分配方案,避免多个任务之间的资源争抢。
最后说两句掏心窝的话。代理IP这个东西,工具本身不会让你变强,你怎么用它才会。我见过有人用最贵的固定IP,代码写得一塌糊涂,照样三天两头挂;也见过有人用短效动态IP,代理池管理做得扎实,跑了大半年没出过什么大问题。2026年了,各家服务商的IP质量差距在缩小,真正拉开差距的是你的工程化能力——健康检查、失败重试、并发控制、用量监控,这些东西比"IP池有多大"重要十倍。把基础打扎实了,选一个靠谱的服务商(我目前长期用神龙HTTP,运营商正规授权、IP纯度高、API文档写得清楚、技术支持响应快,综合下来省心),剩下的就是按自己的业务节奏去调参数、调策略,慢慢磨出最适合自己的方案。没有银弹,但有方法论,希望这篇能帮你少走点弯路。


