用 Python 做采集的朋友多少都遇到过这种情况:脚本本地跑得好好的,跑着跑着突然全是失败请求,一查发现 IP 被目标网站限制了。这时候换上 SOCKS5 代理,再把并发参数调顺,采集效率和稳定性立刻能上一个台阶。这篇教程就从基础配置讲到并发优化,把每一步的代码和踩坑点都摊开说清楚。
一、为什么爬虫场景偏爱 SOCKS5 代理
很多新手第一反应是用 HTTP 代理,但跑过一段时间就会发现,SOCKS5 在采集场景里明显更"省心"。原因在于它的工作层级更底层:SOCKS5 工作在会话层,只负责把数据包原样转发出去,不关心也不解析上层应用协议。这意味着无论是 HTTP 还是 HTTPS 请求,甚至其他基于 TCP 的通信,它都能一视同仁地代理。
对爬虫来说,这种"不挑协议"的特性带来三个直接好处:一是通用性强,同一套代理配置可以同时服务 requests、httpx、aiohttp 等不同客户端;二是转发开销更小,没有应用层解析的额外负担,高并发下延迟表现更稳定;三是认证方式灵活,支持账号密码认证,也支持 IP 白名单,接入流程简单。
| 对比项 | SOCKS5 代理 | HTTP 代理 |
|---|---|---|
| 工作层级 | 会话层,转发原始流量 | 应用层,解析 HTTP 报文 |
| 支持协议 | 任意 TCP 流量 | 仅 HTTP / HTTPS |
| 转发效率 | 更轻量,高并发更稳 | 有解析开销 |
| 典型场景 | 爬虫采集、客户端程序 | 网页浏览、接口调试 |
二、Python 配置 SOCKS5 代理:两种主流写法
先解决"能不能跑通"的问题。下面两种方案覆盖了绝大多数项目,任选其一即可。
方案一:requests + PySocks(最常见)
requests 本身不直接支持 SOCKS 协议,需要先装一个依赖:
pip install requests pysocks
# 或者一行装齐
pip install "requests[socks]"
然后在请求里通过 proxies 参数传入代理地址:
import requests
# 把账号、密码、地址、端口替换成自己的代理信息
proxy_url = "socks5://用户名:密码@代理地址:端口"
proxies = {
"http": proxy_url,
"https": proxy_url,
}
resp = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(resp.json()) # 返回的 IP 应该是代理服务器的出口 IP
小技巧:把 socks5:// 换成 socks5h://,域名解析也会交给代理服务器完成,可以避免本地 DNS 污染或泄露真实解析记录,采集场景更推荐这种写法。
方案二:httpx(原生支持,配置更简洁)
pip install "httpx[socks]"
import httpx
with httpx.Client(
proxy="socks5://用户名:密码@代理地址:端口",
timeout=10
) as client:
resp = client.get("https://httpbin.org/ip")
print(resp.json())
httpx 的好处是 API 和 requests 非常接近,同时天生支持异步,后面切换并发方案时迁移成本更低。
三、并发优化第一步:多线程方案
代理配通只是及格线,真正拉开差距的是并发。Python 的 GIL 对网络 IO 密集型任务影响不大,所以用多线程跑采集完全可行,标准库里的 ThreadPoolExecutor 就够用:
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
PROXIES = {
"http": "socks5://用户名:密码@代理地址:端口",
"https": "socks5://用户名:密码@代理地址:端口",
}
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
def fetch(url):
try:
resp = requests.get(url, proxies=PROXIES, headers=HEADERS, timeout=10)
return url, resp.status_code, len(resp.text)
except Exception as e:
return url, None, str(e)
urls = [f"https://目标网站.com/list/{page}" for page in range(1, 201)]
with ThreadPoolExecutor(max_workers=20) as pool:
futures = [pool.submit(fetch, u) for u in urls]
for fut in as_completed(futures):
url, status, length = fut.result()
print(url, status, length)
三个关键点:max_workers 不要一上来就拉满,从 10~20 开始,观察成功率和响应时间再逐步上调;每个请求都要带超时,否则一个卡死的连接就会拖住一个线程;异常要兜住,让单个失败不影响整批任务。
四、并发优化第二步:异步协程方案
当任务量到了几万、几十万页面这个级别,多线程的线程切换开销和资源占用就开始吃亏了,这时候换异步协程。aiohttp 配合 aiohttp-socks 可以直接挂 SOCKS5 代理:
pip install aiohttp aiohttp-socks
import asyncio
import aiohttp
from aiohttp_socks import ProxyConnector
CONNECTOR = ProxyConnector.from_url("socks5://用户名:密码@代理地址:端口")
async def fetch(session, sem, url):
async with sem: # 信号量控制实际并发上限
try:
async with session.get(url) as resp:
text = await resp.text()
return url, resp.status, len(text)
except Exception as e:
return url, None, str(e)
async def main():
sem = asyncio.Semaphore(100)
timeout = aiohttp.ClientTimeout(total=10)
async with aiohttp.ClientSession(connector=CONNECTOR, timeout=timeout) as session:
urls = [f"https://目标网站.com/list/{p}" for p in range(1, 1001)]
tasks = [fetch(session, sem, u) for u in urls]
for result in await asyncio.gather(*tasks):
print(result)
asyncio.run(main())
协程方案的核心是用 Semaphore 控制并发上限:你可以创建 1000 个任务,但同时只有 100 个在跑,既吃满带宽又不至于把代理连接数打爆。单机跑几千并发,协程比线程轻松得多。
五、连接池与重试:并发稳定的隐形功臣
很多教程讲到并发就结束了,但实际跑长任务时,真正决定"能不能连续跑一晚上不出事"的,是连接复用和失败重试这两件事。
用 Session 复用连接,别每次都新建:
import requests
from requests.adapters import HTTPAdapter, Retry
session = requests.Session()
retry = Retry(
total=3, # 最多重试3次
backoff_factor=0.5, # 重试间隔递增
status_forcelist=[500, 502, 503, 504],
)
adapter = HTTPAdapter(
pool_connections=20, # 连接池数量
pool_maxsize=100, # 池内最大连接数
max_retries=retry,
)
session.mount("http://", adapter)
session.mount("https://", adapter)
session.proxies = PROXIES
# 之后所有请求都走 session.get(...),连接自动复用
超时要把连接超时和读取超时分开设:timeout=(5, 10) 表示 5 秒内建连、10 秒内拿到响应,比笼统的一个数字更容易定位问题。
失败后换 IP 重试:同一个 IP 连续失败时,大概率是这个 IP 被目标站盯上了,从代理池里换一个再试,成功率远高于原地硬重试。这也意味着,做并发优化之前,先得有一个稳定、量足的代理来源。
六、并发数到底开多少?一张表看明白
并发不是越大越好。开太小浪费代理资源,开太大轻则超时重试变多,重则整批 IP 一起被限制。参考下面的起点,再根据目标站的实际反应微调:
| 目标站点情况 | 建议并发 | 配套策略 |
|---|---|---|
| 无明确频率限制 | 10~30 | 先小流量试跑,观察成功率 |
| 有反爬但较宽松 | 30~80 | 随机 UA + 请求间隔抖动 |
| 反爬严格 | 5~15 | 低速慢爬,IP 轮换要勤 |
| 异步大规模采集 | 100~500+ | 信号量控流 + IP 池轮换 |
一个简单的调参节奏:固定其他变量,每次把并发上调 20%~30%,连续观察成功率和平均响应时间,一旦成功率下滑就退回上一档。稳定压倒一切。
七、常见报错与排查思路
1. 提示 Missing dependencies for SOCKS support
说明 PySocks 没装或装丢了,执行 pip install pysocks 即可,装完重启解释器再跑。
2. 407 Proxy Authentication Required
认证信息不对。检查账密是否正确、URL 里特殊字符是否需要转义,或者改用代理服务商提供的白名单认证方式。
3. 大量请求超时
先降低并发试试;如果降并发就恢复,说明是并发超过了代理或目标站的承受能力;如果降了还是超时,换一批 IP 再测,排除 IP 质量问题。
4. 连接数超限报错
部分代理服务对单账号并发连接数有限制,超出会拒绝新建连接。这时候要么控制客户端并发,要么联系服务商提升配额。
八、代理来源选对,并发优化才有着力点
最后说说代理本身的选取,这直接决定前面所有优化能发挥几成功力。挑选时重点看四点:协议支持(确认提供 SOCKS5)、IP 池规模与可用率、并发连接数上限、提取方式(API 批量提取最方便程序接入)。
像天启HTTP这类国内代理 IP 服务商,支持 SOCKS5 在内的常用协议,提供 API 批量提取和账密认证两种接入方式,IP 池覆盖国内多城市节点,配合本文的多线程或协程方案可以直接上手。它的定位是国内业务场景,如果你的采集目标本身就在国内,协议、并发、提取流程都能对得上,接入成本很低。
常见问题
Q: socks5 和 socks5h 有什么区别?
socks5h 会把域名解析也交给代理服务器完成,本地不做 DNS 解析;socks5 则在本地解析后再发起代理连接。爬虫场景更推荐 socks5h,能避免本地 DNS 污染带来的问题。
Q: 多线程和异步协程到底选哪个?
任务量在几千页面以内、追求快速出活,多线程足够;任务量上万、需要长时间稳定运行,直接上异步协程,资源占用和吞吐表现都更好。
Q: 为什么加了代理之后反而变慢了?
先测单个请求的裸延迟,排除代理节点本身慢的问题;再检查是否每次请求都在新建连接(没用 Session 复用);最后看并发是否过高导致排队超时,逐项排查即可定位。
Q: 并发开到多少会被限制 IP?
没有统一答案,取决于目标站的策略。稳妥做法是从低并发起步,逐步上调并盯紧成功率,一旦下滑立即回退,同时提高 IP 轮换频率。
Q: 天启HTTP 能用于采集国外网站吗?
天启HTTP 是国内 IP 代理服务商,节点覆盖国内城市,主要面向国内业务场景。如果采集目标需要国外出口 IP,则不适用,需要另选对应的服务。





