Python 爬虫代理 IP 怎么用?requests 代理、隧道代理与 403 排查
爬虫遇到 403、验证码、IP 被封怎么办?本文从代理 IP 原理、requests proxies 写法、账号密码认证、短效代理和隧道代理选择、失败重试与合规边界讲清排查思路。
爬虫什么时候需要代理 IP
同一段爬虫代码,前几次请求正常,连续跑一会儿之后突然变成 403、验证码、空数据,或者接口直接提示访问受限,这时就要考虑是不是触发了 IP 维度的风控。

代理 IP 不是万能钥匙,它主要解决的是“目标服务器看到的访问出口是谁”这个问题。请求没有加代理时,目标站点看到的是你的本机出口 IP;请求加了代理后,请求会先到代理服务器,再由代理服务器访问目标站点,目标站点看到的就是代理服务器的出口 IP。
所以,代理 IP 适合这些场景:
- 学习或授权测试环境中,接口按 IP 限制访问频率。
- 同一 IP 连续请求后出现 403、验证码或临时封禁。
- 需要验证目标服务看到的出口 IP、请求头、Cookie 是否符合预期。
- 爬虫任务已经做好限速、超时、重试,但仍然被 IP 维度拦截。
反过来,如果问题出在 Cookie 失效、请求头缺失、接口参数错误、JS 渲染没处理,单纯换代理通常没有用。代理只换出口,不会自动补全登录态、请求签名和浏览器环境。
代理 IP 的工作方式
普通请求链路是:
你的程序 -> 目标网站
加代理之后,链路会变成:
你的程序 -> 代理服务器 -> 目标网站
目标网站通常只能看到代理服务器的出口 IP,而不是你本机的真实出口 IP。课程第 63 节里用“回显请求信息”的接口演示过这一点:不加代理时,接口返回的是本机出口 IP;加代理后,接口返回的 IP 会变成代理出口。
这也是代理能缓解 IP 封禁的原因:被限制的是访问出口,不一定是你的机器本身。
不过这里要分清两个地址:
| 名称 | 含义 | 常见表现 |
|---|---|---|
| 代理入口 | 你的程序连接的代理地址 | 域名或 IP + 端口 |
| 代理出口 | 代理服务器访问目标站点时暴露的 IP | 目标站点真正看到的 IP |
有些代理入口和出口是同一个 IP,有些代理会经过中转,入口和出口并不一致。判断代理是否生效时,不要只看你填进代码里的代理地址,要看目标服务器最终看到的出口 IP。
requests 代理怎么写
在 requests 里,代理通过 proxies 参数传入。它是一个字典,分别指定 http 和 https 请求使用哪个代理。
import requests
url = "https://httpbin.org/ip"
proxies = {
"http": "http://123.4.5.6:9999",
"https": "http://123.4.5.6:9999",
}
response = requests.get(url, proxies=proxies, timeout=10)
print(response.text)
这里最容易误解的是 https 这一项。它表示“访问 HTTPS 目标地址时使用这个代理”,不表示代理服务器本身一定要用 HTTPS 协议。很多 HTTP 代理也可以代理 HTTPS 目标站点。
如果代理只支持 HTTP,就不要写成 https://123.4.5.6:9999。代理协议、目标网站协议、字典里的键名,是三个不同概念。
账号密码认证代理怎么写
付费代理通常需要账号密码。最常见的写法是把账号密码放进代理 URL:
import os
from urllib.parse import quote
import requests
proxy_host = "proxy.example.com"
proxy_port = "8000"
# 账号密码不要硬编码到源码里,建议从环境变量读取
proxy_user = quote(os.environ["PROXY_USER"], safe="")
proxy_pass = quote(os.environ["PROXY_PASS"], safe="")
proxy_url = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
proxies = {
"http": proxy_url,
"https": proxy_url,
}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.text)
如果账号或密码里包含 @、:、/ 这类特殊字符,直接拼进 URL 可能会解析错,所以这里用 quote 做了一次编码。
课程代码同步仓库可以放公共示例,但不要把真实代理账号、密码、AuthKey、提取链接提交进去。代理凭证一旦泄露,很容易被别人刷完额度。
短效代理、隧道代理、代理池怎么选
不同代理产品的使用方式差别很大。初学者不要先纠结品牌,先把类型分清。
| 类型 | 工作方式 | 适合场景 | 注意点 |
|---|---|---|---|
| 短效提取代理 | 先调用提取接口拿一个 IP,再把这个 IP 写入 proxies |
小规模练习、单次任务、手动验证 | IP 有效期短,需要自己处理失效和重取 |
| 隧道代理 | 代理入口固定,服务商在后面自动换出口 IP | 不想自己维护代理切换逻辑 | 不一定能随时强制换 IP,要看产品规则 |
| 自建代理池 | 自己维护可用代理、失效检测、评分和调度 | 长期任务、复杂采集系统 | 维护成本高,免费代理质量通常很差 |
| 免费代理 | 网上公开可搜到的代理 | 临时测试代理参数写法 | 慢、不稳定、失效率高,不适合正式任务 |
课程第 63 节里演示过两种常见流程:一种是手动提取短效 IP,再写入 proxies;另一种是使用固定隧道入口,让服务商自动切换出口 IP。真正做项目时,建议先从隧道代理或稳定付费代理开始,别把时间浪费在大量不可用的免费代理上。
短效代理如何自动重取
短效代理的问题是有效期短。手动复制一个 IP 可以演示原理,但写进爬虫任务里,就要考虑失败后自动重取。
下面是一个简化版写法。真实代理平台返回格式不同,你需要按实际文档解析。
import time
import requests
from requests import RequestException
PROXY_API = "https://proxy.example.com/get"
def fetch_proxy():
response = requests.get(PROXY_API, timeout=5)
response.raise_for_status()
# 假设平台直接返回 123.4.5.6:9999
proxy_addr = response.text.strip()
return f"http://{proxy_addr}"
def request_with_proxy(url, max_retries=3):
last_error = None
for attempt in range(max_retries):
proxy_url = fetch_proxy()
proxies = {
"http": proxy_url,
"https": proxy_url,
}
try:
response = requests.get(url, proxies=proxies, timeout=10)
if response.status_code != 403:
return response
except RequestException as exc:
last_error = exc
# 失败后稍微停一下,避免连续打满目标站点和代理服务
time.sleep(1 + attempt)
if last_error:
raise last_error
raise RuntimeError("代理重试后仍然被拒绝")
这段代码的重点不是“无限换 IP”,而是给失败设置边界:最多重试几次、每次有超时、失败后停一下。爬虫稳定性不是靠疯狂请求堆出来的,而是靠限速、超时、重试和状态判断一起配合。
如果你还没处理过 timeout、ConnectionError、HTTPError 这些异常,可以先看 Python 爬虫 requests 异常处理完全指南。
Session、Cookie 和代理要一起看
很多人遇到 403 后第一反应是换代理,但真实原因可能是登录态丢了。
例如一个接口需要先访问首页拿 Cookie,再请求数据接口。如果你每次都用新的 requests.get(),Cookie 没有被自动保留,目标站点可能会把你当成异常请求。
这种场景应该先用 Session 保持 Cookie:
import requests
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0",
})
proxy_url = "http://123.4.5.6:9999"
session.proxies.update({
"http": proxy_url,
"https": proxy_url,
})
# 先访问首页,让 Session 保存服务器下发的 Cookie
session.get("https://example.com/", timeout=10)
# 再请求数据接口,Cookie 会自动带上
response = session.get("https://example.com/api/data", timeout=10)
print(response.status_code)
如果用了代理还是 403,排查顺序建议是:
- 先确认目标接口是否需要登录态或 Cookie。
- 再确认
User-Agent、Referer、Accept等请求头是否缺失。 - 然后检查请求频率是否过高。
- 最后再判断是否需要换代理 IP。
Cookie 自动保持和验证码重试可以继续看 requests Session 教程:Cookie 自动保持、验证码重试与 403 排查。
aiohttp 和 Playwright 里怎么加代理
如果你用的是 aiohttp,代理通常写在单次请求的 proxy 参数里:
import aiohttp
async def fetch(session, url, proxy_url):
async with session.get(url, proxy=proxy_url, timeout=10) as response:
return await response.text()
异步爬虫一定要额外注意并发数。代理 IP 能换出口,但不能替你承受无限并发。用 aiohttp 时建议配合 asyncio.Semaphore 控制并发,具体可以看 Python aiohttp 教程:异步请求、并发爬虫与超时重试完整指南。
如果你用的是 Playwright,代理通常在启动浏览器时配置:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": "http://123.4.5.6:9999",
}
)
page = browser.new_page()
page.goto("https://example.com")
print(page.title())
browser.close()
动态网页、JS 渲染、接口找不到时,Playwright 比单纯换代理更重要。相关基础可以看 Playwright Python 教程:从安装到动态网页自动化实战。
403 和 IP 封禁的排查清单
遇到 403,不要一上来就写代理池。先按下面顺序排查:
- 看状态码和响应内容:确认是 403、验证码页、空数据,还是接口参数错误。
- 看是否只有连续请求才失败:第一次正常,连续多次失败,更像频率或 IP 风控。
- 看请求头是否完整:特别是
User-Agent、Referer、Accept、Content-Type。 - 看 Cookie 是否保持:登录后接口、验证码接口、下单接口通常都依赖 Cookie。
- 看是否需要 JS 渲染:源代码里没有数据,不代表接口拿不到,可能需要分析 Network。
- 看请求频率是否过高:同一秒大量请求,即使用代理也容易被拦。
- 最后再换代理 IP:代理是出口层面的解决方案,不是所有 403 的根因。
请求头排查可以看 HTTP 请求头与响应头实战;静态页面和动态页面判断可以看 网页源代码和 Elements 有什么区别。
不要把代理当成“无限请求许可证”
代理 IP 只能降低单一出口 IP 被限制后的影响,不能改变爬虫行为本身。如果请求频率过高、采集范围过大、抓取了不该抓的数据,换代理只会把风险放大。
写爬虫代理逻辑时,至少要守住几条底线:
- 只在学习、测试、授权或合规范围内使用。
- 不采集、扩散个人敏感信息。
- 给每个请求设置超时,不让任务无限挂起。
- 给重试设置上限,不做无限循环。
- 给并发设置上限,不把目标服务打崩。
- 发现异常拦截、验证码、封禁提示时,先降频或停止排查。
如果你不确定某个采集行为是否合适,先看 爬虫合法吗?一文讲清爬虫法律边界与风险。
常见问题
免费代理能不能用?
可以用来测试 proxies 参数写法,但不建议用于正式任务。免费代理常见问题是可用率低、速度慢、出口混乱、随时失效。你会把大量时间花在“这个代理到底还能不能用”上,而不是解决真正的采集逻辑。
为什么换了代理还是 403?
通常是因为 403 的原因不是 IP。常见原因包括 Cookie 缺失、请求头不完整、接口参数错误、访问频率异常、页面需要 JS 渲染、账号状态异常等。代理只改变出口 IP,不会自动模拟真实浏览器行为。
代理越多,爬虫就越快吗?
不一定。代理会增加一次中转,速度通常比直连慢。如果代理质量差,并发越高,失败率越高。真正稳定的做法是控制并发、设置超时、失败重试、记录状态,再根据需要增加代理资源。
用代理后本机就绝对安全了吗?
不是。目标站点看到的可能是代理出口 IP,但账号、Cookie、请求行为、浏览器指纹、访问路径仍然可能暴露异常特征。代理只能隔离一部分 IP 风险,不能替代合规边界和工程控制。
和课程代码怎么衔接
这篇文章对应课程里“代理的使用”这一段,适合放在 requests、Session/Cookie、验证码、异步爬虫之后学习。课程同步代码仓库在 Gitee:xfeicode/crawler,里面按“爬虫入门、动态网站突破、异步爬虫、验证码识别”等方向组织示例。
建议学习顺序是:
- 先掌握
requests基础请求和异常处理。 - 再学 Session、Cookie、请求头排查。
- 接着理解动态网页和 Playwright。
- 最后再把代理 IP 放进完整爬虫流程里。
这样你遇到 403 时,才不会只会“换 IP”,而是能判断到底是请求写错、状态丢失、频率过高,还是确实触发了 IP 维度的限制。
Practice