先把角色摆正:代理IP到底帮你干什么
写爬虫的人多半遇到过这种场面:程序头天晚上还跑得顺顺当当,第二天早上一看日志,满屏的连接超时和重复内容。原因不复杂——同一个IP高频次地访问同一个网站,对方迟早会起疑心,轻则让你多等几秒,重则直接不搭理你。
代理IP干的就是这件事:让每次请求从不同的出口出去,目标站看到的是一群"普通访客",而不是一台机器在疯狂敲门。所以它没什么高深的,本质上就是给你的请求换了个出发地点。
但真要用起来,从哪拿IP、怎么挂到请求上、挂错了怎么补救,每一环都有讲究。这篇文章就按实际操作的顺序,把整条链路走一遍。
第一步:从提取接口拿到原始IP
正规的服务商都会给一个提取接口(API),你带着自己的密钥去请求它,它返回一批当下可用的IP地址。以神龙HTTP为例,注册后在个人中心生成专属提取链接,浏览器里打开就能看到返回结果,一行一条,格式一般是"IP:端口"。
程序里接入也很直接:
import requests
# 提取链接在个人中心生成,替换成你自己的
api_url = "https://你的提取链接"
resp = requests.get(api_url, timeout=5)
# 返回内容按行切分,每行一条 "IP:端口"
ip_list = [line.strip() for line in resp.text.split("\n") if line.strip()]
print(f"本次拿到 {len(ip_list)} 条IP")
这里有两个容易踩的坑。一是提取频率别顶满,接口都有调用限制,程序里加个间隔,或者按消耗速度定量补货;二是拿到手先别急着全信,IP是有生命周期的,短效动态IP可能几分钟到几小时就到期,提取和使用之间隔得越久,失效的比例越高。
第二步:把代理挂进请求里
Python的requests库接代理只需要一个字典参数:
proxy = "http://123.45.67.89:8080"
proxies = {
"http": proxy,
"https": proxy,
}
resp = requests.get(
"https://example.com/data",
proxies=proxies,
timeout=(3, 10), # 连接超时3秒,读取超时10秒
)
print(resp.status_code)
几个细节值得说一下。协议要对得上:服务商一般支持HTTP、HTTPS、SOCKS5,你目标站走哪种协议,代理就配对应的写法,前缀别写错。超时要拆开设置,timeout=(3, 10)这种写法把"建立连接"和"等对方回话"分开控制,比笼统给一个大数好得多——连接都建立不起来,等再久也没意义。
还有一点新手常犯:把代理写死在代码里。今天这条IP能用,明天就未必。正确姿势是维护一个IP池(其实就是个列表),每次请求随机取一条,用完的、坏掉的动态剔除,再从提取接口补充新的。
第三步:进池子之前,先验一遍货
不是所有返回的IP都活着。与其让业务代码在运行时撞上死IP,不如在入库前统一筛一遍:
def check_proxy(proxy):
"""探测一条IP是否可用,返回True表示能正常转发"""
try:
# 探测地址换成任意稳定、轻量的页面即可
requests.get(
"https://httpbin.org/ip",
proxies={"http": proxy, "https": proxy},
timeout=5,
)
return True
except Exception:
return False
alive = [p for p in ip_list if check_proxy(p)]
print(f"校验后存活 {len(alive)} / {len(ip_list)} 条")
探测地址选一个稳定、轻量、和目标站无关的页面就行,别拿目标站本身去测——那样等于提前暴露了自己的访问节奏。存活率太低(比如低于一半)的时候,先回头检查提取参数和协议写法,别急着怪IP质量。
第四步:异常处理,决定爬虫能跑多久
前面都顺的话,爬虫能跑起来;但决定它能不能连续跑一整天的,是异常处理。代理场景下的异常就那么几类,见招拆招:
| 异常现象 | 大概率原因 | 建议动作 |
|---|---|---|
| ConnectTimeout | IP已过期或线路慢 | 剔除,取下一条重试 |
| ProxyError | 端口不通或格式写错 | 核对写法,重新提取 |
| 频繁返回验证页 | 单IP请求太密集 | 放慢频率,扩大池子 |
| 返回内容残缺 | 页面结构变了 | 人工看一眼再改解析 |
把这些逻辑落成代码,大概长这样:
import random
import time
import requests
def fetch(url, pool, max_retry=3):
"""带重试的请求:坏IP剔除,好IP复用"""
for _ in range(max_retry):
if not pool:
raise RuntimeError("池子空了,先去提取新IP")
proxy = random.choice(pool)
try:
resp = requests.get(
url,
proxies={"http": proxy, "https": proxy},
timeout=(3, 10),
)
if resp.status_code == 200:
return resp.text
# 状态码不对,这条IP可能已经被目标站留意上了
pool.remove(proxy)
except requests.exceptions.ConnectTimeout:
print(f"[超时] {proxy},重试")
except requests.exceptions.ProxyError:
print(f"[失效] {proxy},剔除")
pool.remove(proxy)
except requests.exceptions.RequestException as e:
print(f"[其他] {e},歇两秒再来")
time.sleep(2)
return None
这段代码有三个设计意图:重试上限——最多试3次,防止在死循环里空转;坏IP即剔——连不上、代理报错的直接移出池子,不给它第二次浪费机会;池子见底要报警——抛出异常提醒你去补充,而不是默默返回空结果,让下游误以为"没采集到数据"。
另外强烈建议把每次请求的结果写进日志:用了哪条IP、耗时多少、返回什么状态。出了问题,日志是唯一能帮你还原现场的东西。神龙HTTP的个人中心里有可视化的用量统计和实时监控,能直接看到提取量、成功率和异常趋势,自己再留一份本地日志,两边对照,排查问题快很多。
第五步:池子的日常维护,比想象中简单
IP池不需要做得很复杂,一个列表加三条规则就够了。
定期体检。每隔几分钟抽几条探测一下,连续两次不通过的踢掉。别全量检测,浪费请求额度。
按需补充。池子低于某个水位(比如50条)就自动调一次提取接口。短效动态IP消耗快,水位可以设高些;长效静态IP稳定,水位可以低些。
分场景调度。对延迟敏感的请求走池子里响应最快的几条;需要稳定长连接的任务单独用长效静态IP或固定IP代理,别和短效IP混在一个池子里互相拖累。
选对服务商,上面一半的活能省掉
自己维护IP池终究是个体力活,IP质量本身才是天花板。如果池子里进来的IP本来就干净、稳定,校验和剔除的工作量会小一大截。
我们实际用下来,神龙HTTP在两个点上比较省心。一是资源底子厚:3000万+正规授权代理IP储备,覆盖300+城市,都是国内三大运营商正规授权的线路,可用率标称99.9%,实际到手基本不用做太多二次筛选。二是接入成本低:提取API兼容主流爬虫编程语言,文档和示例代码给得齐全,Python、Java这些常见技术栈照着抄就能跑通,遇到问题技术团队7×24小时在线,响应不算慢。
产品线也分得清楚:短效动态IP适合高频更换出口的采集任务,长效静态IP和固定IP代理适合需要稳定身份的长期任务,按自己的场景对号入座就行。注册后在个人中心先小量提取测一轮可用率和速度,再决定用哪种,比看任何宣传都实在。
常见问题
Q: 提取出来的IP放了一会儿就失效,正常吗?
正常。短效动态IP的设计就是短生命周期,几分钟到几小时不等。正确用法是"随用随提、用前校验",别一次提一大堆囤着慢慢用。需要长期稳定的场景,直接选长效静态IP或固定IP代理。
Q: 挂了代理之后请求反而变慢了,怎么回事?
先看三件事:代理节点和你服务器的距离远不远,尽量选同城或邻近城市的节点;超时是不是设得太宽,把连接超时压到3秒以内能快速淘汰慢线路;池子里是不是混进了高延迟的IP,跑一轮测速把慢的剔掉。正规服务商的线路延迟通常在几十毫秒量级,明显不对劲就取另一条对比一下。
Q: 重试几次合适?池子要多大才够用?
重试2到3次是经验值,再多基本是在浪费时间和请求额度。池子大小取决于目标站的强度和你的采集节奏:请求频率低的小任务,几十条轮着用就够;全天候跑的任务,建议几百条起步,并且把自动补货做成水位触发的,别等池子空了才手动去提。
Q: 不太会写代码,也能用代理IP吗?
能。提取和接入本质上就是调一个接口,神龙HTTP提供完整的文档和示例代码,主流编程语言都有现成写法,照着改两个参数就能跑。实在卡住了,直接找他们的技术支持,7×24小时都有人,把你的报错信息发过去,一般很快能给到排查方向。





