Python mitmproxy 隧道代理:中间人代理转发爬虫代理
mitmproxy upstream 模式转发到亿牛云爬虫代理,通过 addon 注入 Proxy-Tunnel 头实现 IP 固定。
亿牛云技术团队2026年5月31日2 分钟阅读
mitmproxy 的角色
mitmproxy 是一个中间人代理(Man-in-the-Middle Proxy),通常用于拦截、查看和修改 HTTP/HTTPS 流量。在采集场景中,可以将 mitmproxy 作为本地转发层,将所有流量转发到亿牛云爬虫代理。
架构
客户端 → mitmproxy (localhost:38080) → 亿牛云爬虫代理 (t.16yun.cn:31111) → 目标站
这种架构的好处是:客户端不需要配置代理认证,将所有代理逻辑集中在 mitmproxy 层。
启动命令
# upstream 模式启动,上游指向爬虫代理
mitmdump \
--listen-host 127.0.0.1 \
--listen-port 38080 \
--mode upstream:http://t.16yun.cn:31111 \
--upstream-auth username:password \
-s addon.py
参数说明:
| 参数 | 作用 |
|---|---|
--mode upstream:http://host:port | 将所有请求转发到上游代理 |
--upstream-auth user:pass | 上游代理的认证信息 |
-s addon.py | 加载 addon 脚本 |
--connection_strategy=lazy | 延迟建立连接 |
Addon 脚本
addon 可以在请求转发前注入自定义头,用于 Proxy-Tunnel:
# addon.py
import os
from mitmproxy import http
HOST = os.getenv("PROXY_HOST", "t.16yun.cn")
PORT = os.getenv("PROXY_PORT", "31111")
USER = os.getenv("PROXY_USERNAME") or os.getenv("PROXY_USER") or "username"
PASS = os.getenv("PROXY_PASSWORD") or os.getenv("PROXY_PASS") or "password"
SEED = os.getenv("PROXY_TUNNEL", "mitmproxy-demo-1")
class UpstreamProxy:
def request(self, flow: http.HTTPFlow) -> None:
# 注入 Proxy-Tunnel 头
flow.request.headers.setdefault("Proxy-Tunnel", SEED)
addons = [UpstreamProxy()]
客户端通过 mitmproxy 访问
客户端只需要将代理指向本地 mitmproxy,不需要知道上游代理的认证信息:
import requests
session = requests.Session()
session.proxies = {
"http": "http://127.0.0.1:38080",
"https": "http://127.0.0.1:38080",
}
for i in range(3):
resp = session.get("https://httpbin.org/ip", timeout=30)
print(f"请求 {i+1}: {resp.json()['origin']}")
在代码中启动 mitmproxy
import subprocess
import atexit
import signal
import socket
import time
def start_mitmproxy():
host = os.getenv("PROXY_HOST", "t.16yun.cn")
port = os.getenv("PROXY_PORT", "31111")
user = os.getenv("PROXY_USERNAME", "user")
pwd = os.getenv("PROXY_PASSWORD", "password")
listen_port = int(os.getenv("MITMPROXY_PORT", "38080"))
cmd = [
"mitmdump",
"--listen-host", "127.0.0.1",
"--listen-port", str(listen_port),
"--mode", f"upstream:http://{host}:{port}",
"--upstream-auth", f"{user}:{pwd}",
"-s", "addon.py",
"--set", "connection_strategy=lazy",
]
proc = subprocess.Popen(cmd)
def cleanup():
if proc.poll() is None:
proc.terminate()
proc.wait(timeout=5)
atexit.register(cleanup)
# 等待端口就绪
deadline = time.time() + 20
while time.time() < deadline:
try:
socket.create_connection(("127.0.0.1", listen_port), timeout=1)
return listen_port
except OSError:
time.sleep(0.5)
raise RuntimeError("mitmproxy 启动超时")
四种场景在 mitmproxy 中的实现
| 场景 | mitmproxy 实现 | 说明 |
|---|---|---|
| A:强制切换 | 客户端每次新建连接 | 由客户端控制,mitmproxy 透传 |
| B:保持 IP | 客户端复用连接 | mitmproxy 保持上游连接 |
| C:Proxy-Tunnel HTTP/HTTPS | addon 注入 Proxy-Tunnel | addon 自动为每个请求添加 |
mitmproxy 的优势在于:所有客户端的代理逻辑统一管理,不需要每个客户端单独配置代理认证。
错误排查
| 现象 | 原因 | 解决 |
|---|---|---|
| mitmproxy 启动失败 | mitmdump 未安装 | pip install mitmproxy |
| 上游认证失败 | --upstream-auth 凭据错误 | 核对用户名密码 |
| 连接超时 | 代理不可达 | 验证 t.16yun.cn:31111 连通性 |
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。