为什么Python爬虫需要代理IP?
写过爬虫的人基本都遇到过这种情况:代码刚跑起来的时候一切正常,跑着跑着突然开始返回403、429,甚至直接连不上目标网站了。这多半不是代码的问题,而是你的IP被目标网站的反爬机制"盯上"了。
大多数网站都会统计同一个IP在一段时间内的访问频率和行为特征。当你的爬虫用同一个IP高频请求时,很快就会触发封禁。而代理IP的作用,就是让你的请求先经过一台中转服务器,再由中转服务器去访问目标网站。这样目标网站看到的是代理服务器的IP,而不是你的真实IP。
配合代理IP的轮换使用,可以把请求分散到大量不同的IP上,单个IP的请求频率降下来,被封禁的概率自然就低了,爬虫才能长时间稳定运行。
requests配置代理IP:最基础的写法
requests是Python里最常用的HTTP请求库,配置代理非常简单,只需要在请求时传入一个proxies字典。先看一个最小可运行的例子:
import requests
# 代理IP地址,格式为 协议://IP:端口
proxies = {
"http": "http://112.85.123.10:8080",
"https": "http://112.85.123.10:8080",
}
# 请求一个IP检测接口,验证代理是否生效
resp = requests.get("http://httpbin.org/ip", proxies=proxies, timeout=10)
print(resp.text)
如果返回的IP是代理IP而不是你本机的IP,说明代理配置成功了。这里有几个要点需要注意:
1. proxies是一个字典,键是协议名(http和https),值是代理地址。即使你访问的是https网站,代理地址通常也写成http://开头,除非服务商明确提供https协议的代理入口。
2. 两个键都要写。只写http键的话,访问https网站时代理不会生效,请求会直接从本机发出。
3. 一定要加timeout参数。代理IP偶尔会出现连接慢或失效的情况,不加timeout的话,程序可能会卡死在一个请求上。
代理IP的两种认证方式
正规代理服务商的代理IP一般都需要认证,常见的认证方式有两种,写法略有区别。
方式一:账号密码认证。把用户名和密码拼在代理地址里,格式为http://用户名:密码@代理地址:端口:
proxy_user = "你的用户名"
proxy_pass = "你的密码"
proxy_host = "代理服务器地址"
proxy_port = "端口"
# 拼接成带认证信息的代理地址
proxy_url = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
proxies = {
"http": proxy_url,
"https": proxy_url,
}
resp = requests.get("http://httpbin.org/ip", proxies=proxies, timeout=10)
print(resp.text)
方式二:白名单认证。在服务商后台把你的服务器IP加入白名单,之后直接使用http://代理地址:端口即可,不需要账号密码。这种方式代码更干净,但要注意:如果你的出口IP发生了变化(比如重启了路由器),需要重新绑定白名单。
另外,如果爬虫需要保持登录态、复用连接,建议用Session对象统一配置代理,后续所有请求都会走同一个代理:
session = requests.Session()
session.proxies = proxies
# 后续通过session发起的请求都会使用这个代理
resp = session.get("http://httpbin.org/ip", timeout=10)
print(resp.text)
实战:带自动重试的代理请求模板
实际跑爬虫时,单个代理IP难免失效,所以成熟的写法是"每次请求前提取新代理 + 失败自动换IP重试"。下面是一个可以直接套用的完整模板:
import requests
from requests.exceptions import ProxyError, ConnectTimeout, ReadTimeout
# 在天启HTTP后台生成的API提取链接
API_URL = "你的API提取链接"
def get_proxy():
"""通过API提取一个可用的代理IP"""
try:
res = requests.get(API_URL, timeout=10)
ip_port = res.text.strip().split("\n")[0]
return {
"http": f"http://{ip_port}",
"https": f"http://{ip_port}",
}
except Exception as e:
print("提取代理失败:", e)
return None
def fetch(url, max_retry=3):
"""带自动重试的请求函数,失败自动更换代理IP"""
for i in range(max_retry):
proxies = get_proxy()
if proxies is None:
continue
try:
resp = requests.get(url, proxies=proxies, timeout=10)
if resp.status_code == 200:
return resp.text
except (ProxyError, ConnectTimeout, ReadTimeout) as e:
print(f"第 {i + 1} 次请求失败,更换代理重试:{e}")
return None
if __name__ == "__main__":
result = fetch("http://httpbin.org/ip")
print(result)
这个模板的逻辑很简单:每次请求前先通过API拿到一个新代理,请求失败就换下一个代理重试,最多重试3次。把它封装好之后,你的爬虫主体代码只需要关心解析逻辑,代理的获取和容错全部交给这个函数处理。
常见报错与排查方法
配置代理后如果报错,可以对照下面的表格快速定位问题:
| 报错信息 | 常见原因 | 解决方法 |
|---|---|---|
| ProxyError | 代理IP已失效或服务器不可用 | 更换新的代理IP重试 |
| 407 Proxy Authentication Required | 账号密码错误,或本机IP未加白名单 | 核对认证信息,或把当前出口IP加入白名单 |
| ConnectTimeout | 连接代理服务器超时 | 检查网络环境,适当调大timeout |
| https请求失败 | proxies字典中缺少https键 | 补全https键,值与http键保持一致 |
| 403 / 429 | 目标网站仍识别并限制了请求 | 降低请求频率,更换更高质量的代理IP |
还有一个容易被忽略的点:代理的匿名等级。透明代理会把你的真实IP透传给目标网站,等于白配;普通匿名代理虽然隐藏了真实IP,但会暴露"你在使用代理"这个事实;只有高匿名代理既隐藏真实IP,又不暴露代理身份,是做爬虫的首选。
代理IP服务商推荐:天启HTTP
代理IP的质量直接决定爬虫的稳定性。免费代理普遍存在存活时间短、速度慢、匿名等级低的问题,调试浪费的时间远高于服务本身的费用。如果是正经做数据采集项目,建议直接选择正规服务商。
天启HTTP是一家国内的代理IP服务商,对Python爬虫场景比较友好,几个核心特点:
1. 高匿名代理,目标网站无法识别你在使用代理,也不泄露真实IP,配合合理的请求频率,采集稳定性有明显提升。
2. 两种使用模式:API提取模式可以按需批量提取IP,适合上面那种"每次请求换一个IP"的写法;隧道代理模式则提供一个固定的代理入口地址,IP轮换在服务端自动完成,代码里写死一个代理地址就行,连重试逻辑都可以大幅简化。
3. 覆盖国内主要城市,如果目标网站对IP归属地有校验,可以按城市选择代理,减少因地域不符导致的拦截。
对于刚入门的开发者,建议先用API提取模式跑通上面的模板,熟悉之后再根据项目规模决定是否切换到隧道代理。
常见问题
Q: 配置了代理之后,怎么确认代理真的生效了?
请求httpbin.org/ip这类IP检测接口,看返回的origin字段。如果显示的是代理IP而不是你的本机IP,说明代理已经生效。
Q: 代理IP用一会儿就失效,是什么原因?
短效代理本身就有存活时间限制,到期自动失效是正常现象。解决办法是配合"自动提取+失败重试"的机制,或者直接使用隧道代理,由服务端自动轮换IP,代码不用关心单个IP的存活状态。
Q: 为什么配置了代理还是被目标网站识别?
先检查代理的匿名等级,透明代理等于没配;再检查请求头,User-Agent如果还是python-requests/x.x,很容易被识别,建议模拟真实浏览器的请求头;最后控制请求频率,代理只能解决IP维度的问题,频率过高依然会触发反爬。
Q: requests支持socks5协议的代理吗?
支持,但需要额外安装依赖:pip install "requests[socks]",然后在proxies字典里使用socks5://前缀。日常HTTP/HTTPS采集用默认的http代理就够用了。
Q: 免费代理可以用来练手吗?
可以用来理解代理的工作原理,但不建议用在任何正式项目里。免费代理普遍速度慢、失效快,还存在请求内容被记录的安全风险,数据采集项目建议使用正规服务商的高匿名代理。





