写爬虫写到一半,目标站点突然给你返回403,或者干脆连接超时,页面一片空白。你盯着屏幕愣了两秒,心里大概就一个念头:这ip是不是被标记了?
说实话,只要你用同一个出口ip连续请求超过几十次,大部分站点的风控机制就会把你"请"出去。这时候你需要的不是换UA、不是加随机延时,而是给每次请求换一个干净的代理ip。今天这篇就专门讲一件事:Python爬虫里,代理ip到底怎么设、怎么轮、怎么从服务商那边动态拉。代码全贴出来,你照着改改参数就能跑。
先搞清楚:代理ip在requests里到底长什么样
很多人第一次用代理,最大的困惑是"这个字典到底怎么填"。其实requests库对代理的支持非常直接,就是一个字典,key是协议,value是代理地址。格式就这一种:
proxies = {
"http": "http://代理ip:端口",
"https": "http://代理ip:端口"
}
response = requests.get("https://目标站点", proxies=proxies, timeout=15)
print(response.status_code) 200 就说明代理生效了
注意一个细节:https请求的代理地址,value前面还是写http://,不是https://。这是requests库的约定,写反了不会报错,但代理根本不会生效,请求还是走你本地网络出去。我见过太多人在这上面卡半小时,就因为这个斜杠后面的协议写错了。
怎么验证代理真的生效了?最简单的办法,请求一个能显示你当前出口ip的页面,看看返回的ip是不是你填的那个代理。如果还是你家里的宽带ip,说明代理没走通,先检查端口和协议。
一个ip不够用?把多个ip塞进列表里轮着来
单个代理ip撑不了几次请求就会被限流。实际项目里,你手里至少得有一小把ip轮着用。写法也不复杂,核心就是每次请求之前随机(或者按顺序)从列表里挑一个:
import requests
import random
import time
proxy_pool = [
"http://203.0.113.10:8080",
"http://203.0.113.11:8080",
"http://203.0.113.12:8080",
"http://203.0.113.13:8080",
"http://203.0.113.14:8080",
]
def build_proxies():
chosen = random.choice(proxy_pool)
return {
"http": chosen,
"https": chosen
}
for i in range(20):
proxies = build_proxies()
try:
resp = requests.get(
"https://目标站点/某页面",
proxies=proxies,
timeout=12,
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
)
print(f"第 {i+1} 次 | 代理: {proxies['http']} | 状态: {resp.status_code}")
except requests.exceptions.Timeout:
print(f"第 {i+1} 次 | 超时,跳过")
except requests.exceptions.ConnectionError:
print(f"第 {i+1} 次 | 连接失败,这个ip可能已失效")
time.sleep(random.uniform(1, 3)) 随机间隔,别太机械
这里有两个小建议。第一,超时时间别设太长,10到15秒足够,代理ip如果15秒内没响应,基本就是废了,没必要干等。第二,请求之间加个随机sleep,1到3秒都行,比固定间隔自然得多,也不容易触发频率检测。
如果你的ip列表是存在文件里的(比如txt一行一个),读进来就行:
with open("proxy_list.txt", "r") as f:
proxy_pool = [line.strip() for line in f if line.strip()]
手动维护ip列表太累?用API动态拉取
上面那种写法适合你手里就固定几个ip的场景。但如果你需要的是持续、稳定、随时可用的代理ip资源,手动维护列表就太痛苦了——今天还能用的ip,明天可能就不行了。
这时候就该上代理服务商的API了。以神龙HTTP为例,它提供短效动态IP、长效静态IP和固定IP三种资源池,全部来自国内三大运营商正规授权,3000万+的ip储备每日更新去重,可用率标称99.9%。你通过它的API接口,每次请求前现拉一个ip,用完即弃(短效)或者按周期复用(长效/固定),完全不用自己操心ip死活的问题。
它支持HTTP/HTTPS/SOCKS5三种协议,300+城市级定位节点,延迟控制得比较紧,高并发提取也没问题。API接口兼容主流爬虫语言,文档里直接给了示例代码,集成成本很低。技术团队是7×24小时在线的,遇到接口调不通之类的情况随时能问到人。
下面是一个典型的"拉ip→用ip→请求目标"的完整流程:
import requests
import random
import time
========== 第一步:从神龙HTTP API获取代理ip ==========
def fetch_proxies(count=5):
"""
调用神龙HTTP API,获取指定数量的代理ip
实际参数名以官方文档为准,这里用通用写法示意
"""
api_url = "API地址(在神龙HTTP控制台获取)"
params = {
"key": "你的API密钥",
"count": count,
"protocol": "http" 支持 http / https / socks5
}
resp = requests.get(api_url, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
返回格式一般是 {"code": 0, "data": ["ip:port", "ip:port", ...]}
return data.get("data", [])
========== 第二步:构建代理字典 ==========
def make_proxies(ip_port):
return {
"http": f"http://{ip_port}",
"https": f"http://{ip_port}"
}
========== 第三步:执行采集 ==========
def crawl_with_proxy(target_url):
ip_list = fetch_proxies(count=5)
if not ip_list:
print("未获取到代理ip,请检查API密钥或余额")
return None
chosen_ip = random.choice(ip_list)
proxies = make_proxies(chosen_ip)
try:
resp = requests.get(
target_url,
proxies=proxies,
timeout=15,
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"
}
)
print(f"使用代理: {chosen_ip} | 状态码: {resp.status_code}")
return resp.text
except Exception as e:
print(f"代理 {chosen_ip} 请求异常: {e}")
return None
跑起来
html = crawl_with_proxy("https://目标站点/某页面")
if html:
print(f"采集成功,内容长度: {len(html)} 字符")
实际项目里,你会把"拉ip"这一步做成一个连接池或者队列,后台线程持续从API取ip放进池子里,前台采集线程从池子里取,用完放回或者丢弃。这样就不存在"每次请求都调一次API"的延迟问题了。神龙HTTP的API本身支持高并发提取,这个架构跑起来压力不大。
短效、长效、固定,到底选哪种?
这是很多人选型时最纠结的点。我直接上对比,省得你来回翻文档:
| 类型 | 存活时长 | 核心特点 | 适合场景 |
|---|---|---|---|
| 短效动态IP | 3/5/10/15/30分钟(可定制) | 3000万+资源每日更新去重,延迟很低,高连通率高并发 | 需要频繁换ip、对ip纯净度要求高、采集频率大的场景 |
| 长效静态IP | 1/4/8/12/24小时(可定制) | 每日去重量10万+,支持指定省份/城市/混播,ip纯净度有保障 | 需要ip存活时间稍长、有地域定位需求、中等频率采集 |
| 固定IP | 长期稳定 | 基于云主机+ISP正式分配,纯净度及可用率99.83%,高连通高稳定 | ip需求量不大、追求很高稳定性、需要固定出口的场景 |
简单说:量大、频率高、怕被封,选短效动态;有地域要求、想省点ip消耗,选长效静态;量小但要求稳,选固定IP。神龙HTTP这三种都是包量或包时计费,个人和企业都能用,不用一上来就签年约。如果你业务比较复杂,比如既要采集又要做AI训练数据准备,他们还有企业定制池,大客户经理一对一帮你出方案,这个后面有需求再聊。
几个容易踩的坑,提前帮你排掉
代理ip看着简单,真跑起来能出的问题比你想的多。下面这几个是我见过出现频率最高的:
坑一:代理设置了但没生效。九成是协议写错了。https请求的代理value里写成了"https://ip:port",应该写"http://ip:port"。还有一种是requests版本太老,升级一下就好。
坑二:代理ip本身是通的,但目标站点不认。有些站点对代理ip段有黑名单,你拿到的ip虽然能上网,但被目标站点识别为代理就给你403。这时候换一批ip试试,或者换一种类型的代理(比如从短效换成固定IP,固定IP是ISP正式分配的,被识别为代理的概率低很多)。
坑三:并发一开,代理全超时。你同时发50个请求,但代理ip的带宽或连接数扛不住。解决办法:控制并发数,或者用神龙HTTP的高并发提取接口多拉几个ip分摊压力。别硬扛,ip不是无限的。
坑四:ip用着用着突然407(需要认证)。说明你的代理需要用户名密码,但代码里没带。在代理地址里加上认证信息就行:
proxies = {
"http": "http://用户名:密码@代理ip:端口",
"https": "http://用户名:密码@代理ip:端口"
}
常见问题
Q1:我设置了proxies参数,但抓包发现请求还是走的本地ip,代理根本没走通,怎么排查?
按这个顺序查:第一,确认代理地址格式对不对,协议头是不是http://(不是https://);第二,用curl单独测一下这个代理能不能通,比如 curl -x http://ip:port https://目标站点,如果curl也通不了,说明代理本身有问题,跟你的代码无关;第三,检查你的代码里有没有其他地方覆盖了proxies参数,比如用了Session对象但没在Session上设代理;第四,看requests版本,太老的版本对某些代理格式支持不好,升级到最新版基本能解决。
Q2:代理ip用了几次就超时了,是不是ip质量不行?
不一定是质量差。短效动态ip本身存活时间就短(3到30分钟),你连续用同一个ip发请求,对方站点可能很快就限流了。这不是ip"坏了",是正常的风控反应。正确做法是不要死磕一个ip,每次请求都从池子里取一个新的,或者用神龙HTTP的API每次现拉。另外检查一下你的请求频率,如果一秒发十几个请求,再好的ip也扛不住,适当加个间隔。
Q3:我的采集任务需要指定某个城市的ip,比如只要杭州的,怎么实现?
神龙HTTP支持300+城市级精准定位,你在API请求参数里指定城市就行。长效静态IP池还支持指定省份、城市或者混播(不指定具体城市,由系统分配)。如果你需要"只要杭州的ip",在拉取时加上城市参数,返回的ip就都是杭州节点的。固定IP池因为是云主机+ISP分配,也可以指定地域。具体参数名看API文档,控制台里都有说明。
Q4:我同时跑好几个采集任务,代理ip会不会互相冲突?
不会。每个任务独立调用API拉ip,或者从自己的池子里取,互不影响。但要注意总并发量——你同时跑5个任务,每个任务10个并发,那就是50个并发在走代理,这时候代理的带宽和连接数就成了瓶颈。神龙HTTP支持高并发提取,但也不是无限制的,建议根据实际ip资源量控制总并发。如果量确实大,走企业定制池让他们的技术团队帮你规划一下资源分配,比你自己硬调参数靠谱。
最后说一句,代理ip这东西,工具选对了,代码写对了,剩下的就是调参数和控节奏。别一上来就追求"每秒几百个请求",先把单次请求跑稳、跑通,再慢慢加并发。ip是消耗品,省着用、换着用,比硬扛一个ip到死要高效得多。神龙HTTP那边有7×24的技术支持,集成过程中遇到接口调不通、参数对不上之类的具体问题,直接找他们的人问,比自己对着文档猜快得多。


