用青龙面板跑定时任务的人,多半都遇到过这种场面:脚本昨天还好好的,今天到点一执行就超时、返回一堆空数据,或者直接被对方站点挡在门外。翻半天代码逻辑,最后发现代码没问题,是出口IP被记住了。
这篇就聊一件事——青龙面板怎么配置代理ip。不讲虚的,按容器层、任务层、脚本层三层往下拆,哪层适合你用,照着抄命令就行。
先在脑子里分清楚:代理可以加在三个位置
很多教程一上来就让你改环境变量,结果改完面板插件装不上、更新也卡住,人就懵了。原因很简单:代理加的位置不同,影响范围完全不一样。
容器层是把代理写进青龙容器本身,整个容器里所有出站请求都走代理,一次改动全局生效。方便,但也最粗暴,面板自身的更新、插件下载、甚至你远程连面板都可能被绕进去。任务层是给某个任务单独挂变量,只有这个脚本走代理,其他任务照常,日常最常用。脚本层是在代码里自己管代理池,能按需取IP、失败自动换,灵活度高,代价是要多写几十行。
一、容器层:用环境变量让整个青龙走代理
假设你是用 docker 起的青龙,改法就是加两个环境变量,顺手把 NO_PROXY 补上,不然容器内部调用自己也会绕一圈代理,转着转着就超时了。
docker run -d \
--name qinglong \
-p 5700:5700 \
-e HTTP_PROXY=http://用户名:密码@代理地址:端口 \
-e HTTPS_PROXY=http://用户名:密码@代理地址:端口 \
-e NO_PROXY=localhost,127.0.0.1,ql-web,qinglong \
-v /opt/ql/data:/ql/data \
whyour/qinglong:latest
如果你用的是 docker-compose 就更清楚了,在 environment 里补上三行,然后 docker compose up -d 重建容器才生效——只 restart 是不够的,环境变量必须重建容器才会重新注入。
services:
qinglong:
image: whyour/qinglong:latest
container_name: qinglong
restart: always
ports:
- "5700:5700"
volumes:
- /opt/ql/data:/ql/data
environment:
- HTTP_PROXY=http://用户名:密码@代理地址:端口
- HTTPS_PROXY=http://用户名:密码@代理地址:端口
- NO_PROXY=localhost,127.0.0.1,ql-web,qinglong
有几个细节容易翻车。第一,账号密码里如果带 @、:、# 这类符号,必须先做 URL 编码,否则代理地址整串都会被解析错。第二,SOCKS5 代理写成 socks5h://地址:端口,加个 h,让域名解析也在代理那边做,不然本地解析照样暴露。第三,NO_PROXY 里一定要留 localhost 和 127.0.0.1,这是很多“面板突然打不开”的真实原因。
二、改完别凭感觉,先验证再跑任务
环境变量写进去不等于生效。进容器里看一眼,最直接:
# 1. 看变量到底进没进容器
docker exec -it qinglong env | grep -i proxy
# 2. 用变量里的代理手动发一次请求,看状态码
docker exec -it qinglong bash -c \
'curl -s -m 10 -x "$HTTPS_PROXY" -o /dev/null -w "%{http_code}\n" https://你要采集的站点'
返回 200,耗时比直连多几十到几百毫秒,那就是通了。如果返回 000 或者干脆卡住不返回,基本就三个原因:代理地址写错了、账号密码没编码、或者 NO_PROXY 里把目标站点也顺手带进去了。
顺手提一句,容器层的代价就在这里——你为了跑任务加上去的代理,面板自己下载插件时也在用。所以更稳的做法是:容器层只留 NO_PROXY 基础配置,真正的代理放到任务层。
三、任务层:只给某一个脚本挂代理
青龙面板的「环境变量」页面就是干这个用的。新建一个变量,名字按脚本需要来定,值填代理地址;如果你不想让请求库自动接管,用自定义名字更保险,比如 PROXY_URL、PROXY_URL_A、PROXY_URL_B,一个任务一个,互不干扰。
import os
import requests
proxy = os.environ.get("PROXY_URL")
if not proxy:
raise SystemExit("PROXY_URL 没取到,去面板环境变量里补一个")
proxies = {"http": proxy, "https": proxy}
resp = requests.get("https://你要采集的站点", proxies=proxies, timeout=15)
print(resp.status_code)
注意两点:面板里改完变量,要重新执行一次任务才会读到新值,已经跑着的进程不会热加载;还有,变量名字别和系统里的 HTTP_PROXY 撞车,一旦撞了,容器里所有任务都会被动走代理,就不是“只影响一个脚本”了。
四、脚本层:定时任务里自己养一个代理池
如果你跑的是采集类任务,单个固定代理肯定不够用——短效IP本身几分钟就过期,你不主动换,它自己也会断。所以脚本里得有两件事:能取到新IP,知道什么时候该换。
import os, time, requests
EXTRACT_API = os.environ["PROXY_EXTRACT_API"] # 提取链接放环境变量,别写死在代码里
def fetch_proxy():
r = requests.get(EXTRACT_API, timeout=10)
r.raise_for_status()
return r.text.strip() # 常见返回 http://ip:port
def build_session(proxy):
s = requests.Session()
s.proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}
return s
def run(urls):
proxy = fetch_proxy()
sess = build_session(proxy)
born = time.time()
for url in urls:
for attempt in range(3):
try:
resp = sess.get(url, timeout=15)
if resp.status_code != 200:
raise RuntimeError(f"状态码 {resp.status_code}")
print(f"[OK] {url}")
break
except Exception as e:
print(f"[第{attempt + 1}次失败] {e}")
if attempt == 2:
print("[跳过] 这条先记下来")
break
# 短效IP一般一两分钟就到期,超时就提前换新的
if time.time() - born > 60:
proxy = fetch_proxy()
sess = build_session(proxy)
born = time.time()
这段代码的关键不在 except,而在 born。很多人只写了报错重试,没写时间判断,结果IP半小时前就失效了,脚本还在拿它死磕,三轮重试全打在同一堵墙上。按时间主动换 比 等报错才换 要可靠得多。
代理来源上,短效动态IP配合这种写法比较顺。像神龙HTTP的短效动态IP,提取接口直接给可用地址,覆盖 300+ 城市级定位,需要换个地区的IP时改一下提取参数就行;接口兼容主流爬虫语言,脚本里就是一个 requests.get 的事,不用额外装一堆东西。
五、短效、长效、固定,各管一段场景
选代理不是越贵越好,是看任务节奏。跑得快、量不大的任务,用短效;跑得久、连接要一直保持的,用长效静态;需要稳定白名单调用的,用固定IP。
| 类型 | 大致有效期 | 适合的任务 | 配置上的注意点 |
|---|---|---|---|
| 短效动态IP | 几分钟 | 一次性抓取、需要频繁换IP的采集 | 脚本里按时间主动换,别等报错 |
| 长效静态IP | 数小时到一天 | 一个任务连跑很久、连接不能断 | 到期前重新提取,避免中途掉线 |
| 固定IP代理 | 长期不变 | 白名单对接、稳定调用 | 高并发前先压测延迟 |
神龙HTTP这三类都有,支持 HTTP / HTTPS / SOCKS5,背后是 3000万+ 正规授权代理IP储备,可用率标称 99.9%,容器里配、脚本里调都能用。个人中心还能看到可视化用量统计和实时监控,哪个任务在烧IP、烧得多快,一眼看得出来——这点对跑定时任务的人挺实在,不至于月底才发现某个脚本偷偷跑飞了。
六、几个真的会踩到的坑
密码里有特殊字符。 代理连不上,八成是 @ 或 : 没编码,把密码里的符号换成 %40、%3A 再试。
日志把账号密码打出来了。 青龙面板的日志谁都看得到,打印时统一做一层掩码,http://***:***@地址:端口 就行,别嫌麻烦。
容器时区不对。 用 time.time() 判断过期问题不大,但凡是用本地时间算的,时区差八个钟头,判断全乱。
一上来就开几十个线程。 代理扛得住,目标站也未必受得了。并发先压到 5 到 10,稳定了再往上加,中间加一点随机停顿。
只配了 HTTP_PROXY 没配 HTTPS_PROXY。 现在大部分站点都是 https,只配前者,等于什么都没配。
常见问题
Q:加了容器环境变量之后,青龙面板打不开了怎么办?
先把容器停掉重建一份不带代理变量的,进去把 NO_PROXY 补全,至少包含 localhost,127.0.0.1 和容器名。如果还是不行,就别在容器层挂代理了,改成任务层,用自定义变量名让脚本自己读,影响面能小很多。
Q:面板里环境变量加了,脚本里还是取不到?
先确认三件事:变量名拼写完全一致(大小写敏感)、任务重新执行过一次、脚本里读的是同一个名字。青龙面板的变量是在任务启动时注入的,进程跑起来之后改面板不会自动生效,这一点很容易忽略。
Q:一个定时任务想同时用多个IP跑,怎么安排?
两种做法。简单点的是顺序跑:一个IP跑完一批、按时间判断换新的,同一时刻只有一个出口,压力小也够用。要快一点就开多线程,每个线程自己持有一个会话和自己取到的IP,线程之间别共用同一个 Session,不然换IP会互相打架。
Q:短效IP跑一半就失效,是不是代理质量不行?
先看脚本有没有按时间主动换。短效IP本来就只有几分钟寿命,指望它一直在线不现实。如果已经按时换了还是频繁断,那就把重试次数和超时调一下,单次请求超时设 15 秒左右比较合适;再不行换个地区试试,有时候是某个节点当时确实不稳。
Q:容器层和脚本层能不能一起用?
能,但没必要全叠上。容器层做兜底、脚本层做精调是可行的,只是注意别让同一次请求既走容器变量又走会话代理,那样排查问题时你会很难受。建议只在一层做主要控制,另一层留空。





