#by:哆啦A梦 #入口:http://mx.qrurl.net/h5/wxa/link?sid=26407uif5Oq #BREO变量填写wx_server里的openid/账号标识,多账号换行分割 #需要配置wx_server_url、wx_auth,用于获取wx.login code #账号变量名:BREO #new Env("BREO") #cron 8 9,10,11 * * * import requests import json import os import sys import time from pathlib import Path if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8", errors="replace") if hasattr(sys.stderr, "reconfigure"): sys.stderr.reconfigure(encoding="utf-8", errors="replace") MINI_APP_ID = "wx61457400e4212cec" WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") WX_AUTH = os.getenv("wx_auth", "") TOKEN_CACHE_PATH = Path(__file__).with_name("BREO_token_cache.json") LOGIN_BASE = "https://breoplus.breo.cn/app/minic" APP_BASE = "https://breoplus.breo.cn/breo-app" DEFAULT_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF" session = requests.Session() def read_token_cache(): try: if not TOKEN_CACHE_PATH.exists(): return {} return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} except Exception: return {} def write_token_cache(cache): try: TOKEN_CACHE_PATH.write_text(json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8") except Exception as e: print(f"⚠️ 写入token缓存失败: {e}") def mask_token(token): if not token: return "" return f"{token[:6]}***{token[-6:]}" def is_success(result): return result.get("success") is True or str(result.get("code")) in ("0000", "200", "200.0") def is_token_error(message): text = str(message) return any(key in text for key in ["40101", "40102", "token", "登录", "授权", "过期", "失效"]) def wx_headers(): return { "auth": WX_AUTH, "User-Agent": DEFAULT_UA, "Content-Type": "application/json", } def app_headers(token=None): headers = { "User-Agent": DEFAULT_UA, "content-Type": "application/json", "Content-Type": "application/json", "deviceInfo": "{}", "Referer": "https://servicewechat.com/wx61457400e4212cec/390/page-frame.html", } if token: headers["token"] = token return headers def breo_task_headers(token): return { "token": token, "device-type": "Xiaomi", "device-version": "10", "channel": "Breo", "version_code": "30201", "version": "3.2.1", "encrypt": "1", "Content-Type": "application/json; charset=UTF-8", "Referer": "https://servicewechat.com/wx61457400e4212cec/390/page-frame.html", "User-Agent": DEFAULT_UA, } def get_wx_code(account_id): if not WX_AUTH: raise RuntimeError("缺少wx_auth,无法从wx_server获取code") resp = session.post( f"{WX_SERVER_URL}/wx/code", json={"appid": MINI_APP_ID, "openid": account_id}, headers=wx_headers(), timeout=30, ) resp.raise_for_status() data = resp.json() code = data.get("code") or (data.get("data") or {}).get("code") if not code: raise RuntimeError(f"wx_server未返回code: {data}") return code def login_with_code(account_id): code = get_wx_code(account_id) login_resp = session.get( f"{LOGIN_BASE}/login/{code}", headers=app_headers(), timeout=30, ) login_resp.raise_for_status() login_data = login_resp.json() if str(login_data.get("code")) != "200" or not login_data.get("data"): raise RuntimeError(f"code登录失败: {login_data}") user_info = login_data["data"] uid = user_info.get("uid") open_id = user_info.get("openId") union_id = user_info.get("unionId") if not uid: raise RuntimeError(f"登录响应缺少uid: {login_data}") token_resp = session.post( f"{APP_BASE}/customer/loginByUid", json={"uid": uid, "openId": open_id, "unionId": union_id}, headers=app_headers(), timeout=30, ) token_resp.raise_for_status() token_data = token_resp.json() if not is_success(token_data) or not (token_data.get("result") or {}).get("token"): raise RuntimeError(f"业务token登录失败: {token_data}") return { "token": token_data["result"]["token"], "uid": uid, "openId": open_id, "unionId": union_id, "userInfo": user_info, "customer": token_data.get("result", {}), "updatedAt": int(time.time()), } def get_cached_token(account_id): return read_token_cache().get(account_id) def save_cached_token(account_id, auth_info): cache = read_token_cache() cache[account_id] = auth_info write_token_cache(cache) def remove_cached_token(account_id): cache = read_token_cache() if account_id in cache: del cache[account_id] write_token_cache(cache) def validate_token(token): try: resp = session.post( f"{APP_BASE}/getUserLevelInfoByUid", headers=app_headers(token), timeout=15, ) if resp.status_code != 200: return False data = resp.json() if is_success(data): return True return not is_token_error(data) except Exception: return False def get_token_for_account(account_id, index): cached = get_cached_token(account_id) if cached and cached.get("token"): print(f"账号 {index} 使用缓存token: {mask_token(cached['token'])}") if validate_token(cached["token"]): return cached["token"] print(f"账号 {index} 缓存token失效,重新登录") remove_cached_token(account_id) auth_info = login_with_code(account_id) save_cached_token(account_id, auth_info) user_info = auth_info.get("userInfo") or {} print(f"账号 {index} code登录成功: {user_info.get('nickname') or user_info.get('telephone') or auth_info.get('uid')}") return auth_info["token"] def get_random_one_word(): try: response = requests.get("https://uapis.cn/api/say") if response.status_code == 200: return response.text.strip() else: return "无法获取一言" except Exception as e: print(f"获取一言时出错: {e}") return "无法获取一言" def get_proclamation(): primary_url = "https://github.com/3288588344/toulu/raw/refs/heads/main/tl.txt" backup_url = "https://tfapi.cn/TL/tl.json" try: response = requests.get(primary_url, timeout=10) if response.status_code == 200: print("\n" + "=" * 50) print("📢 公告信息") print("=" * 35) print(response.text) print("=" * 35 + "\n") print("公告获取成功,开始执行任务...\n") return except requests.exceptions.RequestException as e: print(f"获取公告时发生错误: {e}, 尝试备用链接...") try: response = requests.get(backup_url, timeout=10) if response.status_code == 200: print("\n" + "=" * 50) print("📢 公告信息") print("=" * 35) print(response.text) print("=" * 35 + "\n") print("公告获取成功,开始执行任务...\n") else: print(f"⚠️ 获取公告失败,状态码: {response.status_code}") except requests.exceptions.RequestException as e: print(f"⚠️ 获取公告时发生错误: {e}, 可能是网络问题或链接无效。") def post_to_breo(token, content, title): url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/releasePost" headers = breo_task_headers(token) data = { "anonymoused": 1, "content": content, "expressText": "", "images": [], "subTitle": "", "title": title, "topicText": "" } try: response = requests.post(url, headers=headers, data=json.dumps(data)) if response.status_code == 200: result = response.json() if result.get("success", False): print("✅ 发帖成功!") print(f"帖子 ID: {result['result']['id']}") print(f"帖子标题: {result['result']['title']}") return result["result"]["id"] else: print(f"❌ 发帖失败,错误信息:{result.get('message', '未知错误')}") return None else: print(f"❌ 请求失败,状态码:{response.status_code}") return None except Exception as e: print(f"❌ 请求错误: {e}") return None def collect_post(token, post_id): url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/collect" headers = breo_task_headers(token) data = { "postId": post_id } try: response = requests.post(url, headers=headers, data=json.dumps(data)) if response.status_code == 200: result = response.json() if result.get("success", False): print("✅ 收藏成功!") reward = result.get("result") or {} print(f"获得点数: {reward.get('point', 0)}") print(f"成长值: {reward.get('grow', 0)}") else: print(f"❌ 收藏失败,错误信息:{result.get('message', '未知错误')}") else: print(f"❌ 请求失败,状态码:{response.status_code}") except Exception as e: print(f"❌ 请求错误: {e}") def comment_post(token, post_id): for _ in range(2): # 评论2次 comment_content = get_random_one_word() # 使用随机一言作为评论内容 url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/comment" headers = breo_task_headers(token) data = { "anonymoused": 0, "commentText": comment_content, "postId": post_id } try: response = requests.post(url, headers=headers, data=json.dumps(data)) if response.status_code == 200: result = response.json() if result.get("success", False): print("✅ 评论成功!") reward = result.get("result") or {} root = reward.get("rootOutVO") or {} print(f"评论内容: {root.get('commentText', comment_content)}") print(f"获得点数: {reward.get('point', 0)}") print(f"成长值: {reward.get('grow', 0)}") else: print(f"❌ 评论失败,错误信息:{result.get('message', '未知错误')}") else: print(f"❌ 请求失败,状态码:{response.status_code}") except Exception as e: print(f"❌ 请求错误: {e}") time.sleep(1) # 避免频繁请求 def browse_mall(token): url = "https://breoplus.breo.cn/breo-app/user/po-task-info/mall" headers = breo_task_headers(token) try: response = requests.post(url, headers=headers) if response.status_code == 200: result = response.json() if result.get("success", False): print("✅ 浏览商城成功!") reward = result.get("result") or {} print(f"获得点数: {reward.get('point', 0)}") print(f"成长值: {reward.get('grow', 0)}") else: print(f"❌ 浏览商城失败,错误信息:{result.get('message', '未知错误')}") else: print(f"❌ 请求失败,状态码:{response.status_code}") except Exception as e: print(f"❌ 请求错误: {e}") def punch_in(token): url = "https://breoplus.breo.cn/breo-app/user/po-task-info/punch" headers = breo_task_headers(token) try: response = requests.post(url, headers=headers) if response.status_code == 200: result = response.json() if result.get("success", False): print("✅ 签到成功!") reward = result.get("result") or {} print(f"获得点数: {reward.get('point', 0)}") print(f"成长值: {reward.get('grow', 0)}") else: print(f"❌ 签到失败,错误信息:{result.get('message', '未知错误')}") else: print(f"❌ 请求失败,状态码:{response.status_code}") except Exception as e: print(f"❌ 请求错误: {e}") if __name__ == "__main__": # 获取公告 #get_proclamation() # 从环境变量读取 wx_server 账号标识/openid accounts = [item.strip() for item in os.getenv("BREO", "").replace("&", "\n").splitlines() if item.strip()] if not accounts: print("❌ 未检测到 账号信息,退出脚本。") else: skip_community = os.getenv("BREO_SKIP_COMMUNITY", "").lower() in ("1", "true", "yes") print("=============== 开始执行任务 ===============") for i, account in enumerate(accounts, 1): print(f"\n-------------- 账号 {i} 开始 --------------") try: token = get_token_for_account(account, i) except Exception as e: print(f"❌ 账号 {i} 登录失败: {e}") continue print("🚀 正在签到...") punch_in(token) if skip_community: print("\n📝 已跳过发帖/收藏/评论任务") else: print("\n📝 正在发布帖子...") post_id = post_to_breo(token, "这是一个自动发布的帖子", "自动化测试") if post_id: print("\n⭐ 正在收藏帖子...") collect_post(token, post_id) print("\n💬 正在评论帖子...") comment_post(token, post_id) else: print("❌ 发帖失败,跳过后续操作。") print("\n🛒 正在浏览商城...") browse_mall(token) print(f"-------------- 账号 {i} 结束 --------------") print("\n=============== 所有任务执行完毕 ===============")