收起左侧

别让NAS空转:用青龙面板给网盘加个定时任务

13
回复
681
查看
[ 复制链接 ]

10

主题

23

回帖

0

牛值

初出茅庐

我的NAS白天是家庭数字中心,晚上"值班"——用青龙面板帮网盘"签到"。本文介绍这个"差事"怎么安排:Docker部署、任务配置、以及怎么让它低调稳定运行。

💡 一、为什么选青龙面板?

NAS 24小时开机,除了存文件、跑下载,其实还能干点"定时活儿"。比如每天早上去网盘打个卡,领点存储空间——这事不大,但贵在坚持,漏一天就断签。

手动打开App点一下不难,难的是365天不忘。这种事情让青龙面板代劳最合适不过了。

青龙面板是个开源的定时任务管理工具,提供Web界面管理脚本,支持Python、JavaScript等常见语言。它原本跑在服务器上,但用Docker装在NAS里更合适:省电、安静、不占用电脑资源。

🛠️ 二、部署:Docker方式安装

以下以飞牛OS为例,群晖、威联通操作类似。

飞牛OS-Docker compose可视化部署

Docker compose命令ssh部署

📁 1. 准备目录

在NAS的Docker目录下创建文件夹:

/docker/qinglong

这个目录用于持久化存储任务脚本和日志,容器删除后数据不会丢。

⚙️ 2. Compose配置

新建 docker-compose.yml 文件,优化后的代码,能解决:

  • 宿主机DNS被运营商劫持或污染,导致API请求失败
  • 家庭宽带DNS不稳定
  • 容器内域名解析超时,需要同时解析外网 域名(网盘API)和内网 域名(NAS服务)
  • 国内服务器拉取Docker Hub镜像慢或失败:
services:
  qinglong:
    image: whyour/qinglong:latest
    container_name: qinglong
    restart: always
    # 添加以下三行, ↓↓↓
    dns:
      - 8.8.8.8 #Google公共DNS,解析稳定、快速
      - 114.114.114.114 #中国电信公共DNS,国内解析速度快
    environment:
      # 添加以下两行 ↓↓↓
      - DockerMirror=China # 自动使用国内Docker镜像源,加速镜像拉取
      - NPMMirror=https://registry.npmmirror.com # 使用淘宝NPM镜像源,Node.js依赖安装速度提升10倍以上
      # 原有环境变量保留
      - QL_DIR=/ql
    volumes:
      - ./ql/data:/ql/data
    ports:
      - 5700:5700 #端口5700可按需修改,确保NAS防火墙放行。

▶️ 3. 启动与初始化

docker-compose up -d

等待1-2分钟,浏览器访问 NAS_IP:5700,按引导完成:

  • 设置管理员账号
  • 初始化完成进入主界面

⚙️ 4. 配置通知渠道(可选)

想让任务跑完后给你发个微信提醒?青龙面板支持企业微信、Server酱、钉钉等多种通知方式。这里以PushPlus应用为例:

  1. 访问https://www.pushplus.plus → 注册,登入后台 → 绑定微信 → 个人资料
  2. 复制用户token,或者左侧消息token新建个,复制都可以使用
  3. 青龙面板 → 系统设置 → 通知设置 → 通知方式 → 选择pushplus → 在"pushPlusToken"填入刚才复制的token即可。
  4. 测试推送通道,确认微信能收到通知


🎯 三、实战:网盘"签到"任务

部署完成后,以阿里网盘自动"打卡"为例,演示完整配置流程。

🔑 1. 获取身份凭证(控制台命令方式)

网盘签到需要 refresh_token 维持登录状态,获取方式基于官方网页端:

  1. 电脑浏览器访问网盘官网并登录
  2. 按 F12 打开开发者工具,切换到 Console(控制台) 标签
  3. 粘贴以下命令并回车:
JSON.parse(localStorage.token).refresh_token
  1. 控制台会输出一长串字符,即为refresh_token,复制后粘贴到青龙面板的环境变量中

安全提示:该token仅用于维持登录状态,存储于本地NAS,不经过第三方服务器。建议定期更换,可在网盘官网退出登录后重新获取。

📦 2. 安装依赖

进入青龙面板 → 依赖管理 → 根据脚本类型选择对应分类 → 创建依赖。

Python3依赖:

本任务需要:

  • requests —— 用于发起HTTP请求

其他常见任务可能需要的依赖:

bs4
telethon
cacheout
jieba
PyExecJS
ping3
canvas
Crypto
ds
requests
pycryptodome
aiohttp
redis
httpx
success
openai
dashscope

Node.js依赖(部分脚本需要):

request
cheerio
js-base64
dotenv
magic
tough-cookie
ws@7.4.3
require
requests
date-fns
ts-md5
typescript
json5
axios@v0.27.2
crypto-js
@types/node
png-js
node-telegram-bot-api
fs
jsdom
form-data
jieba
tslib
ds
jsdom -g
prettytable
ql
common
node-jsencrypt
moment
global-agent
axios
crypto -g
-g typescipt
https
proxy
qs
cjs
sharp
jsencrypt
node-rsa
xmldom
socks-proxy-agent

Linux依赖(系统级工具):

gcc
libc-dev
g++
libffi-dev
python3-dev

建议:按需安装,避免容器臃肿。安装后重启容器生效。可以直接复制,点击确认会自动安装。

📝 3. 阿里云盘自动签到脚本

所有脚本文件默认位置在部署时你映射的NAS主机文件夹 - ./ql/data:/ql/data,青龙面板脚本管理会自动读取这里面的脚本文件内容。

aliyunpan_signup.py代码:

#!/usr/bin/python
# coding=utf-8
'''
File: aliyunpan_sign.py
Author: mingfei (Bug修复版)
'''
import sys
import os
import traceback
import requests
import time
from loguru import logger

# 配置日志
logger.remove()
logger.add(sys.stdout, level='INFO', format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level}</level> | {message}")
work_path = os.path.dirname(os.path.abspath(__file__))
logger.add(f"{work_path}/logs/aliyunpan_sign.log", encoding='utf8')

# 从环境变量读取refresh_token
refresh_token = os.getenv('ALIYUNPAN_REFRESH_TOKEN', '').strip()
if not refresh_token:
    logger.error("❌ 请先在环境变量里添加阿里云盘的refresh_token")
    exit(1)

# 通知模块容错
try:
    import notify
except ImportError:
    logger.warning("⚠️ 通知模块加载失败")
    notify = None


def get_access_token(token):
    """刷新获取access_token"""
    try:
        url = "https://auth.aliyundrive.com/v2/account/token"
        data_dict = {
            "refresh_token": token,
            "grant_type": "refresh_token"
        }
        headers = {
            "accept": "application/json",
            "content-type": "application/json;charset=UTF-8",
            "origin": "https://www.aliyundrive.com",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        }

        resp = requests.post(url, json=data_dict, headers=headers, timeout=10)
        resp_json = resp.json()
      
        access_token = resp_json.get('access_token', "")
        if access_token:
            logger.success(f"✅ access_token获取成功: {access_token[:20]}...")
            return access_token
        else:
            logger.error(f"❌ 获取access_token失败: {resp_json}")
            return ""
    except Exception as e:
        logger.error(f"❌ 获取access_token异常: {traceback.format_exc()}")
        return ""


class ALiYunPan(object):
    def __init__(self, access_token):
        self.access_token = access_token

    def sign_in(self):
        """签到主流程:查询状态+领取奖励"""
        try:
            # 1. 查询签到状态
            logger.info("🔍 查询签到状态...")
            url = 'https://member.aliyundrive.com/v2/activity/sign_in_list'
            headers = {
                "Authorization": self.access_token,
                "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15"
            }
          
            resp = requests.post(url, json={}, headers=headers, timeout=10)
            resp_json = resp.json()
          
            code = resp_json.get('code', '')
            if code == "AccessTokenInvalid":
                logger.error("❌ access_token无效,请检查refresh_token")
                return False
          
            result = resp_json.get('result', {})
            sign_in_logs_list = result.get("signInInfos", [])
            sign_in_count = result.get("signInCount", 0)
          
            if not sign_in_logs_list:
                logger.warning("⚠️ 未获取到签到信息")
                return False
          
            # 2. 处理签到逻辑
            today_reward = None
            msg_lines = []
            today_day = str(sign_in_count)  # 确保是字符串类型
          
            for sign_in_logs_dict in sign_in_logs_list:
                status = sign_in_logs_dict.get('status', '')
                day = str(sign_in_logs_dict.get('day', 0))  # 强制转字符串再比较
              
                if status == "normal":  # 已签到
                    rewards = sign_in_logs_dict.get('rewards', [])
                    if rewards:
                        reward = rewards[0]
                        is_claimed = reward.get('status', '') == 'verification'
                      
                        # 领取未领取的奖励
                        if not is_claimed:
                            reward_info = self.claim_reward(day)
                        else:
                            reward_info = reward
                      
                        name = reward_info.get('name', '无奖励')
                        description = reward_info.get('description', '')
                      
                        # 判断是否是今天(字符串比较)
                        is_today = (day == today_day)
                        if is_today:
                            today_reward = f"{name}({description})"
                            status_icon = '📅'
                        else:
                            status_icon = '✅'
                      
                        # 修复:将day转换为整数再格式化
                        lo**sg = f"{status_icon}第{int(day):2d}天 | 奖励: {name} -> {description}"
                        logger.info(lo**sg)
                        msg_lines.append(lo**sg)
          
            # 3. 输出总结
            logger.info(f"\n{'='*60}")
            logger.info(f"📊 本月累计签到: {sign_in_count}/{len(sign_in_logs_list)} 天")
          
            if today_reward:
                logger.success(f"✅ 今日签到成功!获得奖励: {today_reward}")
            else:
                logger.warning("⚠️ 今日未签到,请检查脚本执行时间是否晚于0点")
          
            logger.info(f"\n{'='*60}")
          
            # 4. 发送通知
            title = "阿里云盘签到结果"
            msg = f"本月签到: {sign_in_count}/{len(sign_in_logs_list)} 天\n"
            if today_reward:
                msg += f"\n✅ 今日奖励: {today_reward}"
            msg += "\n\n详情:\n" + "\n".join(msg_lines)
          
            if notify and hasattr(notify, 'send'):
                notify.send(title, msg)
          
            return True
          
        except Exception as e:
            logger.error(f"❌ 签到流程异常: {traceback.format_exc()}")
            return False

    def claim_reward(self, day):
        """领取奖励(同时触发签到)"""
        try:
            logger.info(f"🎁 正在领取第{day}天奖励...")
            url = 'https://member.aliyundrive.com/v2/activity/sign_in_reward'
            headers = {
                "Authorization": self.access_token,
                "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15"
            }
            body = {'signInDay': int(day)}  # 转整数传给API
          
            resp = requests.post(url, json=body, headers=headers, timeout=10)
            resp_json = resp.json()
            result = resp_json.get('result', {})
          
            name = result.get('name', '未知奖励')
            description = result.get('description', '')
            logger.success(f"✅ 领取成功: {name} -> {description}")
            return {'name': name, 'description': description}
        except Exception as e:
            logger.error(f"❌ 领取奖励异常: {traceback.format_exc()}")
            return {'name': '领取失败', 'description': ''}


def main():
    """主函数"""
    # 分割多个token
    if ',' in refresh_token:
        tokens = [t.strip() for t in refresh_token.split(',') if t.strip()]
    else:
        tokens = [refresh_token]
  
    logger.info(f"📋 共检测到 {len(tokens)} 个账号")
  
    for index, token in enumerate(tokens, 1):
        logger.info(f"\n{'='*60}")
        logger.info(f"👤 正在处理第 {index}/{len(tokens)} 个账号...")
      
        access_token = get_access_token(token)
      
        if access_token:
            ali = ALiYunPan(access_token)
            ali.sign_in()
        else:
            logger.error("❌ 获取access_token失败,跳过此账号")
      
        # 账号间延迟
        if index < len(tokens):
            logger.info("⏳ 等待3秒...")
            time.sleep(3)
  
    logger.info("\n🏁 所有账号处理完成!")


if __name__ == '__main__':
    main()

🔐 4. 配置环境变量

环境变量 → 新建:

  • 名称:ALIYUNPAN_REFRESH_TOKEN
  • 值:步骤1获取的refresh_token

⏰ 5. 设置定时任务

定时任务 → 新建:

  • 名称:网盘签到
  • 命令:task aliyunpan_signup.py
  • 定时规则:0 15 0 * * ?(每天凌晨00:15签到)

保存后点击"运行一次"测试,查看日志确认正常。

手机微信确认推送消息是否正常


⚠️ 四、低调稳定运行的建议

凭证管理:敏感信息务必通过环境变量注入,避免写入脚本文件。定期更换token,可在网盘官网退出登录后重新获取。

频率控制:设置为每天1次,时间选在个人常用时段,模拟正常用户行为。

日志清理:青龙面板默认保留30天日志,可在系统设置中调整,避免占用过多存储空间。

容器备份./ql/data 目录已做持久化映射,定期将该目录备份到NAS的其他存储池,重建容器时直接恢复。


🚀 五、还能干什么?

掌握这套流程后,可以 similarly 配置:

  • NAS本地日志定期清理
  • 家庭安防视频自动归档
  • SSL证书到期前自动提醒
  • 智能家居状态定时巡检

除了网盘"打卡",青龙面板还能处理很多"细水长流"的活儿:

  • 批量管理积分任务、监控价格变动、自动领取会员权益等等。

这些脚本在开源社区都能找到,但建议自己看懂代码再跑,毕竟"副业"的收入和风险都得自己担。

核心逻辑都是一样:定时规则 + 脚本执行 + 结果通知。

✅ 总结

青龙面板的价值在于把"定时任务"这件事变得可视、可管、可查。对于NAS这种常年开机的设备,装一个相当于多了个"值班员",处理那些"小事但别忘"的活儿。

本文的网盘"签到"只是入门示例。你的NAS晚上还能"值"什么"班",取决于你的需求。


📚 附:常用Cron表达式

表达式 含义
0 9 * * * 每天9点
0 */6 * * * 每6小时
0 2 * * 0 每周日凌晨2点

如有修改将更新在文章底部留言,觉得有用可以点赞+转发+推荐,点点关注,你的支持是我更新的最大动力❤。
收藏
送赞 2
分享

1

主题

13

回帖

0

牛值

江湖小虾

请问一下,脚本 128-130行的几个*号是什么

是论坛和谐了关键字把*删除就可以了  详情 回复
昨天 12:40
我的锅,没核对,不知道为啥论坛粘贴进来就被转义了,127-130行是下面这个 lo**sg = f"{status_icon}第{int(day):2d}天 | 奖励: {name} -> {description}" logger.info(lo**sg)  详情 回复
昨天 09:44
同问,也在这里卡住了  详情 回复
前天 18:41

3

主题

16

回帖

0

牛值

江湖小虾

分享点脚本玩玩吧

0

主题

12

回帖

0

牛值

江湖小虾

四哥! 发表于 2026-2-4 17:18
请问一下,脚本 128-130行的几个*号是什么

同问,也在这里卡住了
#改 第128行 log = f"{status_icon}第{int(day):2d}天 | 奖励: {name} -> {description}" # 第129行 logger.info(log)  详情 回复
昨天 10:40
我把*号随便改成几个字符,脚本能运行,但日志显示的是未知奖励。第二第直接运行失败。  详情 回复
昨天 08:35

1

主题

13

回帖

0

牛值

江湖小虾

赵某某 发表于 2026-2-4 18:41
同问,也在这里卡住了

我把*号随便改成几个字符,脚本能运行,但日志显示的是未知奖励。第二天直接运行失败。

10

主题

23

回帖

0

牛值

初出茅庐

昨天 09:44 楼主 显示全部楼层

我的锅,没核对,不知道为啥论坛粘贴进来就被转义了,127-130行里的"lo**sg"是 "lo**sg"

微信图片_20260205094637_307_4.jpg

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
应该是被吃掉了,是 猪_M 吧?改了,运行提示 未知奖励。  详情 回复
昨天 10:45

1

主题

1

回帖

0

牛值

系统先锋体验团🛩️

能不能分享点脚本给大家

0

主题

4

回帖

0

牛值

江湖小虾

赵某某 发表于 2026-2-4 18:41
同问,也在这里卡住了

#改 第128行
log = f"{status_icon}第{int(day):2d}天 | 奖励: {name} -> {description}"
# 第129行
logger.info(log)

1

主题

13

回帖

0

牛值

江湖小虾

纳斯派 发表于 2026-2-5 09:44
我的锅,没核对,不知道为啥论坛粘贴进来就被转义了,127-130行里的&quot;lo**sg&quot;是 &quot;lo**sg&quot;

...

应该是被吃掉了,是 猪_M 吧?改了,运行提示 未知奖励。
奖励自动点脚本没写进去,手动点了之后,就会有信息了  详情 回复
昨天 11:23

10

主题

23

回帖

0

牛值

初出茅庐

昨天 11:23 楼主 显示全部楼层
四哥! 发表于 2026-2-5 10:45
应该是被吃掉了,是 猪_M 吧?改了,运行提示 未知奖励。

奖励自动点脚本没写进去,手动点了之后,就会有信息了

0

主题

5

回帖

0

牛值

江湖小虾

四哥! 发表于 2026-2-4 17:18
请问一下,脚本 128-130行的几个*号是什么

是论坛和谐了关键字把*删除就可以了

0

主题

12

回帖

0

牛值

江湖小虾

Traceback (most recent call last):
  File "/ql/data/scripts/aliyunpan_signup.py", line 12, in <module>
    from loguru import logger
ModuleNotFoundError: No module named 'loguru'

又出现以上问题了

你这是没安装这个 loguru 依赖  详情 回复
昨天 22:30

10

主题

23

回帖

0

牛值

初出茅庐

昨天 22:30 楼主 显示全部楼层
赵某某 发表于 2026-2-5 21:31
Traceback (most recent call last):
  File &quot;/ql/data/scripts/aliyunpan_signup.py&quot;, line 12, in &lt;modul ...

你这是没安装这个 loguru 依赖  

0

主题

12

回帖

0

牛值

江湖小虾

半小时前 显示全部楼层
搞定了,谢谢
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则