#!/usr/bin/env python3 """ 夸克网盘自动签到脚本 用法: python quark_sign.py --url "你的夸克URL" [--check] python quark_sign.py --config ~/.config/quark_sign.json """ import argparse import json import os import sys from urllib.parse import urlparse, parse_qs, unquote # 尝试导入 requests,如果没有则使用 urllib HAS_REQUESTS = True try: import requests except ImportError: HAS_REQUESTS = False import urllib.request import urllib.parse import urllib.error import ssl class QuarkSign: BASE_URL = "https://drive-m.quark.cn/1/clouddrive/capacity/growth" def __init__(self, url: str): self.params = self._extract_params(url) if not self.params.get("kps") or not self.params.get("sign"): raise ValueError("URL 中缺少 kps 或 sign 参数,请检查 URL 是否完整") def _extract_params(self, url: str) -> dict: parsed = urlparse(url) params = parse_qs(parsed.query) return {k: unquote(v[0]) for k, v in params.items()} def _build_query(self, extra: dict = None) -> dict: q = { "pr": "ucpro", "fr": "android", "kps": self.params.get("kps"), "sign": self.params.get("sign"), "vcode": self.params.get("vcode", "1780291057288"), } if extra: q.update(extra) return q def _post(self, endpoint: str, data: dict = None, params: dict = None) -> dict: url = f"{self.BASE_URL}/{endpoint}" query = self._build_query(params) if HAS_REQUESTS: resp = requests.post(url, json=data or {}, params=query, timeout=10) return resp.json() else: # 使用 urllib fallback full_url = url + "?" + urllib.parse.urlencode(query) payload = json.dumps(data or {}).encode("utf-8") req = urllib.request.Request( full_url, data=payload, headers={"Content-Type": "application/json"}, method="POST", ) ctx = ssl.create_default_context() with urllib.request.urlopen(req, context=ctx, timeout=10) as resp: return json.loads(resp.read().decode("utf-8")) def _get(self, endpoint: str, params: dict = None) -> dict: url = f"{self.BASE_URL}/{endpoint}" query = self._build_query(params) if HAS_REQUESTS: resp = requests.get(url, params=query, timeout=10) return resp.json() else: full_url = url + "?" + urllib.parse.urlencode(query) req = urllib.request.Request(full_url, method="GET") ctx = ssl.create_default_context() with urllib.request.urlopen(req, context=ctx, timeout=10) as resp: return json.loads(resp.read().decode("utf-8")) def sign(self) -> dict: """执行签到""" return self._post("sign", data={"sign_cyclic": True}) def info(self) -> dict: """获取签到信息""" return self._get("sign", params={"_size": 1}) def reward_info(self) -> dict: """获取奖励记录""" return self._get("reward_record", params={"_size": 10}) def format_reward(reward_bytes: int) -> str: if reward_bytes >= 1024 ** 3: return f"{reward_bytes / (1024 ** 3):.2f} GB" return f"{reward_bytes / (1024 ** 2):.2f} MB" def main(): parser = argparse.ArgumentParser(description="夸克网盘自动签到") parser.add_argument("--url", help="夸克网盘分享/签到 URL(包含 kps 和 sign 参数)") parser.add_argument("--config", "-c", help="配置文件路径(JSON 格式)") parser.add_argument("--check", action="store_true", help="仅检查签到状态,不执行签到") parser.add_argument("--info", action="store_true", help="显示签到信息") args = parser.parse_args() # 获取 URL url = args.url if not url and args.config: with open(os.path.expanduser(args.config)) as f: cfg = json.load(f) url = cfg.get("url") if not url: # 尝试环境变量 url = os.environ.get("QUARK_SIGN_URL") if not url: # 尝试读取默认配置(skill 内置) script_dir = os.path.dirname(os.path.abspath(__file__)) default_cfg = os.path.join(script_dir, "..", "config.json") if os.path.exists(default_cfg): with open(default_cfg) as f: cfg = json.load(f) url = cfg.get("url") if not url: print("❌ 请提供 URL:--url、--config 或环境变量 QUARK_SIGN_URL") print(" 提示:可在 skill 目录下创建 config.json 写入默认 URL") sys.exit(1) try: qs = QuarkSign(url) except ValueError as e: print(f"❌ {e}") sys.exit(1) if args.info: print("📋 获取签到信息...") info = qs.info() print(json.dumps(info, indent=2, ensure_ascii=False)) return if args.check: print("🔍 检查签到状态...") info = qs.info() data = info.get("data", {}) if data.get("sign_daily"): print("✅ 今日已签到") else: print("⏳ 今日未签到") return # 执行签到 print("🚀 执行签到...") result = qs.sign() status = result.get("status") code = result.get("code") msg = result.get("message", "") data = result.get("data", {}) if data and status == 200: reward = data.get("sign_daily_reward", 0) print(f"✅ 签到成功!获得 {format_reward(reward)}") elif "repeat" in msg.lower() or code == 44210: print("ℹ️ 今日已签到过,无需重复签到") else: print(f"❌ 签到失败: {msg} (code={code}, status={status})") sys.exit(1) if __name__ == "__main__": main()