上周帮一个做电商数据监控的朋友调爬虫,他代码写了两个月,逻辑没问题,数据也抓得回来,但一跑超过两百条请求,目标站点直接把他IP封了。折腾了三天,最后发现卡点根本不在代码上,而是没有给爬虫配代理IP。这事儿其实挺典型的——很多人写爬虫只盯着解析逻辑和反爬对抗,却忽略了最底层、也最容易被忽视的一环:你的请求是从哪个IP发出去的。
这篇教程不聊什么高深的分布式架构,就讲一件事:从零开始,怎么给你的爬虫搭一套能用的代理IP体系,从选IP、配代码、做轮换到日常维护,全部跑通。看完你就能自己搭起来,不用再去群里问"大佬这个IP怎么配"了。
先搞清楚:你的爬虫到底需不需要代理IP
不是所有爬虫都得挂代理。如果你只是偶尔抓个几十条公开页面,频率很低,目标站点也没有严格的访问控制,那直接用本机IP就行,没必要多此一举。
但下面这几种情况,代理IP基本是刚需:
第一,请求频率上来了。哪怕你只是每五分钟抓一次数据,一天下来也是288次请求。目标站点的WAF(Web应用防火墙)对同一IP的访问频率是有阈值的,超了就直接403或者弹验证码。
第二,你需要采集的数据量比较大。比如做市场研究,要覆盖全国300多个城市的门店信息,或者做AI训练需要采集大量公开语料,这种场景下单一IP根本扛不住。
第三,目标站点有IP维度的访问限制。有些平台对同一IP的日请求量有硬性上限,你就算把请求间隔拉到30秒,一天也就抓个几百条,效率太低。
简单说,只要你的爬虫不是"跑一次就完事"的脚本,而是需要持续、稳定、有一定量级的数据采集,代理IP就是基础设施,跟你的服务器、数据库一样,是必须提前规划好的。
搭建之前,先把这几个坑踩明白
我见过太多人上来就"搞个代理IP池",结果用了一周发现全是坑。在动手之前,有几个问题你得先想清楚:
你要的是动态IP还是固定IP? 这俩东西用途完全不同。动态IP是每次请求(或者每隔几分钟)换一个出口IP,适合高频采集、需要大量不同IP的场景。固定IP是给你一个长期不变的IP,适合需要"记住"你身份的场景,比如登录态维护、API调用等。选错了,后面全白搭。
你的目标站点在哪个地区? 如果你采集的是国内电商数据,那IP的地理位置最好覆盖对应城市。有些站点会根据IP归属地返回不同的内容,IP地域不对,你抓回来的数据可能压根不是你要的。
你的并发量大概是多少? 这个直接决定了你需要多大的IP池。如果你同时跑10个线程,每个线程每秒发2个请求,那你的IP池至少得能支撑20个并发连接不出现排队。IP池太小,所有请求挤在几个IP上,等于没挂代理。
你的预算是多少? 代理IP不是免费的(免费的可用率惨不忍睹,后面会说)。先算清楚你每天大概需要消耗多少IP,再去看服务商的计费方式,别到时候发现一天烧掉几百块。
代理IP从哪来?别自己养了
先说结论:除非你是做网络安全研究的,否则别自己搭代理IP池。 自己养IP意味着你要去搞大量的宽带线路、做IP清洗、维护可用性,这套东西的运维成本远超你直接买商用代理。而且自己抓的IP质量参差不齐,被封的概率很高。
商用代理IP服务商的核心价值就三点:IP来源正规、可用率有保障、有API接口方便集成。
我目前比较推荐的是神龙HTTP,简单说下为什么:
它家的IP资源来自国内三大运营商的正规授权,不是那种来路不明的"野IP"。资源储备在3000万+,每天更新去重,IP纯度标称99.8%,实际用下来可用率确实能到99.9%左右。覆盖300多个城市级节点,你采集哪个城市的数据,就能指定对应地区的IP出口,这个对做本地化数据采集的人来说非常实用。
协议方面支持HTTP、HTTPS、SOCKS5,主流爬虫框架基本都能直接对接。API接口兼容Python、Java、Go这些常见语言,文档写得也比较清楚,不用对着接口猜参数。
套餐类型上,我根据实际使用场景简单列一下:
| 套餐类型 | IP存活时间 | 适合场景 | 计费方式 |
|---|---|---|---|
| 短效动态IP池 | 3/5/10/15/30分钟(可定制) | 高频采集、大规模数据抓取、需要频繁更换IP的场景 | 包量/包时 |
| 长效静态IP池 | 1/4/8/12/24小时(可定制) | 中等频率采集、需要IP保持一定稳定性的任务 | 包量/包时 |
| 固定IP池 | 长期不变 | 登录态维护、API对接、对稳定性要求很高的场景 | 按个数包时 |
如果你刚起步,建议先用短效动态IP池跑通流程,体验一下API调用和IP轮换的完整链路。等你的业务稳定了、对IP稳定性有要求了,再考虑上固定IP或者企业定制方案。神龙HTTP那边有7×24小时的技术支持,集成过程中遇到接口问题可以直接问,不用自己对着文档死磕。
动手写代码:Python + 代理IP 跑通第一个请求
下面用Python的requests库演示,怎么把代理IP配进你的爬虫里。假设你已经从神龙HTTP的API获取到了一个代理IP(格式为 http://用户名:密码@IP:端口)。
第一步:通过API获取代理IP
import requests
神龙HTTP的API接口(具体地址在控制台获取)
api_url = "https://api.shenlongip.com/get_ip"
api_params = {
"username": "你的账号",
"password": "你的密码",
"protocol": "http", 协议类型:http / https / socks5
"city": "杭州", 指定城市,不填则随机
"count": 1 获取数量
}
resp = requests.get(api_url, params=api_params, timeout=10)
proxy_ip = resp.json()["data"][0] 例如: "http://user:pass@120.25.34.16:8080"
print(f"获取到代理IP: {proxy_ip}")
第二步:用代理IP发起HTTP请求
import requests
def fetch_with_proxy(url, proxy_ip, headers=None):
"""
通过代理IP访问目标URL
:param url: 目标地址
:param proxy_ip: 代理IP,格式 http://user:pass@ip:port
:param headers: 自定义请求头
:return: 响应对象
"""
proxies = {
"http": proxy_ip,
"https": proxy_ip
}
if headers is None:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36"
}
try:
resp = requests.get(
url,
proxies=proxies,
headers=headers,
timeout=15,
verify=True HTTPS请求时验证证书
)
resp.raise_for_status()
return resp
except requests.exceptions.ProxyError:
print(f"[警告] 代理IP {proxy_ip} 连接失败,需要更换")
return None
except requests.exceptions.Timeout:
print(f"[警告] 请求超时,代理IP {proxy_ip} 可能已失效")
return None
except requests.exceptions.HTTPError as e:
print(f"[错误] HTTP {e.response.status_code}")
return None
测试一下
target_url = "https://www.example.com/data"
result = fetch_with_proxy(target_url, proxy_ip)
if result:
print(f"状态码: {result.status_code}")
print(f"响应长度: {len(result.text)} 字符")
第三步:封装一个带自动换IP的采集函数
实际使用中,一个IP不可能永远好用。你需要一个机制:当前IP请求失败或者被限流了,自动从池子里拿一个新的。
import time
import random
class er:
def __init__(self, api_url, username, password, city=None):
self.api_url = api_url
self.username = username
self.password = password
self.city = city
self.current_proxy = None
self.fail_count = 0
self.max_fail = 3 连续失败3次就换IP
def get_new_proxy(self):
"""从神龙HTTP API获取一个新的代理IP"""
params = {
"username": self.username,
"password": self.password,
"protocol": "http",
"count": 1
}
if self.city:
params["city"] = self.city
resp = requests.get(self.api_url, params=params, timeout=10)
data = resp.json()
if data.get("code") == 200:
self.current_proxy = data["data"][0]
self.fail_count = 0
print(f"[INFO] 已更换代理IP: {self.current_proxy}")
return self.current_proxy
else:
raise Exception(f"获取代理IP失败: {data.get('msg')}")
def fetch(self, url, headers=None, retries=3):
"""带自动换IP的采集方法"""
for attempt in range(retries):
if self.current_proxy is None:
self.get_new_proxy()
result = fetch_with_proxy(url, self.current_proxy, headers)
if result is not None:
return result
请求失败,累计失败次数
self.fail_count += 1
if self.fail_count >= self.max_fail:
print(f"[INFO] 连续失败{self.fail_count}次,更换代理IP...")
self.get_new_proxy()
随机等待,避免触发频率限制
time.sleep(random.uniform(1, 3))
return None
使用示例
crawler = er(
api_url="https://api.shenlongip.com/get_ip",
username="你的账号",
password="你的密码",
city="上海"
)
采集一个页面
response = crawler.fetch("https://www.example.com/page1")
if response:
print(f"采集成功,内容长度: {len(response.text)}")
这套代码跑起来,你的爬虫就具备了"IP不够用自动换、IP失效自动补"的能力。核心逻辑不复杂,但一定要做好异常处理,别一个IP挂了整个爬虫就崩了。
代理IP的轮换策略,别傻乎乎用一个IP打到死
很多人拿到代理IP后,写个for循环把池子里的IP轮一遍就完事了。实际跑起来你会发现,这种"平均分配"的策略效果很差。原因是:不同IP的"体质"不一样,有的IP刚出来就很好用,有的IP可能已经被目标站点标记过了。
我实际项目中比较稳定的轮换策略是这样的:
按失败率淘汰,而不是按时间淘汰。 每个IP维护一个滑动窗口(比如最近20次请求),如果失败率超过30%,就把它标记为"待观察";超过50%,直接踢出当前池子,从API重新拉一个。这比"每5分钟换一次IP"要聪明得多,因为你不会把一个好IP给浪费了。
同一IP的两次请求之间,加随机间隔。 别用固定的sleep(2),用 time.sleep(random.uniform(1.5, 4.0)) 这种。固定间隔太容易被识别为机器行为。
高并发场景下,一个IP同时只跑1-2个线程。 你开20个线程全挤在一个IP上,那跟没挂代理没区别。神龙HTTP的短效动态IP池支持高并发提取,但你的代码层面也要做好IP和线程的绑定关系,别搞混了。
下面是一个简单的IP池管理器的思路:
from collections import deque
import threading
class IPPool:
def __init__(self, max_size=50):
self.pool = deque(maxlen=max_size)
self.lock = threading.Lock()
self.stats = {} ip -> {"success": 0, "fail": 0}
def add_ip(self, ip):
with self.lock:
if ip not in self.pool:
self.pool.append(ip)
self.stats[ip] = {"success": 0, "fail": 0}
def get_ip(self):
"""获取一个可用IP(优先选成功率高的)"""
with self.lock:
if not self.pool:
return None
按成功率排序,取最高的
best_ip = max(self.pool, key=lambda ip: self._success_rate(ip))
return best_ip
def report(self, ip, success):
"""上报IP使用结果"""
with self.lock:
if ip in self.stats:
self.stats[ip]["success" if success else "fail"] += 1
失败率超过50%且总请求数>10,踢出池子
total = self.stats[ip]["success"] + self.stats[ip]["fail"]
if total > 10 and self._success_rate(ip) < 0.5:
self.pool.remove(ip)
del self.stats[ip]
print(f"[INFO] IP {ip} 失败率过高,已移除")
def _success_rate(self, ip):
s = self.stats.get(ip, {"success": 0, "fail": 0})
total = s["success"] + s["fail"]
return s["success"] / total if total > 0 else 0.5
这个池子不大,但核心逻辑是对的:好的IP多用,差的IP淘汰,池子始终维持在健康状态。配合神龙HTTP的API随时补充新IP,整个系统就能稳定跑下去。
怎么判断你的代理IP质量行不行
别光看服务商宣传页上写的"可用率99.9%",你得自己验。我一般用下面这几个维度来测:
连通性测试: 拿100个IP,每个发一个GET请求到 https://httpbin.org/ip(或者任何公开的测试端点),看返回的IP是不是跟你拿到的一致。如果返回的IP跟你拿到的不一样,说明中间经过了二次转发,这种IP质量要打问号。
延迟测试: 记录每个IP从发请求到收到响应的耗时。神龙HTTP标称低延迟,实际测下来国内节点一般在50-150ms之间。如果你的IP延迟普遍超过500ms,那采集效率会大打折扣。
存活时间验证: 短效IP标称30分钟有效,你拿到后第25分钟再请求一次,看还能不能用。如果提前就失效了,那你的轮换频率得相应调高。
纯净度抽检: 拿几个IP去访问一些对IP质量敏感的网站(比如某些银行、政务平台的公开页面),看会不会直接弹验证码或者拒绝访问。如果大量IP被识别为"代理",那这个IP池的纯净度就不达标。
我一般写个简单的脚本,每天凌晨自动跑一轮检测,把结果存到数据库里。哪天的IP质量突然下降了,第二天就能发现,不至于等爬虫大面积报错才去排查。
常见问题
Q1:我用了代理IP,但目标站点还是返回403,是不是IP被识别了?
不一定是IP的问题。403可能是你的请求头太"裸"了——User-Agent、Referer、Accept这些字段没设全,或者你的请求频率还是太高。先检查你的headers是不是模拟了一个正常的浏览器,再确认你的请求间隔是不是足够随机。如果这些都做了还是403,那大概率是IP确实被标记了,换一个IP试试。如果换了好几个IP都是403,那可能是目标站点的反爬策略升级了,需要调整你的采集策略(比如加cookie、模拟JS执行等)。
Q2:短效IP和长效IP到底怎么选?我两个都买会不会浪费?
不冲突,用途不同。如果你的业务是"今天抓一批数据,明天再抓一批",中间不需要保持登录态,那短效动态IP就够了,成本也低。但如果你有一个长期运行的监控任务,需要每天定时去同一个页面看数据变化,而且目标站点会记住你的IP(比如给你分配了一个session),那你就需要固定IP或者长效IP来保持"身份"不变。实际项目中,很多人是短效IP做主力采集,固定IP做登录和状态维护,两个搭配着用,不浪费。
Q3:我的爬虫是Java/Go写的,神龙HTTP的API能对接吗?
能。神龙HTTP的API是标准的HTTP接口,返回JSON格式,任何能发HTTP请求的语言都能调。Python、Java、Go、Node.js、PHP都没问题。他们的文档里有各语言的示例代码,照着改就行。如果你用的是Go的goproxy或者Java的Apache HttpClient,配置代理的方式跟Python的requests类似,都是把 http://user:pass@ip:port 这个字符串填到代理配置里。
Q4:IP池用着用着突然大面积失效了,怎么排查?
先别慌,按这个顺序查:第一,看是不是你自己的网络环境变了(比如你换了服务器、换了出口IP);第二,调一下神龙HTTP的API,看返回的IP是不是正常的,如果API本身返回异常,联系他们的技术支持;第三,拿返回的IP手动curl一下,看能不能通;第四,如果IP本身没问题但你的爬虫大面积失败,检查是不是目标站点临时加了新的反爬规则。神龙HTTP那边有个人中心可以查看IP使用趋势,如果某一时段失败率突然飙升,在后台一眼就能看出来,不用自己一个个IP去测。
最后说两句
代理IP这件事,说复杂也复杂,说简单也简单。核心就三件事:选对IP类型、把代码里的代理配置写对、做好IP的生命周期管理。别一上来就搞什么百万IP池、分布式调度,先把单线程+代理IP跑通,确认你的采集逻辑没问题,再考虑扩展。
工具选对了,后面就是调参数的事。神龙HTTP的API文档写得比较细,控制台里也有用量统计和IP使用趋势的可视化面板,你不用自己再搭一套监控。把精力放在你的业务逻辑上,IP的事交给服务商,这才是合理的分工。
跑通第一个请求之后,剩下的就是持续优化了。祝你的爬虫稳定运行,别再半夜被403叫醒。


