├── ChinaUnicomLogin.py ├── JS └── .gitkeep ├── LICENSE ├── README.md ├── backUp ├── 52pojie.js ├── china_telecom.py ├── iqiyiRed.js ├── telecom_live_lotter.py ├── txsp_vipRed.py ├── txspegg.py └── txspjfdh.py ├── clean_log.sh ├── divination.py ├── gobing_checkin.py ├── iqiyi.py ├── iqiyiRed.py ├── jryc_monitor.py ├── login ├── telecom_login.py └── unicom_login.py ├── logs └── .gitkeep ├── mt_wxpusher.js ├── qfxhd.js ├── requirements.txt ├── sfexpress.py ├── tools ├── aes_encrypt.py ├── encrypt_symmetric.py ├── iqiyi_login.py ├── notify.py ├── ql_api.js ├── ql_api.py ├── ql_util.py ├── rsa_encrypt.py ├── send_msg.py ├── sfExpressLogin.py ├── tool.py └── wxy_login.py ├── user_agent.json ├── wochangyou.py ├── wochangyou_token.py ├── wochangyou_token_psw.py └── wyx.py /JS/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuanter/misaka/ec8bfa12f90bfb14091faaf983741fb18bc7ae16/JS/.gitkeep -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 不再维护,告辞 2 | # 原仓库来源limoruirui/misaka,本仓库仅做修改 3 | 4 | -------------------------------------------------------------------------------- /backUp/52pojie.js: -------------------------------------------------------------------------------- 1 | /* 2 | -- coding: utf-8 -- 3 | ------------------------------- 4 | @Author : github@limoruirui https://github.com/limoruirui/misaka 5 | @Time : 24/7/2022 00:14 6 | -------------------------------*/ 7 | /* 8 | * 1. 浏览器打开抓包 https://www.52pojie.cn/home.php?mod=spacecp&ac=credit&showcredit=1 9 | * 2. 将获取到的cookie整段填入15行中 或者填入boxjs中 变量名POJIE_COOKIE 10 | * 3. 只测试了Loon 其它自测 crontab 自选 11 | * [Script] 12 | * cron "13 13 * * *" script-path=https://raw.githubusercontent.com/limoruirui/misaka/master/52pojie.js, tag=52破解签到 13 | * 4. 脚本有风险,使用需谨慎.*/ 14 | //若要将cookie填在脚本里 请填在下面这行 15 | let pojie_cookie = ""; 16 | const $ = API("52破解签到"); 17 | pojie_cookie = pojie_cookie || $.read("POJIE_COOKIE"); 18 | const chrome_version_min = 89; 19 | const chrome_version_max = 103; 20 | const chrome_version = Math.floor(Math.random() * (chrome_version_max - chrome_version_min)) + chrome_version_min; 21 | const headers = { 22 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 23 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7", 24 | "Cache-Control": "no-cache", 25 | "Connection": "keep-alive", 26 | "Cookie": pojie_cookie, 27 | "Host": "www.52pojie.cn", 28 | "Content-Type": "text/plain;charset=UTF-8", 29 | "Pragma": "no-cache", 30 | "sec-ch-ua": `".Not/A)Brand";v="99", "Google Chrome";v="${chrome_version}", "Chromium";v="${chrome_version}"`, 31 | "sec-ch-ua-mobile": "?0", 32 | "sec-ch-ua-platform": "Windows", 33 | "Sec-Fetch-Dest": "document", 34 | "Sec-Fetch-Mode": "navigate", 35 | "Sec-Fetch-Site": "none", 36 | "Sec-Fetch-User": "?1", 37 | "Upgrade-Insecure-Requests": "1", 38 | "User-Agent": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chrome_version}.0.${Math.floor(Math.random() * (999 - 100)) + 100}.${Math.floor(Math.random() * (99 - 10)) + 10} Safari/537.36` 39 | }; 40 | if (pojie_cookie.length === 0) { 41 | $.notify("52破解", "", "cookie为空, 请检查"); 42 | } else { 43 | (async () => { 44 | await get_task(); 45 | //接任务后等待两秒钟后再执行 46 | await $.wait(2000); 47 | await check_in(); 48 | $.done(); 49 | })(); 50 | } 51 | 52 | function get_task() { 53 | let get_task_req_data = { 54 | url: "https://www.52pojie.cn/home.php?mod=task&do=apply&id=2", 55 | headers: headers 56 | } 57 | $.http.put(get_task_req_data) 58 | } 59 | 60 | async function check_in() { 61 | let check_in_data = { 62 | url: "https://www.52pojie.cn/home.php?mod=task&do=draw&id=2&referer=https%3A%2F%2Fwww.52pojie.cn%2F.%2F%2Fthread-1521480-1-1.html", 63 | headers: headers 64 | } 65 | let req = await $.http.put(check_in_data); 66 | if (req.body.indexOf("您需要先登录才能继续本操作") !== -1) { 67 | $.notify("52破解", "", "cookie失效, 请检查"); 68 | } else if (req.body.indexOf("不是进行中的任务") !== -1) { 69 | $.notify("52破解", "", "签到失败, 原因为今日已签到或者领取任务失败"); 70 | } else if (req.body.indexOf("任务已完成") !== -1) { 71 | $.notify("52破解", "", "签到成功"); 72 | } else { 73 | $.notify("52破解", "", "签到失败, 签到原因未知, 请查看日志") 74 | console.log(req.body); 75 | } 76 | } 77 | 78 | //https://github.com/Peng-YM/QuanX/blob/master/Tools/OpenAPI/api-minified.js 79 | function ENV(){const e="function"==typeof require&&"undefined"!=typeof $jsbox;return{isQX:"undefined"!=typeof $task,isLoon:"undefined"!=typeof $loon,isSurge:"undefined"!=typeof $httpClient&&"undefined"!=typeof $utils,isBrowser:"undefined"!=typeof document,isNode:"function"==typeof require&&!e,isJSBox:e,isRequest:"undefined"!=typeof $request,isScriptable:"undefined"!=typeof importModule}}function HTTP(e={baseURL:""}){const{isQX:t,isLoon:s,isSurge:o,isScriptable:n,isNode:i,isBrowser:r}=ENV(),u=/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;const a={};return["GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"].forEach(h=>a[h.toLowerCase()]=(a=>(function(a,h){h="string"==typeof h?{url:h}:h;const d=e.baseURL;d&&!u.test(h.url||"")&&(h.url=d?d+h.url:h.url),h.body&&h.headers&&!h.headers["Content-Type"]&&(h.headers["Content-Type"]="application/x-www-form-urlencoded");const l=(h={...e,...h}).timeout,c={onRequest:()=>{},onResponse:e=>e,onTimeout:()=>{},...h.events};let f,p;if(c.onRequest(a,h),t)f=$task.fetch({method:a,...h});else if(s||o||i)f=new Promise((e,t)=>{(i?require("request"):$httpClient)[a.toLowerCase()](h,(s,o,n)=>{s?t(s):e({statusCode:o.status||o.statusCode,headers:o.headers,body:n})})});else if(n){const e=new Request(h.url);e.method=a,e.headers=h.headers,e.body=h.body,f=new Promise((t,s)=>{e.loadString().then(s=>{t({statusCode:e.response.statusCode,headers:e.response.headers,body:s})}).catch(e=>s(e))})}else r&&(f=new Promise((e,t)=>{fetch(h.url,{method:a,headers:h.headers,body:h.body}).then(e=>e.json()).then(t=>e({statusCode:t.status,headers:t.headers,body:t.data})).catch(t)}));const y=l?new Promise((e,t)=>{p=setTimeout(()=>(c.onTimeout(),t(`${a} URL: ${h.url} exceeds the timeout ${l} ms`)),l)}):null;return(y?Promise.race([y,f]).then(e=>(clearTimeout(p),e)):f).then(e=>c.onResponse(e))})(h,a))),a}function API(e="untitled",t=!1){const{isQX:s,isLoon:o,isSurge:n,isNode:i,isJSBox:r,isScriptable:u}=ENV();return new class{constructor(e,t){this.name=e,this.debug=t,this.http=HTTP(),this.env=ENV(),this.node=(()=>{if(i){return{fs:require("fs")}}return null})(),this.initCache();Promise.prototype.delay=function(e){return this.then(function(t){return((e,t)=>new Promise(function(s){setTimeout(s.bind(null,t),e)}))(e,t)})}}initCache(){if(s&&(this.cache=JSON.parse($prefs.valueForKey(this.name)||"{}")),(o||n)&&(this.cache=JSON.parse($persistentStore.read(this.name)||"{}")),i){let e="root.json";this.node.fs.existsSync(e)||this.node.fs.writeFileSync(e,JSON.stringify({}),{flag:"wx"},e=>console.log(e)),this.root={},e=`${this.name}.json`,this.node.fs.existsSync(e)?this.cache=JSON.parse(this.node.fs.readFileSync(`${this.name}.json`)):(this.node.fs.writeFileSync(e,JSON.stringify({}),{flag:"wx"},e=>console.log(e)),this.cache={})}}persistCache(){const e=JSON.stringify(this.cache,null,2);s&&$prefs.setValueForKey(e,this.name),(o||n)&&$persistentStore.write(e,this.name),i&&(this.node.fs.writeFileSync(`${this.name}.json`,e,{flag:"w"},e=>console.log(e)),this.node.fs.writeFileSync("root.json",JSON.stringify(this.root,null,2),{flag:"w"},e=>console.log(e)))}write(e,t){if(this.log(`SET ${t}`),-1!==t.indexOf("#")){if(t=t.substr(1),n||o)return $persistentStore.write(e,t);if(s)return $prefs.setValueForKey(e,t);i&&(this.root[t]=e)}else this.cache[t]=e;this.persistCache()}read(e){return this.log(`READ ${e}`),-1===e.indexOf("#")?this.cache[e]:(e=e.substr(1),n||o?$persistentStore.read(e):s?$prefs.valueForKey(e):i?this.root[e]:void 0)}delete(e){if(this.log(`DELETE ${e}`),-1!==e.indexOf("#")){if(e=e.substr(1),n||o)return $persistentStore.write(null,e);if(s)return $prefs.removeValueForKey(e);i&&delete this.root[e]}else delete this.cache[e];this.persistCache()}notify(e,t="",a="",h={}){const d=h["open-url"],l=h["media-url"];if(s&&$notify(e,t,a,h),n&&$notification.post(e,t,a+`${l?"\n多媒体:"+l:""}`,{url:d}),o){let s={};d&&(s.openUrl=d),l&&(s.mediaUrl=l),"{}"===JSON.stringify(s)?$notification.post(e,t,a):$notification.post(e,t,a,s)}if(i||u){const s=a+(d?`\n点击跳转: ${d}`:"")+(l?`\n多媒体: ${l}`:"");if(r){require("push").schedule({title:e,body:(t?t+"\n":"")+s})}else console.log(`${e}\n${t}\n${s}\n\n`)}}log(e){this.debug&&console.log(`[${this.name}] LOG: ${this.stringify(e)}`)}info(e){console.log(`[${this.name}] INFO: ${this.stringify(e)}`)}error(e){console.log(`[${this.name}] ERROR: ${this.stringify(e)}`)}wait(e){return new Promise(t=>setTimeout(t,e))}done(e={}){s||o||n?$done(e):i&&!r&&"undefined"!=typeof $context&&($context.headers=e.headers,$context.statusCode=e.statusCode,$context.body=e.body)}stringify(e){if("string"==typeof e||e instanceof String)return e;try{return JSON.stringify(e,null,2)}catch(e){return"[object Object]"}}}(e,t)} -------------------------------------------------------------------------------- /backUp/china_telecom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui by院长修改 5 | # @Time : 2022/9/12 16:10 6 | # cron "0 9,12 * * *" script-path=xxx.py,tag=匹配cron用 7 | # const $ = new Env('电信签到'); 8 | # ------------------------------- 9 | 10 | """ 11 | 1. 电信签到 支持多账号执行 不需要抓包 脚本仅供学习交流使用, 请在下载后24h内删除 12 | 2. cron说明 12点必须执行一次(用于兑换) 然后12点之外还需要执行一次(用于执行每日任务) 一天共两次 可直接使用默认cron 13 | 3. 环境变量说明: 14 | 变量名(必须): TELECOM_PHONE_PASSWORD 格式: 手机号&服务密码,1317xxx1322&123456 15 | 单个CK塞多个账号时,以#分隔开:手机号&服务密码#手机号&服务密码,1317xxx1322&123456#1317xxx1322&123456 16 | 选填 TELECOM_FOOD : 给宠物喂食次数 默认为0 不喂食 根据用户在网时长 每天可以喂食5-10次 17 | 4. 必须登录过 电信营业厅 app的账号才能正常运行 18 | """ 19 | """ 20 | update: 21 | 2022.10.25 参考大佬 github@QGCliveDavis https://github.com/QGCliveDavis 的 loginAuthCipherAsymmertric 参数解密 新增app登录获取token 完成星播客系列任务 感谢大佬 22 | 2022.11.11 增加分享任务 23 | """ 24 | import re 25 | from datetime import date, datetime 26 | from random import shuffle, randint, choices 27 | from time import sleep, strftime 28 | from re import findall 29 | from requests import get, post 30 | from base64 import b64encode 31 | from tools.aes_encrypt import AES_Ctypt 32 | from tools.rsa_encrypt import RSA_Encrypt 33 | from tools.tool import timestamp, get_environ, print_now 34 | from tools.ql_api import get_cookie 35 | from tools.send_msg import push 36 | from tools.notify import send 37 | from login.telecom_login import TelecomLogin 38 | from string import ascii_letters, digits 39 | import threading 40 | 41 | 42 | msg_str = "" 43 | 44 | 45 | class ChinaTelecom: 46 | def __init__(self, account, pwd, checkin=True): 47 | self.phone = account 48 | self.ticket = "" 49 | self.token = "" 50 | if pwd != "" and checkin: 51 | userLoginInfo = TelecomLogin(account, pwd).main() 52 | self.ticket = userLoginInfo[0] 53 | self.token = userLoginInfo[1] 54 | 55 | def init(self): 56 | self.msg = "" 57 | self.ua = f"CtClient;9.6.1;Android;12;SM-G9860;{b64encode(self.phone[5:11].encode()).decode().strip('=+')}!#!{b64encode(self.phone[0:5].encode()).decode().strip('=+')}" 58 | self.headers = { 59 | "Host": "wapside.189.cn:9001", 60 | "Referer": "https://wapside.189.cn:9001/resources/dist/signInActivity.html", 61 | "User-Agent": self.ua 62 | } 63 | self.key = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+ugG5A8cZ3FqUKDwM57GM4io6\nJGcStivT8UdGt67PEOihLZTw3P7371+N47PrmsCpnTRzbTgcupKtUv8ImZalYk65\ndU8rjC/ridwhw9ffW2LBwvkEnDkkKKRi2liWIItDftJVBiWOh17o6gfbPoNrWORc\nAdcbpk2L+udld5kZNwIDAQAB\n-----END PUBLIC KEY-----" 64 | 65 | 66 | def req(self, url, method, data=None): 67 | if method == "GET": 68 | data = get(url, headers=self.headers).json() 69 | return data 70 | elif method.upper() == "POST": 71 | data = post(url, headers=self.headers, json=data).json() 72 | return data 73 | else: 74 | print_now("您当前使用的请求方式有误,请检查") 75 | 76 | # 长明文分段rsa加密 77 | def telecom_encrypt(self, text): 78 | if len(text) <= 32: 79 | return RSA_Encrypt(self.key).encrypt(text) 80 | else: 81 | encrypt_text = "" 82 | for i in range(int(len(text) / 32) + 1): 83 | split_text = text[(32 * i):(32 * (i + 1))] 84 | encrypt_text += RSA_Encrypt(self.key).encrypt(split_text) 85 | return encrypt_text 86 | 87 | @staticmethod 88 | def geneRandomToken(): 89 | randomList = choices(ascii_letters + digits, k=129) 90 | token = f"V1.0{''.join(x for x in randomList)}" 91 | return token 92 | 93 | # 签到 94 | def chech_in(self): 95 | url = "https://wapside.189.cn:9001/jt-sign/api/home/sign" 96 | data = { 97 | "encode": AES_Ctypt("34d7cb0bcdf07523").encrypt( 98 | f'{{"phone":{self.phone},"date":{timestamp()},"signSource":"smlprgrm"}}') 99 | } 100 | print_now(self.req(url, "post", data)) 101 | 102 | # 获取任务列表 103 | def get_task(self): 104 | url = "https://wapside.189.cn:9001/jt-sign/paradise/getTask" 105 | data = { 106 | "para": self.telecom_encrypt(f'{{"phone":{self.phone}}}') 107 | } 108 | msg = self.req(url, "post", data) 109 | # print_now(dumps(msg, indent=2, ensure_ascii=False)) 110 | if msg["resoultCode"] == "0": 111 | self.task_list = msg["data"] 112 | else: 113 | print_now("获取任务列表失败") 114 | print_now(msg) 115 | return 116 | 117 | # 做每日任务 118 | def do_task(self): 119 | url = "https://wapside.189.cn:9001/jt-sign/paradise/polymerize" 120 | for task in self.task_list: 121 | if "翻牌抽好礼" in task["title"] or "查看我的订单" in task["title"] or "查看我的云盘" in task[ 122 | "title"] or "查看权益中心" in task["title"] or "访问宽带余额" in task["title"] or "访问“我的宽带”" in \ 123 | task["title"] or "查看“装修进度”" in task["title"] or "查看视频彩铃" in task["title"]: 124 | # if "翻牌抽好礼" in task["title"] or "查看我的订单" in task["title"] or "查看我的云盘" in task["title"]: 125 | #print_now(f'{task["title"]}----{task["taskId"]}') 126 | #print_now(f'{task["title"]}') 127 | decrept_para = f'{{"phone":"{self.phone}","jobId":"{task["taskId"]}"}}' 128 | data = { 129 | "para": self.telecom_encrypt(decrept_para) 130 | } 131 | data = self.req(url, "POST", data) 132 | if data["data"]["code"] == 0: 133 | print(f'账号{self.phone} {task["title"]}-------------------{data["resoultMsg"]}') 134 | # print_now(data) 135 | else: 136 | print_now(f'账号{self.phone} 聚合任务完成失败,原因是{data["resoultMsg"]}') 137 | 138 | # 给宠物喂食 139 | def food(self): 140 | url = "https://wapside.189.cn:9001/jt-sign/paradise/food" 141 | data = { 142 | "para": self.telecom_encrypt(f'{{"phone":{self.phone}}}') 143 | } 144 | res_data = self.req(url, "POST", data) 145 | if res_data["resoultCode"] == "0": 146 | print_now(res_data["resoultMsg"]) 147 | else: 148 | print_now(f'账号{self.phone} 聚合任务完成失败,原因是{res_data["resoultMsg"]}') 149 | 150 | # 查询宠物等级 151 | def get_level(self): 152 | url = "https://wapside.189.cn:9001/jt-sign/paradise/getParadiseInfo" 153 | body = { 154 | "para": self.telecom_encrypt(f'{{"phone":{self.phone}}}') 155 | } 156 | data = self.req(url, "POST", body) 157 | self.level = int(data["userInfo"]["paradiseDressup"]["level"]) 158 | if self.level < 5: 159 | print_now(f"账号{self.phone} 当前等级小于5级 不领取等级权益") 160 | return 161 | url = "https://wapside.189.cn:9001/jt-sign/paradise/getLevelRightsList" 162 | right_list = self.req(url, "POST", body)[f"V{self.level}"] 163 | for data in right_list: 164 | # print(dumps(data, indent=2, ensure_ascii=0)) 165 | if "00金豆" in data["righstName"] or "话费" in data["righstName"]: 166 | rightsId = data["id"] 167 | self.level_ex(rightsId) 168 | continue 169 | # print(self.rightsId) 170 | 171 | # 每月领取等级金豆 172 | def level_ex(self, rightsId): 173 | # self.get_level() 174 | url = "https://wapside.189.cn:9001/jt-sign/paradise/conversionRights" 175 | data = { 176 | "para": self.telecom_encrypt(f'{{"phone":{self.phone},"rightsId":"{rightsId}"}},"receiveCount":1') 177 | } 178 | print_now(self.req(url, "POST", data)) 179 | 180 | # 查询连续签到天数 181 | def query_signinfo(self): 182 | url = "https://wapside.189.cn:9001/jt-sign/reward/activityMsg" 183 | body = { 184 | "para": self.telecom_encrypt(f'{{"phone":{self.phone}}}') 185 | } 186 | data = self.req(url, "post", body) 187 | # print(dumps(data, indent=2, ensure_ascii=0)) 188 | recordNum = data["recordNum"] 189 | if recordNum != 0: 190 | return data["date"]["id"] 191 | return "" 192 | 193 | # 若连续签到为7天 则兑换 194 | def convert_reward(self): 195 | global msg_str #声明我们在函数内部使用的是在函数外部定义的全局变量msg_str 196 | url = "https://wapside.189.cn:9001/jt-sign/reward/convertReward" 197 | try: 198 | rewardId = self.query_signinfo() # "baadc927c6ed4d8a95e28fa3fc68cb9" 199 | except: 200 | rewardId = "baadc927c6ed4d8a95e28fa3fc68cb9" 201 | if rewardId == "": 202 | return 203 | body = { 204 | "para": self.telecom_encrypt( 205 | f'{{"phone":"{self.phone}","rewardId":"{rewardId}","month":"{date.today().__format__("%Y%m")}"}}') 206 | } 207 | for i in range(10): 208 | try: 209 | data = self.req(url, "post", body) 210 | except Exception as e: 211 | print(f"请求发送失败: " + str(e)) 212 | sleep(6) 213 | continue 214 | print_now(data) 215 | if data["code"] == "0": 216 | break 217 | sleep(6) 218 | reward_status = self.get_coin_info() 219 | if reward_status: 220 | self.msg += f"账号{self.phone}连续签到7天兑换2元话费成功\n" 221 | msg_str += f"账号{self.phone}连续签到7天兑换2元话费成功\n" 222 | print_now(self.msg) 223 | #push("电信签到兑换", self.msg) 224 | else: 225 | self.msg += f"账号{self.phone}连续签到7天兑换2元话费失败 明天会继续尝试兑换\n" 226 | msg_str += f"账号{self.phone}连续签到7天兑换2元话费失败 明天会继续尝试兑换\n" 227 | print_now(self.msg) 228 | #push("电信签到兑换", self.msg) 229 | 230 | # 查询金豆数量 231 | def coin_info(self): 232 | url = "https://wapside.189.cn:9001/jt-sign/api/home/userCoinInfo" 233 | data = { 234 | "para": self.telecom_encrypt(f'{{"phone":{self.phone}}}') 235 | } 236 | self.coin_count = self.req(url, "post", data) 237 | print_now(self.coin_count) 238 | 239 | def author(self): 240 | """ 241 | 通过usercode 获取 authorization 242 | :return: 243 | """ 244 | self.get_usercode() 245 | url = "https://xbk.189.cn/xbkapi/api/auth/userinfo/codeToken" 246 | data = { 247 | "usercode": self.usercode 248 | } 249 | data = post(url, headers=self.headers_live, json=data).json() 250 | self.authorization = f"Bearer {data['data']['token']}" 251 | self.headers_live["Authorization"] = self.authorization 252 | 253 | def get_usercode(self): 254 | """ 255 | 授权星播客登录获取 usercode 256 | :return: 257 | """ 258 | url = f"https://xbk.189.cn/xbkapi/api/auth/jump?userID={self.ticket}&version=9.3.3&type=room&l=renwu" 259 | self.headers_live = { 260 | "User-Agent": self.ua, 261 | "Host": "xbk.189.cn", 262 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 263 | "Accept-Language": "zh-CN,zh-Hans;q=0.9" 264 | } 265 | location = get(url, headers=self.headers_live, allow_redirects=False).headers["location"] 266 | usercode = findall(r"usercode=(.*?)&", location)[0] 267 | self.usercode = usercode 268 | 269 | def watch_video(self): 270 | """ 271 | 看视频 一天可完成6次 272 | :return: 273 | """ 274 | url = "https://xbk.189.cn/xbkapi/lteration/liveTask/index/watchVideo" 275 | data = { 276 | "articleId": 3453 277 | } 278 | data = post(url, headers=self.headers_live, json=data).json() 279 | if data["code"] == 0: 280 | print("账号{self.phone} 看小视频15s完成一次") 281 | else: 282 | print(f"账号{self.phone} 完成看小视频15s任务失败, 失败原因为{data['msg']}") 283 | 284 | def like(self): 285 | """ 286 | 点赞直播间 可完成5次 287 | :return: 288 | """ 289 | url = "https://xbk.189.cn/xbkapi/lteration/room/like" 290 | liveId_list = [1820, 2032, 2466, 2565, 1094, 2422, 1858, 2346] 291 | shuffle(liveId_list) 292 | for liveId in liveId_list[:5]: 293 | data = { 294 | "account": self.phone, 295 | "liveId": liveId 296 | } 297 | try: 298 | data = post(url, headers=self.headers_live, json=data).json() 299 | if data["code"] == 8888: 300 | sleep(2) 301 | print(data["msg"]) 302 | else: 303 | print(f"账号{self.phone} 完成点赞直播间任务失败,原因是{data['msg']}") 304 | except Exception: 305 | print(Exception) 306 | 307 | def watch_live(self): 308 | # 首先初始化任务,等待15秒倒计时后再完成 可完成10次 309 | url = "https://xbk.189.cn/xbkapi/lteration/liveTask/index/watchLiveInit" 310 | live_id = randint(1000, 2700) 311 | data = { 312 | "period": 1, 313 | "liveId": live_id 314 | } 315 | data = post(url, headers=self.headers_live, json=data).json() 316 | if data["code"] == 0: 317 | taskcode = data["data"] 318 | url = "https://xbk.189.cn/xbkapi/lteration/liveTask/index/watchLive" 319 | data = { 320 | "key": taskcode, 321 | "period": 1, 322 | "liveId": live_id 323 | } 324 | print("正在等待15秒") 325 | sleep(15) 326 | data = post(url, headers=self.headers_live, json=data).json() 327 | if data["code"] == 0: 328 | print("账号{self.phone} 完成1次观看直播任务") 329 | else: 330 | print(f"账号{self.phone} 完成观看直播任务失败,原因是{data['msg']}") 331 | else: 332 | print(f"账号{self.phone} 初始化观看直播任务失败,失败原因为{data['msg']}") 333 | 334 | def get_userid(self): 335 | url = "https://wapside.189.cn:9001/jt-sign/api/home/homeInfo" 336 | body = { 337 | "para": self.telecom_encrypt( 338 | f'{{"phone":"{self.phone}","signDate":"{datetime.now().__format__("%Y-%m")}"}}') 339 | } 340 | userid = post(url, json=body).json()["data"]["userInfo"]["userThirdId"] 341 | return userid 342 | 343 | def share(self): 344 | """ 345 | 50的分享任务 token不做校检 有值即可 若登录成功了 使用自己的token 否则生成随机的token 346 | :return: 347 | """ 348 | url = "https://appfuwu.189.cn:9021/query/sharingGetGold" 349 | body = { 350 | "headerInfos": { 351 | "code": "sharingGetGold", 352 | "timestamp": datetime.now().__format__("%Y%m%d%H%M%S"), 353 | "broadAccount": "", 354 | "broadToken": "", 355 | "clientType": "#9.6.1#channel50#iPhone 14 Pro Max#", 356 | "shopId": "20002", 357 | "source": "110003", 358 | "sourcePassword": "Sid98s", 359 | "token": self.token if self.token != "" else self.geneRandomToken(), 360 | "userLoginName": self.phone 361 | }, 362 | "content": { 363 | "attach": "test", 364 | "fieldData": { 365 | "shareSource": "3", 366 | "userId": self.get_userid(), 367 | "account": TelecomLogin.get_phoneNum(self.phone) 368 | } 369 | } 370 | } 371 | headers = { 372 | "user-agent": "iPhone 14 Pro Max/9.6.1" 373 | } 374 | data = post(url, headers=headers, json=body).json() 375 | print_now(data) 376 | 377 | def main(self): 378 | global msg_str #声明我们在函数内部使用的是在函数外部定义的全局变量msg_str 379 | self.init() 380 | self.chech_in() 381 | self.get_task() 382 | self.do_task() 383 | if foods != 0: 384 | for i in range(foods): 385 | self.food() 386 | # self.convert_reward() 387 | if datetime.now().day == 1: 388 | self.get_level() 389 | self.share() 390 | # if self.ticket != "": 391 | # self.author() 392 | # for i in range(6): 393 | # self.watch_video() 394 | # sleep(15) 395 | # self.like() 396 | # for i in range(10): 397 | # try: 398 | # self.watch_live() 399 | # except: 400 | # continue 401 | self.coin_info() 402 | self.msg += f"\n账号{self.phone} 当前有金豆{self.coin_count['totalCoin']}\n" 403 | msg_str += f"\n账号{self.phone} 当前有金豆{self.coin_count['totalCoin']}\n" 404 | #push("电信app签到", self.msg) 405 | 406 | def get_coin_info(self): 407 | url = "https://wapside.189.cn:9001/jt-sign/api/getCoinInfo" 408 | decrept_para = f'{{"phone":"{self.phone}","pageNo":0,"pageSize":10,type:"1"}}' 409 | data = { 410 | "para": self.telecom_encrypt(decrept_para) 411 | } 412 | data = self.req(url, "POST", data) 413 | 414 | try: 415 | if "skuName" in data["data"]["biz"]["results"][0] and "连续签到" in data["data"]["biz"]["results"][0]["skuName"]: 416 | return True 417 | except Exception as e: 418 | print(f"账号{self.phone}出现错误,请求失败结果: " ) 419 | print_now(data) 420 | return False 421 | 422 | 423 | 424 | 425 | 426 | 427 | def start(phone,password): 428 | if phone == "": 429 | exit(0) 430 | if password == "": 431 | print_now("电信服务密码未提供 只执行部分任务") 432 | if datetime.now().hour + (8 - int(strftime("%z")[2])) == 12: 433 | telecom = ChinaTelecom(phone, password, False) 434 | telecom.init() 435 | telecom.convert_reward() 436 | else: 437 | telecom = ChinaTelecom(phone, password) 438 | telecom.main() 439 | print("\n") 440 | 441 | 442 | 443 | 444 | if __name__ == '__main__': 445 | l = [] 446 | user_map = [] 447 | cklist = get_cookie("TELECOM_PHONE_PASSWORD") 448 | for i in range(len(cklist)): 449 | #以#分割开的ck 450 | split1 = cklist[i].split("#") 451 | if len(split1)>1: 452 | for j in range(len(split1)): 453 | split2 = split1[j].split("&") 454 | if len(split2)>1: 455 | user_map.append(split1[j]) 456 | else: 457 | userinfo = cklist[i].split("&") 458 | if len(userinfo)>1: 459 | user_map.append(cklist[i]) 460 | 461 | 462 | 463 | num_list = get_cookie("TELECOM_FOOD", 0, False) 464 | num = 0 465 | if num_list != 0: 466 | if len(num_list)>0: 467 | num = num_list[0] 468 | foods = int(float(num)) 469 | for i in range(len(user_map)): 470 | phone="" 471 | password="" 472 | userinfo = user_map[i].split("&") 473 | if len(userinfo)>1: 474 | phone = userinfo[0] 475 | password = userinfo[1] 476 | print('开始执行第{}个账号:{}'.format((i+1),phone)) 477 | if phone == "": 478 | print("当前账号未填写手机号 跳过") 479 | print("\n") 480 | continue 481 | p = threading.Thread(target=start,args=(phone,password)) 482 | l.append(p) 483 | p.start() 484 | print("\n") 485 | for i in l: 486 | i.join() 487 | send("电信签到",msg_str) 488 | -------------------------------------------------------------------------------- /backUp/telecom_live_lotter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui by院长修改 5 | # @Time : 2022/11/11 10:42 6 | # cron "*/30 8-23 * * *" script-path=xxx.py,tag=匹配cron用 7 | # const $ = new Env('某营业厅直播抽奖'); 8 | # ------------------------------- 9 | """ 10 | 1. 脚本仅供学习交流使用, 请在下载后24h内删除 11 | 2. 环境变量说明: 12 | 变量名(必须): TELECOM_PHONE_PASSWORD 13 | 格式: 手机号&服务密码,1317xxx1322&123456 14 | 单个CK塞多个账号时,以#分隔开:手机号&服务密码#手机号&服务密码,1317xxx1322&123456#1317xxx1322&123456 15 | 3. 必须登录过 电信营业厅 app的账号才能正常运行 16 | """ 17 | import re 18 | from random import randint 19 | from base64 import b64encode 20 | from time import mktime, strptime, strftime, sleep as time_sleep 21 | from requests import post, get, packages 22 | packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ":HIGH:!DH:!aNULL" 23 | from datetime import datetime, timedelta 24 | from asyncio import wait, sleep, run 25 | 26 | from tools.ql_api import get_cookie 27 | from tools.tool import timestamp, get_environ, print_now 28 | from tools.send_msg import push 29 | from china_telecom import ChinaTelecom 30 | import threading 31 | import time 32 | import requests 33 | import json 34 | 35 | from tools.notify import send 36 | 37 | class TelecomLotter: 38 | def __init__(self, phone, password): 39 | self.phone = phone 40 | chinaTelecom = ChinaTelecom(phone, password) 41 | chinaTelecom.init() 42 | chinaTelecom.author() 43 | self.authorization = chinaTelecom.authorization 44 | self.ua = chinaTelecom.ua 45 | self.token = chinaTelecom.token 46 | 47 | def get_action_id(self, liveId): 48 | url = "https://appkefu.189.cn:8301/query/getWaresList" 49 | body = { 50 | "headerInfos": { 51 | "code": "getWaresList", 52 | "timestamp": datetime.now().__format__("%Y%m%d%H%M%S"), 53 | "broadAccount": "", 54 | "broadToken": "", 55 | "clientType": "#9.6.1#channel128#samsung SM-G9860#", 56 | "shopId": "20002", 57 | "source": "110003", 58 | "sourcePassword": "Sid98s", 59 | "token": self.token, 60 | "userLoginName": self.phone 61 | }, 62 | "content": { 63 | "attach": "test", 64 | "fieldData": { 65 | "limit": "", 66 | "page": "1", 67 | "liveId": liveId 68 | } 69 | } 70 | } 71 | headers = { 72 | "User-Agent": self.ua, 73 | "authorization": self.authorization 74 | } 75 | data = post(url, headers=headers, json=body).json() 76 | try: 77 | for waresInfo in data["responseData"]["data"]["waresInfos"]: 78 | print(waresInfo["title"]) 79 | if "转盘" in waresInfo["title"] or "抽奖" in waresInfo["title"]: 80 | active_code = findall(r"active_code\u003d(.*?)\u0026", waresInfo["link"])[0] 81 | return active_code 82 | return None 83 | except: 84 | return None 85 | def get_action_id_other(self, liveId): 86 | def encrypt_phone(): 87 | result = "" 88 | for i in self.phone: 89 | result += chr(ord(i) + 2) 90 | return result 91 | url = "https://wapmkt.189.cn:8301/query/directSeedingInfo" 92 | body = { 93 | "headerInfos": { 94 | "code": "directSeedingInfo", 95 | "timestamp": datetime.now().__format__("%Y%m%d%H%M%S"), 96 | "broadAccount": "", 97 | "broadToken": "", 98 | "clientType": "#9.6.1#channel128#samsung SM-G9860#", 99 | "shopId": "20002", 100 | "source": "110003", 101 | "sourcePassword": "Sid98s", 102 | "token": self.token, 103 | "userLoginName": self.phone 104 | }, 105 | "content": { 106 | "attach": "test", 107 | "fieldData": { 108 | "liveId": liveId, 109 | "account": encrypt_phone() 110 | } 111 | } 112 | } 113 | headers = { 114 | "User-Agent": self.ua, 115 | "authorization": self.authorization 116 | } 117 | data = post(url, headers=headers, json=body).json()["responseData"]["data"] 118 | try: 119 | if data["buoyLink"] is None: 120 | return None 121 | active_code = findall(r"active_code\u003d(.*?)\u0026", data["buoyLink"])[0] 122 | return active_code 123 | except: 124 | return None 125 | async def lotter(self, liveId, period): 126 | """ 127 | :param liveId: 直播间id 128 | :param period: 某个参数 暂不明意义 查询直播间信息时会返回 129 | :return: 130 | """ 131 | print_now(f"当前执行的直播间id为{liveId}") 132 | for i in range(2): 133 | # active_code1 查询直播间购物车中的大转盘活动id 134 | active_code1 = self.get_action_id(liveId) 135 | # active_code2 查询直播间非购物车 而是右上角的大转盘活动id 136 | active_code2 = self.get_action_id_other(liveId) 137 | if active_code1 is not None or active_code2 is not None: 138 | break 139 | print(f"此直播间暂无抽奖活动, 等待10秒后再次查询 剩余查询次数{2 - i}") 140 | await sleep(10) 141 | continue 142 | if active_code1 is None and active_code2 is None: 143 | print("查询结束 本直播间暂无抽奖活动") 144 | return 145 | elif active_code1 is None or active_code2 is None: 146 | active_code = active_code1 if active_code2 is None else active_code2 147 | active_code_list = [active_code] 148 | else: 149 | active_code_list = [active_code1, active_code2] 150 | for active_code in active_code_list: 151 | url = "https://xbk.189.cn/xbkapi/active/v2/lottery/do" 152 | body = { 153 | "active_code": active_code, 154 | "liveId": liveId, 155 | "period": period 156 | } 157 | headers = { 158 | "User-Agent": self.ua, 159 | "authorization": self.authorization 160 | } 161 | data = post(url, headers=headers, json=body).json() 162 | print(data) 163 | time_sleep(10) 164 | if data["code"] == 0: 165 | push("直播抽奖", f"{self.phone}: 获得了{data['data']['title']}") 166 | def find_price(self): 167 | url = "https://xbk.189.cn/xbkapi/active/v2/lottery/getMyWinList?page=1&give_status=200&activeCode=" 168 | headers = { 169 | "User-Agent": self.ua, 170 | "authorization": self.authorization 171 | } 172 | data = get(url, headers=headers).json() 173 | if data["code"] == 0: 174 | all_price_list = data["data"] 175 | compare_date = lambda date: date.split("-")[1] == str((datetime.now() + timedelta(hours=8 - int(strftime("%z")[2]))).month) 176 | month_price = [f'{info["win_time"]}: {info["title"]}' for info in all_price_list if compare_date(info["win_time"])] 177 | month_price_info = "\n".join(month_price) 178 | print(month_price_info) 179 | push("本月直播奖品查询", f"{self.phone}:\n{month_price_info}") 180 | else: 181 | print(f"获取奖品信息失败, 接口返回" + str(data)) 182 | 183 | 184 | 185 | 186 | def get_data(): 187 | print('正在加载今日直播数据ing...') 188 | all_list = [] 189 | code = 1 190 | msg_str = "" 191 | for i in range(35): 192 | if code < 10: 193 | code_str = '0' + str(code) 194 | else: 195 | code_str = str(code) 196 | url = f'https://xbk.189.cn/xbkapi/lteration/index/recommend/anchorRecommend?provinceCode={code_str}' 197 | random_phone = f"1537266{randint(1000, 9999)}" 198 | headers = { 199 | "referer": "https://xbk.189.cn/xbk/newHome?version=9.4.0&yjz=no&l=card&longitude=%24longitude%24&latitude=%24latitude%24&utm_ch=hg_app&utm_sch=hg_sh_shdbcdl&utm_as=xbk_tj&loginType=1", 200 | "user-agent": f"CtClient;9.6.1;Android;12;SM-G9860;{b64encode(random_phone[5:11].encode()).decode().strip('=+')}!#!{b64encode(random_phone[0:5].encode()).decode().strip('=+')}" 201 | } 202 | # print(url) 203 | data = requests.get(url, headers=headers).json() 204 | body = data["data"] 205 | for i in body: 206 | if time.strftime('%Y-%m-%d') in i['start_time']: 207 | if i not in all_list: 208 | print('今日开播时间:'+i['start_time']+' 直播间名称:'+i['nickname'] ) 209 | print('安卓浏览器(如via、alook浏览器)直接打开链接 ctclient://startapp/android/open?LinkType=5&Link=https://xbk.189.cn/xbk/livingRoom?liveId='+str(i['liveId']) ) 210 | print('通用打开方式,先登录:https://xbk.189.cn/xbk/newHome 然后直接打开 https://xbk.189.cn/xbk/livingRoom?liveId='+str(i['liveId']) ) 211 | print('\n\n') 212 | msg_str += '今日开播时间:'+i['start_time']+' 直播间名称:'+i['nickname']+'\n1、安卓打开方式\n浏览器(如via、alook浏览器)直接打开链接:\nctclient://startapp/android/open?LinkType=5&Link=https://xbk.189.cn/xbk/livingRoom?liveId='+str(i['liveId'])+'\n2、通用打开方式\n先登录:\nhttps://xbk.189.cn/xbk/newHome\n然后直接打开链接:\nhttps://xbk.189.cn/xbk/livingRoom?liveId='+str(i['liveId'])+'\n\n' 213 | all_list.append(i) 214 | code += 1 215 | list = {} 216 | f = 1 217 | for i in all_list: 218 | list['liveRoom' + str(f)] = i 219 | f += 1 220 | print('直播数据加载完毕') 221 | print('\n\n') 222 | #发送消息 223 | send('电信星播客直播通知', msg_str) 224 | return list 225 | 226 | 227 | 228 | 229 | 230 | def main(phone, password): 231 | apiType = 1 232 | #切换使用直接加载方式 233 | data = getData 234 | # try: 235 | # url = "https://gitee.com/kele2233/genxin/raw/master/telecomLiveInfo.json" 236 | # data = get(url, timeout=5).json() 237 | # except: 238 | # print("主直播接口失效,进入备用抓包接口") 239 | # data = list_d 240 | # # try: 241 | # # url = "https://raw.githubusercontent.com/limoruirui/Hello-Wolrd/main/telecomLiveInfo.json" 242 | # # #url = "https://api.ruirui.fun/telecom/getLiveInfo" 243 | # # data = get(url, timeout=5).json() 244 | # # except: 245 | # # url = "https://xbk.189.cn/xbkapi/lteration/index/recommend/anchorRecommend?provinceCode=01" 246 | # # random_phone = f"1537266{randint(1000, 9999)}" 247 | # # headers = { 248 | # # "referer": "https://xbk.189.cn/xbk/newHome?version=9.4.0&yjz=no&l=card&longitude=%24longitude%24&latitude=%24latitude%24&utm_ch=hg_app&utm_sch=hg_sh_shdbcdl&utm_as=xbk_tj&loginType=1", 249 | # # "user-agent": f"CtClient;9.6.1;Android;12;SM-G9860;{b64encode(random_phone[5:11].encode()).decode().strip('=+')}!#!{b64encode(random_phone[0:5].encode()).decode().strip('=+')}" 250 | # # } 251 | # # data = get(url, headers=headers).json() 252 | # # apiType = 2 253 | print(data) 254 | liveListInfo = {} 255 | allLiveInfo = data.values() if apiType == 1 else data["data"] 256 | for liveInfo in allLiveInfo: 257 | if 1740 > timestamp(True) - int(mktime(strptime(liveInfo["start_time"], "%Y-%m-%d %H:%M:%S"))) + ( 258 | 8 - int(strftime("%z")[2])) * 3600 > 0: 259 | liveListInfo[liveInfo["liveId"]] = liveInfo["period"] 260 | if len(liveListInfo) == 0: 261 | print("查询结束 没有近期开播的直播间") 262 | else: 263 | telecomLotter = TelecomLotter(phone, password) 264 | all_task = [telecomLotter.lotter(liveId, period) for liveId, period in liveListInfo.items()] 265 | run(wait(all_task)) 266 | now = datetime.now() 267 | if now.hour == 12 + int(strftime("%z")[2]) and now.minute > 10: 268 | TelecomLotter(phone, password).find_price() 269 | 270 | 271 | 272 | def start(phone,password): 273 | if phone == "" or password == "": 274 | print("未填写相应变量 退出") 275 | exit(0) 276 | main(phone, password) 277 | print("\n") 278 | 279 | 280 | 281 | 282 | if __name__ == '__main__': 283 | getData = [] 284 | # try: 285 | # url = "https://gitcode.net/weixin_52142858/telecomliveinfo/-/raw/master/telecomLiveInfo.json" 286 | # getData = get(url, timeout=5).json() 287 | # except: 288 | # #加载今日直播信息 289 | # print('主接口失效,使用备用接口中。。。。') 290 | # getData=get_data() 291 | 292 | 293 | 294 | 295 | 296 | l = [] 297 | getData=get_data() 298 | # user_map = [] 299 | # cklist = get_cookie("TELECOM_PHONE_PASSWORD") 300 | # for i in range(len(cklist)): 301 | # #以#分割开的ck 302 | # split1 = cklist[i].split("#") 303 | # if len(split1)>1: 304 | # for j in range(len(split1)): 305 | # split2 = split1[j].split("&") 306 | # if len(split2)>1: 307 | # user_map.append(split1[j]) 308 | # else: 309 | # userinfo = cklist[i].split("&") 310 | # if len(userinfo)>1: 311 | # user_map.append(cklist[i]) 312 | 313 | 314 | 315 | # for i in range(len(user_map)): 316 | # phone="" 317 | # password="" 318 | # userinfo = user_map[i].split("&") 319 | # if len(userinfo)>1: 320 | # phone = userinfo[0] 321 | # password = userinfo[1] 322 | # print('开始执行第{}个账号:{}'.format((i+1),phone)) 323 | # if phone == "" or password == "": 324 | # print("当前账号未填写手机号或者密码 跳过") 325 | # print("\n") 326 | # continue 327 | # p = threading.Thread(target=start,args=(phone,password)) 328 | # l.append(p) 329 | # p.start() 330 | # print("\n") 331 | # for i in l: 332 | # i.join() 333 | -------------------------------------------------------------------------------- /backUp/txsp_vipRed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 22/5/2022 10:48 6 | # ------------------------------- 7 | 8 | """ 9 | 1.腾讯视频每月领取会员天数红包 请低调使用 请不要用于商业牟利 10 | 2.活动时间为每个月的 8号到13号 的 10点到24点 11 | 3.活动期间内一天一次 每天限制领取两次 每个月限制次数暂时未知 请自行探索 请自行斟酌crontab 12 | 4.cookie获取方式 13 | 1.cookie可以用别人loon、qx等软件的mitm类自动获取再去boxjs里复制出来填写到环境变量或本脚本中 14 | 2.也可以自行抓包 电脑或者手机都可以 抓链接为https://access.video.qq.com/user/auth_refresh?的 要整段url和对应headers下的cookie 15 | 5.cookie食用方式: cookie和url都要整段 青龙运行可新建并分别放入到环境变量 V_COOKIE和V_REF_URL 中 16 | 6.推荐抓取腾讯视频app端随便一条链接的headers下的user-agent 并放入环境变量 TX_UA 中 不填写会使用随机的chrome浏览器的user-agent 17 | 7.推送支持tgbot和pushplus 会读取环境变量 青龙若之前有设置 则不需要额外设置 18 | """ 19 | from random import randint 20 | from time import time, sleep 21 | from re import findall 22 | from os import environ, system 23 | from sys import exit, stdout 24 | from json import dumps, load 25 | from datetime import datetime 26 | 27 | try: 28 | from requests import Session, get, post 29 | from fake_useragent import UserAgent 30 | except: 31 | print( 32 | "你还没有安装requests库和fake_useragent库 正在尝试自动安装 请在安装结束后重新执行此脚本\n若还是提示本条消息 请自行运行pip3 install requests和pip3 install fake-useragent或者在青龙的依赖管理里安装python的requests和fake-useragent") 33 | system("pip3 install fake-useragent") 34 | system("pip3 install requests") 35 | print("安装完成 脚本退出 请重新执行") 36 | exit(0) 37 | 38 | 39 | class Txsp_vipRed: 40 | def __init__(self): 41 | self.cookie = environ.get("V_COOKIE") 42 | self.ref_url = environ.get("V_REF_URL") 43 | if self.cookie == "" or self.ref_url == "": 44 | self.print_now("未填写腾讯V_COOKIE或者V_REF_URL") 45 | exit(0) 46 | 47 | self.msg = "" 48 | self.actId = "" 49 | self.laisee_id = "" 50 | self.session = Session() 51 | self.ua = environ.get("TX_UA") if environ.get("TX_UA") else UserAgent().chrome 52 | self.own_ex = environ.get("TX_EGG_OWN") if environ.get("TX_EGG_OWN") else False 53 | self.headers = { 54 | "user-agent": self.ua 55 | } 56 | 57 | """推送相关""" 58 | self.pushplus_token = environ.get("PUSH_PLUS_TOKEN") if environ.get("PUSH_PLUS_TOKEN") else "" 59 | self.tgbot_token = environ.get("TG_BOT_TOKEN") if environ.get("TG_BOT_TOKEN") else "" 60 | self.tg_userId = environ.get("TG_USER_ID") if environ.get("TG_USER_ID") else "" 61 | self.tg_push_api = environ.get("TG_API_HOST") if environ.get("TG_API_HOST") else "" 62 | 63 | """工具""" 64 | 65 | def pushplus(self, title, content): 66 | url = "http://www.pushplus.plus/send" 67 | headers = { 68 | "Content-Type": "application/json" 69 | } 70 | data = { 71 | "token": self.pushplus_token, 72 | "title": title, 73 | "content": content 74 | } 75 | try: 76 | post(url, headers=headers, data=dumps(data)) 77 | except: 78 | self.print_now('推送失败') 79 | 80 | def tgpush(self, content): 81 | url = f"https://api.telegram.org/bot{self.tgbot_token}/sendMessage" 82 | if self.tg_push_api != "": 83 | url = f"https://{self.tg_push_api}/bot{self.tgbot_token}/sendMessage" 84 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 85 | data = {'chat_id': str(self.tg_userId), 'text': content, 'disable_web_page_preview': 'true'} 86 | try: 87 | post(url, headers=headers, data=data, timeout=10) 88 | except: 89 | self.print_now('推送失败') 90 | 91 | def push(self, msg): 92 | if self.pushplus_token != "": 93 | self.pushplus("腾讯视频每月领取会员", msg) 94 | if self.tgbot_token != "" and self.tg_userId != "": 95 | self.tgpush(f"腾讯视频每月领取会员\n{msg}") 96 | 97 | def timestamp(self, short=False): 98 | if (short): 99 | return int(time()) 100 | return int(time() * 1000) 101 | 102 | def print_now(self, content): 103 | print(content) 104 | stdout.flush() 105 | 106 | """重置cookie有效期""" 107 | 108 | def refresh_cookie(self): 109 | headers = { 110 | 'Referer': 'https://v.qq.com', 111 | "Cookie": self.cookie, 112 | "User-Agent": self.ua 113 | } 114 | req = self.session.get(self.ref_url, headers=headers) 115 | if req.headers.get("Set-Cookie") == None: 116 | if self.pushplus_token != "": 117 | self.pushplus("腾讯视频碰蛋活动", "cookie过期或填写错误") 118 | if self.tgbot_token != "" and self.tg_userId != "": 119 | self.tgpush(f"腾讯视频碰蛋活动\ncookie过期或填写错误") 120 | self.print_now("cookie过期或者填写错误, 退出") 121 | exit(0) 122 | # data = loads(req.text[42:-2]) 123 | data = req.text 124 | # self.head = data["head"] 125 | # self.nickname = data["nick"] 126 | self.head = findall(r"\"head\":\"(.*?)\"", data)[0] 127 | self.nickname = findall(r"\"nick\":\"(.*?)\"", data)[0] 128 | 129 | def get_laisee_id(self): 130 | url = "https://api.ruirui.fun/txsp/get_laisee_id" 131 | try: 132 | data = get(url).json() 133 | if data.get("msg") == "success": 134 | self.print_now(f"获取到的助力码为{data['data']}") 135 | return data["data"] 136 | else: 137 | self.print_now("从获取助力码失败,最大可能是助力池为空") 138 | self.msg += "本次运行没有获取到红包码, 可能是池子为空" 139 | return False 140 | except: 141 | self.print_now("获取助力码失败, 可能是api炸了, 也可能你的网络有问题") 142 | return False 143 | 144 | def post_laisee_id(self, laisee_id): 145 | url = "https://api.ruirui.fun/txsp/post_laisee_id" 146 | body = { 147 | "laisee_id": laisee_id, 148 | "last_num": self.lastnum 149 | } 150 | headers = { 151 | "Content-Type": "application/json" 152 | } 153 | try: 154 | data = post(url, headers=headers, json=body).json() 155 | if data.get("data") == "success": 156 | self.msg += "互助码提交成功" 157 | self.print_now("互助码提交成功") 158 | except: 159 | self.print_now("互助码提交失败,跳过提交,获取助力码") 160 | 161 | def get_level(self): 162 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=payvip&cmd=1&otype=json&getannual=1&geticon=1&getsvip=1&g_tk=610014353&_={self.timestamp()}&callback=Zepto{self.timestamp()}' 163 | headers = { 164 | "referer": "https://film.qq.com/x/autovue/grade/?ptag=user.h5", 165 | "host": "vip.video.qq.com", 166 | "accept-encoding": "gzip, deflate, br", 167 | "user-agent": self.ua} 168 | response = self.session.get(url=url, headers=headers) 169 | response.encoding = "utf-8" 170 | try: 171 | level = response.text.split('level')[1].split(',')[0].split(':')[1] 172 | return level 173 | except: 174 | self.print_now("获取等级信息失败, 最大可能是cookie过期或者格式不对, 也可能为网络原因") 175 | exit(0) 176 | 177 | def getActId(self): 178 | url = 'https://film.qq.com/x/autovue/privilege/?pid=privilege&hidetitlebar=1&hidestatusbar=0&style=titlecolor%3D%23ffffff%26contentbkcolor%3D%23fdf6e2&aid=V0$$1:0$2:7$3:8.4.77.25550$4:0$8:4$12:&isDarkMode=0&uiType=MAX' 179 | headers = { 180 | 'User-Agent': 'Mozilla/5.0 (iPad; CPU OS 15_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/11A465 QQLiveBrowser /8.4.55 AppType/UN WebKitCore/WKWebView iOS GDTTangramMobSDK/4.370.6 GDTMobSDK/4.370.6 cellPhone/iPad 1G' 181 | } 182 | req = self.session.get(url, headers=headers) 183 | req.encoding = 'utf-8' 184 | actId = findall(r'"laiSeeActId":"(.*?)",', req.text)[0] 185 | if len(actId) == 26: 186 | return actId 187 | else: 188 | self.msg += '活动id获取失败,请检查' 189 | return None 190 | 191 | def check_lastnum(self, laisee_id): 192 | url = f"https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_vipred_route_read&cmd=1&laisee_id={laisee_id}&otype=xjson&_ts={self.timestamp()}" 193 | headers = { 194 | "Referer": f"https://m.film.qq.com/magic-act/{self.actId}/index_index.html?ovscroll=0&page=index&isDarkMode=0&uiType=MAX", 195 | "User-Agent": self.ua 196 | } 197 | data = get(url, headers=headers).json() 198 | self.lastnum = int(data["total"]) - int(data["used"]) 199 | if self.lastnum == 0: 200 | self.print_now("您本月的红包已被领完,暂不提交") 201 | return False 202 | return True 203 | 204 | def gen_laisee_id(self, actId): 205 | url = f'https://vip.video.qq.com/rpc/trpc.vip_red_group.vip_red_qualification.VipRedQualification/RedQualificationSend?rpc_data=%7B%22act_id%22:%22{actId}%22%7D' 206 | headers = { 207 | 'User-Agent': self.ua, 208 | 'Referer': 'https://film.qq.com/x/autovue/privilege/route/homepage/take?pid=privilege&hidetitlebar=1&hidestatusbar=0&style=titlecolor%3D%23ffffff%26contentbkcolor%3D%23fdf6e2&aid=V0%24%241%3A0%242%3A7%243%3A8.4.77.25550%244%3A0%248%3A4%2412%3A&isDarkMode=0&uiType=MAX' 209 | } 210 | data = self.session.get(url, headers=headers).json() 211 | order_id = data['orderid'] 212 | # print(order_id) 213 | url2 = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?callback=jQuery{randint(30000000000000000000, 39999999999999999999)}_{self.timestamp()}&name=spp_vipred_route_write&cmd=1&head={self.head}&nick={self.nickname}&order_id={order_id}&_={self.timestamp()}' 214 | # print(url2) 215 | data = self.session.get(url2, headers=headers).text 216 | self.print_now(data) 217 | try: 218 | self.laisee_id = findall(r'"laisee_id":"(.*?)",', data)[0] 219 | except: 220 | self.print_now("生成红包码失败, 可能是今天已经领完了, 请明天早上10点再来") 221 | self.laisee_id = "" 222 | if self.laisee_id != "": 223 | self.msg += f"腾讯视频红包分享链接,https://m.film.qq.com/magic-act/{actId}/1_index_index.html?ptag=redshare&redenvelopeId={self.laisee_id}&ovscroll=0&page=index 点击链接领取几天腾讯视频会员" 224 | return True 225 | else: 226 | return False 227 | 228 | def receive(self, laisee_id): 229 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_vipred_route_write&cmd=2&laisee_id={laisee_id}&nick={self.nickname}&head={self.head}&act_id={self.actId}&otype=xjson&_ts={self.timestamp()}' 230 | headers = { 231 | 'Origin': 'https://m.film.qq.com', 232 | 'Accept-Encoding': 'gzip, deflate, br', 233 | 'Host': 'vip.video.qq.com', 234 | 'User-Agent': self.ua, 235 | 'Referer': f'https://m.film.qq.com/magic-act/{self.actId}/index_index.html?ovscroll=0&page=index&isDarkMode=0&uiType=MAX' 236 | } 237 | data = self.session.get(url, headers=headers).json() 238 | self.print_now(data) 239 | if "content" in data: 240 | receive_day = data["content"] 241 | self.print_now(f"领取成功, 获得{receive_day}天会员, 也可能是这个月已经领过的") 242 | self.msg += f"领取成功, 获得{receive_day}天会员, 也可能是这个月已经领过的" 243 | sleep(1) 244 | else: 245 | self.print_now("领取失败,此红包码已被领完或者你本日/本周/本月已领到上限") 246 | 247 | def main(self): 248 | today = datetime.today().day 249 | hour = datetime.today().hour 250 | if today < 8 or today > 13 or hour < 10: 251 | self.print_now("当前不在活动时间 活动时间为每个月的8号到13号的10点到24点") 252 | exit(0) 253 | self.refresh_cookie() 254 | self.actId = self.getActId() 255 | if self.actId is None: 256 | self.print_now(self.msg) 257 | self.push(self.msg) 258 | exit(0) 259 | if int(self.get_level()) >= 6: 260 | self.print_now("您当前账号大于等于6级, 领取红包码并分享") 261 | if self.gen_laisee_id(self.actId): 262 | if self.check_lastnum(self.laisee_id): 263 | self.post_laisee_id(self.laisee_id) 264 | laisee_id_list = self.get_laisee_id() 265 | if laisee_id_list: 266 | self.print_now(f"本次获取到的红包码为\n{laisee_id_list}") 267 | for laisee_id in laisee_id_list: 268 | self.receive(laisee_id) 269 | self.push(self.msg) 270 | 271 | if __name__ == '__main__': 272 | Txsp_vipRed().main() 273 | # test = Txsp_vipRed() 274 | # test.gen_laisee_id(actId="6iuw8rky3tsid022s4rf5iauqg") 275 | -------------------------------------------------------------------------------- /backUp/txspegg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 7/5/2022 20:48 6 | # ------------------------------- 7 | """ 8 | 1.腾讯视频碰蛋活动 请低调使用 请不要用于商业牟利 9 | 2.一天一次或者两次(推荐一次) (((若在每天的16点后运行且环境变量 TX_EGG_OWN 设置为true 则会自己的账号单独开一次(个人不是很建议这种做法 不找人碰不确定会不会加大黑号风险 请自行斟酌),))) 10 | 括号内的时间和变量必须同时满足才会自己碰自己 否则都是池子有码就碰池子 没有就上传你的码到池子 请自行斟酌设置crontab 11 | 3.cookie获取方式 12 | 1.cookie可以用别人loon、qx等软件的mitm类自动获取再去boxjs里复制出来填写到环境变量或本脚本中 13 | 2.也可以自行抓包 电脑或者手机都可以 抓链接为https://access.video.qq.com/user/auth_refresh?的 要整段url和对应headers下的cookie 14 | 4.cookie食用方式: cookie和url都要整段 青龙运行可新建并分别放入到环境变量 V_COOKIE和V_REF_URL 中 15 | 5.推荐抓取腾讯视频app端随便一条链接的headers下的user-agent 并放入环境变量 TX_UA 中 不填写会使用随机的chrome浏览器的user-agent 16 | 6.推送支持tgbot和pushplus 会读取环境变量 青龙若之前有设置 则不需要额外设置 17 | """ 18 | from time import time, sleep, localtime 19 | from re import findall 20 | from os import environ, system 21 | from sys import exit, stdout 22 | from json import dumps 23 | 24 | try: 25 | from requests import Session, get, post 26 | from fake_useragent import UserAgent 27 | except: 28 | print( 29 | "你还没有安装requests库和fake_useragent库 正在尝试自动安装 请在安装结束后重新执行此脚本\n若还是提示本条消息 请自行运行pip3 install requests和pip3 install fake-useragent或者在青龙的依赖管理里安装python的requests和fake-useragent") 30 | system("pip3 install fake-useragent") 31 | system("pip3 install requests") 32 | print("安装完成 脚本退出 请重新执行") 33 | exit(0) 34 | 35 | 36 | class Txspegg: 37 | def __init__(self): 38 | self.cookie = environ.get("V_COOKIE") 39 | self.ref_url = environ.get("V_REF_URL") 40 | if self.cookie == "" or self.ref_url == "": 41 | self.print_now("未填写腾讯V_COOKIE或者V_REF_URL") 42 | exit(0) 43 | 44 | self.msg = "" 45 | self.session = Session() 46 | self.ua = environ.get("TX_UA") if environ.get("TX_UA") else UserAgent().chrome 47 | self.own_ex = environ.get("TX_EGG_OWN") if environ.get("TX_EGG_OWN") else False 48 | self.headers = { 49 | "user-agent": self.ua 50 | } 51 | 52 | """推送相关""" 53 | self.pushplus_token = environ.get("PUSH_PLUS_TOKEN") if environ.get("PUSH_PLUS_TOKEN") else "" 54 | self.tgbot_token = environ.get("TG_BOT_TOKEN") if environ.get("TG_BOT_TOKEN") else "" 55 | self.tg_userId = environ.get("TG_USER_ID") if environ.get("TG_USER_ID") else "" 56 | self.tg_push_api = environ.get("TG_API_HOST") if environ.get("TG_API_HOST") else "" 57 | 58 | """工具""" 59 | 60 | def pushplus(self, title, content): 61 | url = "http://www.pushplus.plus/send" 62 | headers = { 63 | "Content-Type": "application/json" 64 | } 65 | data = { 66 | "token": self.pushplus_token, 67 | "title": title, 68 | "content": content 69 | } 70 | try: 71 | post(url, headers=headers, data=dumps(data)) 72 | except: 73 | self.print_now('推送失败') 74 | 75 | def tgpush(self, content): 76 | url = f"https://api.telegram.org/bot{self.tgbot_token}/sendMessage" 77 | if self.tg_push_api != "": 78 | url = f"https://{self.tg_push_api}/bot{self.tgbot_token}/sendMessage" 79 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 80 | data = {'chat_id': str(self.tg_userId), 'text': content, 'disable_web_page_preview': 'true'} 81 | try: 82 | post(url, headers=headers, data=data, timeout=10) 83 | except: 84 | self.print_now('推送失败') 85 | 86 | def timestamp(self, short=False): 87 | if (short): 88 | return int(time()) 89 | return int(time() * 1000) 90 | 91 | def print_now(self, content): 92 | print(content) 93 | stdout.flush() 94 | 95 | """重置cookie有效期""" 96 | 97 | def refresh_cookie(self): 98 | headers = { 99 | 'Referer': 'https://v.qq.com', 100 | "Cookie": self.cookie, 101 | "User-Agent": self.ua 102 | } 103 | req = self.session.get(self.ref_url, headers=headers) 104 | if req.headers.get("Set-Cookie") == None: 105 | if self.pushplus_token != "": 106 | self.pushplus("腾讯视频碰蛋活动", "cookie过期或填写错误") 107 | if self.tgbot_token != "" and self.tg_userId != "": 108 | self.tgpush(f"腾讯视频碰蛋活动\ncookie过期或填写错误") 109 | self.print_now("cookie过期或者填写错误, 退出") 110 | exit(0) 111 | 112 | """碰了别人的则上报别人的次数+1 用于计数别人的蛋有没有碰完 暂时未使用 后续观察情况再说""" 113 | def egg_sharecode_success(self, sharecode): 114 | url = "https://api.ruirui.fun/txsp/egg_success" 115 | body = { 116 | "sharecode": sharecode 117 | } 118 | try: 119 | post(url, json=body) 120 | except: 121 | self.print_now("上报失败") 122 | 123 | def get_egg_sharecode(self): 124 | url = "https://api.ruirui.fun/txsp/get_egg_sharecode" 125 | try: 126 | data = get(url).json() 127 | if data.get("msg") == "success": 128 | self.print_now(f"获取到的助力码为{data['data']}") 129 | return data["data"] 130 | else: 131 | self.print_now("从获取助力码失败,最大可能是助力池为空, 会尝试将您的助力码提交到池中") 132 | return False 133 | except: 134 | self.print_now("获取助力码失败, 可能是api炸了, 也可能你的网络有问题") 135 | return False 136 | 137 | def post_sharecode(self): 138 | url = "https://api.ruirui.fun/txsp/post_egg_sharecode" 139 | body = { 140 | "sharecode": self.get_sharecode() 141 | } 142 | headers = { 143 | "Content-Type": "application/json" 144 | } 145 | try: 146 | data = post(url, headers=headers, json=body).json() 147 | if data.get("data") == "success": 148 | self.msg += "互助码提交成功" 149 | self.print_now("互助码提交成功") 150 | except: 151 | self.print_now("互助码提交失败,跳过提交,获取助力码") 152 | 153 | def get_level(self): 154 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=payvip&cmd=1&otype=json&getannual=1&geticon=1&getsvip=1&g_tk=610014353&_={self.timestamp()}&callback=Zepto{self.timestamp()}' 155 | headers = { 156 | "referer": "https://film.qq.com/x/autovue/grade/?ptag=user.h5", 157 | "host": "vip.video.qq.com", 158 | "accept-encoding": "gzip, deflate, br", 159 | "user-agent": self.ua} 160 | response = self.session.get(url=url, headers=headers) 161 | response.encoding = "utf-8" 162 | try: 163 | level = response.text.split('level')[1].split(',')[0].split(':')[1] 164 | return level 165 | except: 166 | self.print_now("获取等级信息失败, 最大可能是cookie过期或者格式不对, 也可能为网络原因") 167 | exit(0) 168 | 169 | def get_sharecode(self): 170 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?otype=xjson&name=spp_fulishe_eggs_collision&cmd=65391&actid=flspd_com&_st={self.timestamp()}' 171 | headers = { 172 | 'User-Agent': self.ua, 173 | 'Referer': 'https://film.qq.com/act/d2d-welfare/index.html?showMission=1&ptag=fuli.xrk&isDarkMode=0&uiType=MAX' 174 | } 175 | share_code = self.session.get(url, headers=headers).json()['data']['share_code'] 176 | return share_code 177 | 178 | def get_egg(self): 179 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?otype=xjson&name=fulishe_eggs_adapter&cmd=1&actid=flspd_com&_st={self.timestamp()}' 180 | headers = { 181 | 'User-Agent': self.ua, 182 | 'Referer': 'https://film.qq.com/act/d2d-welfare/index.html?showMission=1&ptag=fuli.xrk&isDarkMode=0&uiType=MAX' 183 | } 184 | self.session.get(url, headers=headers) 185 | 186 | def get_egg_count(self): 187 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?otype=xjson&name=spp_fulishe_eggs_index&cmd=2&actid=flspd_com&_st={self.timestamp()}' 188 | headers = { 189 | 'User-Agent': self.ua, 190 | 'Referer': 'https://film.qq.com/act/d2d-welfare/index.html?showMission=1&ptag=fuli.xrk&isDarkMode=0&uiType=MAX' 191 | } 192 | 193 | return self.session.get(url, headers=headers).json()['data']['egg_count'] 194 | 195 | def together(self, share_code): 196 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?otype=xjson&name=spp_fulishe_eggs_collision&cmd=65394&share_code={share_code}&_st={self.timestamp()}' 197 | headers = { 198 | 'User-Agent': self.ua, 199 | 'Referer': 'https://film.qq.com/act/d2d-welfare/index.html?showMission=1&ptag=fuli.xrk&isDarkMode=0&uiType=MAX' 200 | } 201 | data = self.session.get(url, headers=headers).json() 202 | if data['ret'] == -1019: 203 | self.print_now('您已经和他碰过了') 204 | return "" 205 | if data['ret'] == -1016: 206 | self.print_now('他已经没有蛋蛋了') 207 | return "" 208 | if data['ret'] == -1017: 209 | self.print_now('你已经没有蛋蛋了') 210 | return "" 211 | if data['ret'] == 0: 212 | try: 213 | own = data['data']['guest_lottery_info']['property_name'] 214 | guest = data['data']['master_lottery_info']['property_name'] 215 | result = f'你得到了{own}, 对方得到了{guest}' 216 | # self.egg_sharecode_success(share_code) 217 | self.print_now(result) 218 | self.msg += f'{result}\n' 219 | except: 220 | self.tgpush(data) 221 | 222 | def own(self): 223 | own_url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?otype=json&name=spp_fulishe_eggs_collision&cmd=65395&actid=flspd_com&_={self.timestamp()}&callback=Zepto{self.timestamp()}' 224 | headers = { 225 | 'User-Agent': self.ua, 226 | 'Referer': 'https://film.qq.com/act/d2d-welfare/index.html?showMission=1&ptag=fuli.xrk&isDarkMode=0&uiType=MAX' 227 | } 228 | html_data = self.session.get(own_url, headers=headers).text 229 | try: 230 | data = findall(r'"property_name":"(.*?)","property_result"', html_data)[0] 231 | self.msg += f'你得到了{data}' 232 | except: 233 | self.print_now("自己碰自己失败 可能为网络问题") 234 | 235 | def main(self): 236 | self.refresh_cookie() 237 | if int(self.get_level()) < 1: 238 | self.print_now("您当前账号不是腾讯视频会员, 无法参与") 239 | exit(0) 240 | if self.own_ex and localtime().tm_hour == 16: 241 | self.own() 242 | else: 243 | self.get_egg() 244 | sharecode_list = self.get_egg_sharecode() 245 | if sharecode_list != False: 246 | for sharecode in sharecode_list: 247 | if int(self.get_egg_count()) == 0: 248 | self.print_now("你已经没有蛋蛋了, 退出执行") 249 | self.msg = "你没有蛋蛋了" 250 | break 251 | self.together(sharecode) 252 | sleep(2) 253 | if int(self.get_egg_count()) > 0: 254 | self.post_sharecode() 255 | if self.msg == "互助码提交成功": 256 | self.msg += "\n本次执行没有碰到任何蛋,但是成功将互助码提交到了互助池,等待其它人碰即可" 257 | if self.msg == "": 258 | self.msg = "本次执行既没有碰到别人的蛋 也没能将您的助力码提交到池子 可能为池子服务器问题或者网络原因 请尝试重新提交" 259 | if self.pushplus_token != "": 260 | self.pushplus("腾讯视频碰蛋活动", self.msg) 261 | if self.tgbot_token != "" and self.tg_userId != "": 262 | self.tgpush(f"腾讯视频碰蛋活动\n{self.msg}") 263 | 264 | if __name__ == '__main__': 265 | Txspegg().main() 266 | -------------------------------------------------------------------------------- /backUp/txspjfdh.py: -------------------------------------------------------------------------------- 1 | # !!!!!此脚本应该已不可用,更新了 需要逆向解密参数 没什么收益 懒得更新了 需要更新的话提issue再说吧 2 | #腾讯视频积分兑换任务,9积分换10成长值,一周一次(别问为什么写,问就是写完之前不知道是一周一次) 3 | #ck用签到ck,获取方法其它腾讯视频签到库有,两个参数分别填在33 34行内,多账号格式['xxx', 'yyy', 'zzz'] 4 | #tg推送改15 16行参数 5 | from requests import get, post 6 | from random import choice 7 | from time import time 8 | from re import findall 9 | def get_ua(brower_name): 10 | url = 'https://raw.githubusercontent.com/limoruirui/misaka/master/user-agent.json' 11 | useragent = choice(get(url).json()[brower_name]) 12 | return useragent 13 | def timestamp(): 14 | return int(round(time()*1000)) 15 | def tgpush(content): 16 | bot_token = '' 17 | user_id = '' 18 | url = f"https://api.telegram.org/bot{bot_token}/sendMessage" 19 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 20 | data = {'chat_id': str(user_id), 'text': content, 'disable_web_page_preview': 'true'} 21 | try: 22 | req = post(url, headers=headers, data=data) 23 | except: 24 | print('推送失败') 25 | def get_headers(ck, ua, Referer): 26 | headers = { 27 | 'Cookie':ck, 28 | 'User-Agent':ua, 29 | 'Referer': Referer 30 | } 31 | return headers 32 | def login(): 33 | cookie_list = [] 34 | ref_url_list = [''] 35 | ck_list = [''] 36 | login_list = zip(ref_url_list, ck_list) 37 | for ref_url, ck in login_list: 38 | headers_resetck = { 39 | 'Referer': 'https://v.qq.com', 40 | "Cookie":ck, 41 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15" 42 | } 43 | faul_num = 3 44 | while faul_num > 0: 45 | try: 46 | req = get(ref_url,headers=headers_resetck) 47 | if req.status_code == 200: 48 | try: 49 | vqq_vusession = req.headers['Set-Cookie'].split('vqq_vusession=')[1].split(';')[0] 50 | except: 51 | faul_num -= 1 52 | continue 53 | cookie = ck.split('vqq_vusession=')[0] + f'vqq_vusession={vqq_vusession};' + ck.split('vqq_vusession=')[1].split(';', 1)[1] 54 | cookie_list.append(cookie) 55 | break 56 | except: 57 | continue 58 | #return cookie_list[int(argv[1])] 59 | return cookie_list 60 | def jfye(ck, ua): 61 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=get_cscore&type=1&_={timestamp()}&callback=Zepto{timestamp()}' 62 | headers = { 63 | 'Cookie':ck, 64 | 'User-Agent':ua, 65 | 'Referer': 'https://film.qq.com/x/credit_mall/route/creditDetail?ptag=hlw.vmallscore' 66 | } 67 | jfye = findall(r'"vip_score_total":(.*?),', get(url, headers=headers).text)[0] 68 | return jfye 69 | def get_9list(): 70 | for i in range(0, 3): 71 | url = 'https://film.qq.com/x/credit_mall/cgi/productListByModule?_param=%7B%22moduleId%22%3A%2220200710006728%22%2C%22page%22%3A1%2C%22page_size%22%3A15%7D' 72 | shop_data = get(url).json()['data'][i] 73 | if shop_data['uiRealCreditPrice'] <= 10: 74 | sProductId = shop_data['sProductId'] 75 | return sProductId 76 | else: 77 | continue 78 | tgpush('本次运行未发现积分低于10的物品') 79 | def get_billno(ck, ua): 80 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=welfare_donate&g_vstk=1376497764&g_actk=3899139375&aid=V0%24%242%3A5%2412%3Ahlw.vmallscore%243%3A8.4.90%2434%3A1%248%3A4101&welfare_id={get_9list()}&score=1&remark=&_={timestamp()}&callback=Zepto{timestamp()}' 81 | Referer = f'https://film.qq.com/x/credit_mall/route/productDetail?productId={get_9list()}&ptag=hlw.vmallscore' 82 | billno = findall(r'"bill_no":"(.*?)",', get(url, headers=get_headers(ck, ua, Referer)).text)[0] 83 | return billno 84 | def exchange(ck, ua): 85 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=scores_exchange&cmd=61232&source=101&bill_no={get_billno(ck, ua)}&productid={get_9list()}&price=9&aid=V0%24%242%3A5%244%3A0%2412%3Ahlw.vmallscore%248%3A999%243%3A8.4.60%241%3A0%2434%3A1%248%3A4002&_={timestamp()}&callback=Zepto{timestamp()}' 86 | Referer = f'https://film.qq.com/x/credit_mall/route/productDetail?productId={get_9list()}&ptag=hlw.vmallscore' 87 | get(url, headers=get_headers(ck, ua, Referer)) 88 | print(f'您当前拥有{jfye(ck, ua)}积分') 89 | def lingqu(ck, ua, account_numb): 90 | url = f'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_MissionFaHuo&cmd=4&task_id=8&_={timestamp()}&callback=Zepto{timestamp()}' 91 | Referer = 'https://v.qq.com' 92 | try: 93 | data = get(url, headers=get_headers(ck, ua, Referer)).text 94 | score = findall(r'"score":(.*?)}', data)[0] 95 | if score != 0: 96 | account_numb += 1 97 | except: 98 | print('周任务-积分兑换完成失败') 99 | return data 100 | def main(): 101 | ck_list = login() 102 | account_numb = 0 103 | for ck in ck_list: 104 | ua = get_ua('Safari') 105 | data = lingqu(ck, ua, account_numb) 106 | if '已发过货' in data: 107 | print('此账号本周已领取,请下周再来') 108 | account_numb += 1 109 | elif '"score":' in data: 110 | print('领取成功') 111 | else: 112 | exchange(ck, ua) 113 | lingqu(ck, ua, account_numb) 114 | tgpush(f'本次运行周任务-积分兑换成功完成{account_numb}个账号') 115 | if __name__ == '__main__': 116 | main() 117 | -------------------------------------------------------------------------------- /clean_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "=================== start clean qinglong logs ==========================" 3 | 4 | logs=$(find /var/log/nginx/*.log) 5 | 6 | for log in $logs; 7 | do 8 | echo "clean logs:" 9 | echo $log 10 | cat /dev/null> $log 11 | done 12 | 13 | echo "==================== end clean qinglong logs ==========================" 14 | -------------------------------------------------------------------------------- /iqiyi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 5/5/2022 20:09 6 | # ------------------------------- 7 | """ 8 | 1.爱奇艺每日任务脚本 请低调使用 请不要用于商业牟利 一天一次 请自行斟酌设置crontab 9 | 2.cookie获取方式 10 | 1.cookie可以用别人loon、qx等软件的mitm类自动获取再去boxjs里复制出来填写到环境变量或本脚本中 11 | 2.也可以自行抓包 电脑或者手机都可以 12 | 3.实在都不会 13 | 3.cookie食用方式: 可以只保留P00001=xxx;中xxx的值 也可以整段都要 青龙运行可新建并放入到环境变量 iqy_ck 中 也可以直接填写在本脚本中 14 | 4.关于dfp 15 | 1.dfp相当于爱奇艺的浏览器指纹 不需要登录也会有 有效期非常长 实测半年多前的还能用 其中领取每日任务的奖励和刷观影时长都需要使用到 16 | 2.dfp目前本脚本写死了一个 但是多用户使用同一个不知道有没有风险 17 | 3.建议有能力的自己抓包 在cookie里的__dfp字段 然后环境变量新增 iqiyi_dfp 填入 或者在本脚本内写死 18 | 4.不会自己抓的话 请打开设置环境变量 get_iqiyi_dfp 为 True 再执行脚本会获得并输出到面板 请复制后按上一条填入环境变量 获取完请删除get_iqiyi_dfp环境变量 小鸡经不起操 19 | 5.get请求 没携带任何东西出去 开源脚本 请不要说什么提交什么东西到我服务器 20 | 5.库中有每月自动领取爱奇艺会员天数红包的脚本 可配合使用(需有高等级的运行脚本提供红包 其它人才可以领取) 21 | """ 22 | cookie = "" 23 | iqiyi_dfp = "" 24 | from time import sleep, time 25 | from random import randint, choice 26 | from json import dumps 27 | from hashlib import md5 as md5Encode 28 | from string import digits, ascii_lowercase, ascii_uppercase 29 | from sys import exit, stdout 30 | from os import environ, system 31 | from re import findall 32 | 33 | try: 34 | from requests import Session, get, post 35 | from fake_useragent import UserAgent 36 | except: 37 | print( 38 | "你还没有安装requests库和fake_useragent库 正在尝试自动安装 请在安装结束后重新执行此脚本\n若还是提示本条消息 请自行运行pip3 install requests和pip3 install fake-useragent或者在青龙的依赖管理里安装python的requests和fake-useragent") 39 | system("pip3 install fake-useragent") 40 | system("pip3 install requests") 41 | print("安装完成 脚本退出 请重新执行") 42 | exit(0) 43 | iqy_ck = environ.get("iqy_ck") if environ.get("iqy_ck") else cookie 44 | get_iqiyi_dfp = environ.get("get_iqiyi_dfp") if environ.get("get_iqiyi_dfp") else False 45 | pushplus_token = environ.get("PUSH_PLUS_TOKEN") if environ.get("PUSH_PLUS_TOKEN") else "" 46 | tgbot_token = environ.get("TG_BOT_TOKEN") if environ.get("TG_BOT_TOKEN") else "" 47 | tg_userId = environ.get("TG_USER_ID") if environ.get("TG_USER_ID") else "" 48 | tg_push_api = environ.get("TG_API_HOST") if environ.get("TG_API_HOST") else "" 49 | if iqy_ck == "": 50 | print("未填写cookie 青龙可在环境变量设置 iqy_ck 或者在本脚本文件上方将获取到的cookie填入cookie中") 51 | exit(0) 52 | if "__dfp" in iqy_ck: 53 | iqiyi_dfp = findall(r"__dfp=(.*?)(;|$)", iqy_ck)[0][0] 54 | iqiyi_dfp = iqiyi_dfp.split("@")[0] 55 | if "P00001" in iqy_ck: 56 | iqy_ck = findall(r"P00001=(.*?)(;|$)", iqy_ck)[0][0] 57 | if iqiyi_dfp == "": 58 | iqiyi_dfp = environ.get("iqiyi_dfp") if environ.get( 59 | "iqiyi_dfp") else "a18af56a9b6a224272ab8ed00d1a587078cd5c8ab119b2a4a689d5a22f06bcbd8b" 60 | 61 | 62 | class Iqiyi: 63 | def __init__(self, ck, dfp): 64 | self.ck = ck 65 | self.session = Session() 66 | self.user_agent = UserAgent().chrome 67 | self.headers = { 68 | "User-Agent": self.user_agent, 69 | "Cookie": f"P00001={self.ck}", 70 | "Content-Type": "application/json" 71 | } 72 | self.dfp = dfp 73 | self.uid = "" 74 | self.msg = "" 75 | self.user_info = "" 76 | self.sleep_await = environ.get("sleep_await") if environ.get("sleep_await") else 1 77 | 78 | """工具""" 79 | 80 | def req(self, url, req_method="GET", body=None): 81 | data = {} 82 | if req_method.upper() == "GET": 83 | try: 84 | data = self.session.get(url, headers=self.headers, params=body).json() 85 | except: 86 | self.print_now("请求发送失败,可能为网络异常") 87 | # data = self.session.get(url, headers=self.headers, params=body).text 88 | return data 89 | elif req_method.upper() == "POST": 90 | try: 91 | data = self.session.post(url, headers=self.headers, data=dumps(body)).json() 92 | except: 93 | self.print_now("请求发送失败,可能为网络异常") 94 | # data = self.session.post(url, headers=self.headers, data=dumps(body)).text 95 | return data 96 | elif req_method.upper() == "OTHER": 97 | try: 98 | self.session.get(url, headers=self.headers, params=dumps(body)) 99 | except: 100 | self.print_now("请求发送失败,可能为网络异常") 101 | else: 102 | self.print_now("您当前使用的请求方式有误,请检查") 103 | 104 | def timestamp(self, short=False): 105 | if (short): 106 | return int(time()) 107 | return int(time() * 1000) 108 | 109 | def md5(self, str): 110 | m = md5Encode(str.encode(encoding='utf-8')) 111 | return m.hexdigest() 112 | 113 | def uuid(self, num, upper=False): 114 | str = '' 115 | if upper: 116 | for i in range(num): 117 | str += choice(digits + ascii_lowercase + ascii_uppercase) 118 | else: 119 | for i in range(num): 120 | str += choice(digits + ascii_lowercase) 121 | return str 122 | 123 | def pushplus(self, title, content): 124 | url = "http://www.pushplus.plus/send" 125 | headers = { 126 | "Content-Type": "application/json" 127 | } 128 | data = { 129 | "token": pushplus_token, 130 | "title": title, 131 | "content": content 132 | } 133 | try: 134 | post(url, headers=headers, data=dumps(data)) 135 | except: 136 | self.print_now('推送失败') 137 | 138 | def tgpush(self, content): 139 | url = f"https://api.telegram.org/bot{tgbot_token}/sendMessage" 140 | if tg_push_api != "": 141 | url = f"https://{tg_push_api}/bot{tgbot_token}/sendMessage" 142 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 143 | data = {'chat_id': str(tg_userId), 'text': content, 'disable_web_page_preview': 'true'} 144 | try: 145 | post(url, headers=headers, data=data, timeout=10) 146 | except: 147 | self.print_now('推送失败') 148 | 149 | def print_now(self, content): 150 | print(content) 151 | stdout.flush() 152 | 153 | def get_dfp_params(self): 154 | get_params_url = "https://api.lomoruirui.com/iqiyi/get_dfp" 155 | data = get(get_params_url).json() 156 | return data 157 | 158 | def get_dfp(self): 159 | body = self.get_dfp_params() 160 | url = "https://cook.iqiyi.com/security/dfp_pcw/sign" 161 | headers = { 162 | "Accept": "*/*", 163 | "Accept-Encoding": "gzip, deflate, br", 164 | "Accept-Language": "zh-CN,zh;q=0.9", 165 | "Cache-Control": "no-cache", 166 | "Connection": "keep-alive", 167 | "Content-Length": "1059", 168 | "Content-Type": "application/x-www-form-urlencoded", 169 | "Host": "cook.iqiyi.com", 170 | "Origin": "https://www.iqiyi.com", 171 | "Pragma": "no-cache", 172 | "Referer": "https://www.iqiyi.com/", 173 | "sec-ch-ua": f"\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"{body['data']['sv']}\", \"Google Chrome\";v=\"{body['data']['sv']}\"", 174 | "sec-ch-ua-mobile": "?0", 175 | "sec-ch-ua-platform": "Windows", 176 | "Sec-Fetch-Dest": "empty", 177 | "Sec-Fetch-Mode": "cors", 178 | "Sec-Fetch-Site": "same-site", 179 | "User-Agent": self.user_agent 180 | } 181 | data = post(url, headers=headers, data=body["data"]["body"]).json() 182 | self.dfp = data["result"]["dfp"] 183 | self.print_now(self.dfp) 184 | 185 | def get_userinfo(self): 186 | url = f"https://tc.vip.iqiyi.com/growthAgency/v2/growth-aggregation?messageId={self.qyid}&platform=97ae2982356f69d8&P00001={self.ck}&responseNodes=duration%2Cgrowth%2Cupgrade%2CviewTime%2CgrowthAnnualCard&_={self.timestamp()}" 187 | data = self.req(url) 188 | msg = data['data']['growth'] 189 | try: 190 | self.user_info = f"查询成功: 到期时间{msg['deadline']}\t当前等级为{msg['level']}\n\t今日获得成长值{msg['todayGrowthValue']}\t总成长值{msg['growthvalue']}\t距离下一等级还差{msg['distance']}成长值" 191 | self.print_now(self.user_info) 192 | except: 193 | self.user_info = f"查询失败,未获取到用户信息" 194 | 195 | """获取用户id""" 196 | 197 | def getUid(self): 198 | url = f'https://passport.iqiyi.com/apis/user/info.action?authcookie={self.ck}&fields=userinfo%2Cqiyi_vip&timeout=15000' 199 | data = self.req(url) 200 | if data.get("code") == 'A00000': 201 | self.uid = data['data']['userinfo']['pru'] 202 | else: 203 | self.print_now("请求api失败 最大可能是cookie失效了 也可能是网络问题") 204 | self.tgpush("爱奇艺每日任务: 请求api失败 最大可能是cookie失效了 也可能是网络问题") 205 | exit(0) 206 | 207 | def get_watch_time(self): 208 | url = "https://tc.vip.iqiyi.com/growthAgency/watch-film-duration" 209 | data = self.req(url) 210 | watch_time = data['data']['viewtime']['time'] 211 | return watch_time 212 | 213 | def get_sign(self): 214 | self.qyid = self.md5(self.uuid(16)) 215 | time_stamp = self.timestamp() 216 | if self.uid == "": 217 | self.print_now("获取用户id失败 可能为cookie设置错误或者网络异常,请重试或者检查cookie") 218 | exit(0) 219 | data = f'agentType=1|agentversion=1|appKey=basic_pcw|authCookie={self.ck}|qyid={self.qyid}|task_code=natural_month_sign|timestamp={time_stamp}|typeCode=point|userId={self.uid}|UKobMjDMsDoScuWOfp6F' 220 | url = f'https://community.iqiyi.com/openApi/task/execute?agentType=1&agentversion=1&appKey=basic_pcw&authCookie={self.ck}&qyid={self.qyid}&sign={self.md5(data)}&task_code=natural_month_sign×tamp={time_stamp}&typeCode=point&userId={self.uid}' 221 | return url 222 | 223 | def getUrl(self, Time, dfp): 224 | return f'https://msg.qy.net/b?u=f600a23f03c26507f5482e6828cfc6c5&pu={self.uid}&p1=1_10_101&v=5.2.66&ce={self.uuid(32)}&de=1616773143.1639632721.1639653680.29&c1=2&ve={self.uuid(32)}&ht=0&pt={randint(1000000000, 9999999999) / 1000000}&isdm=0&duby=0&ra=5&clt=&ps2=DIRECT&ps3=&ps4=&br=mozilla%2F5.0%20(windows%20nt%2010.0%3B%20win64%3B%20x64)%20applewebkit%2F537.36%20(khtml%2C%20like%20gecko)%20chrome%2F96.0.4664.110%20safari%2F537.36&mod=cn_s&purl=https%3A%2F%2Fwww.iqiyi.com%2Fv_1eldg8u3r08.html%3Fvfrm%3Dpcw_home%26vfrmblk%3D712211_cainizaizhui%26vfrmrst%3D712211_cainizaizhui_image1%26r_area%3Drec_you_like%26r_source%3D62%2540128%26bkt%3DMBA_PW_T3_53%26e%3Db3ec4e6c74812510c7719f7ecc8fbb0f%26stype%3D2&tmplt=2&ptid=01010031010000000000&os=window&nu=0&vfm=&coop=&ispre=0&videotp=0&drm=&plyrv=&rfr=https%3A%2F%2Fwww.iqiyi.com%2F&fatherid={randint(1000000000000000, 9999999999999999)}&stauto=1&algot=abr_v12-rl&vvfrom=&vfrmtp=1&pagev=playpage_adv_xb&engt=2&ldt=1&krv=1.1.85&wtmk=0&duration={randint(1000000, 9999999)}&bkt=&e=&stype=&r_area=&r_source=&s4={randint(100000, 999999)}_dianshiju_tbrb_image2&abtest=1707_B%2C1550_B&s3={randint(100000, 999999)}_dianshiju_tbrb&vbr={randint(100000, 999999)}&mft=0&ra1=2&wint=3&s2=pcw_home&bw=10&ntwk=18&dl={randint(10, 999)}.27999999999997&rn=0.{randint(1000000000000000, 9999999999999999)}&dfp={dfp}&stime={self.timestamp()}&r={randint(1000000000000000, 9999999999999999)}&hu=1&t=2&tm={Time}&_={self.timestamp()}' 225 | 226 | def sign(self): 227 | url = self.get_sign() 228 | body = { 229 | "natural_month_sign": { 230 | "taskCode": "iQIYI_mofhr", 231 | "agentType": 1, 232 | "agentversion": 1, 233 | "authCookie": self.ck, 234 | "qyid": self.qyid, 235 | "verticalCode": "iQIYI" 236 | } 237 | } 238 | data = self.req(url, "post", body) 239 | # print(data) 240 | if data.get('code') == 'A00000': 241 | self.print_now(f"签到执行成功, {data['data']['msg']}") 242 | else: 243 | self.print_now("签到失败,原因可能是签到接口又又又又改了") 244 | 245 | def dailyTask(self): 246 | taskcodeList = { 247 | 'b6e688905d4e7184': "浏览生活福利", 248 | 'a7f02e895ccbf416': "看看热b榜", 249 | '8ba31f70013989a8': "每日观影成就", 250 | "freeGetVip": "浏览会员兑换活动", 251 | "GetReward": "逛领福利频道"} 252 | for taskcode in taskcodeList: 253 | # 领任务 254 | url = f'https://tc.vip.iqiyi.com/taskCenter/task/joinTask?P00001={self.ck}&taskCode={taskcode}&platform=b6c13e26323c537d&lang=zh_CN&app_lm=cn' 255 | if self.req(url)['code'] == 'A00000': 256 | # print(f'领取{taskcodeList[taskcode]}任务成功') 257 | sleep(10) 258 | # 完成任务 259 | url = f'https://tc.vip.iqiyi.com/taskCenter/task/notify?taskCode={taskcode}&P00001={self.ck}&platform=97ae2982356f69d8&lang=cn&bizSource=component_browse_timing_tasks&_={self.timestamp()}' 260 | if self.req(url)['code'] == 'A00000': 261 | # print(f'完成{taskcodeList[taskcode]}任务成功') 262 | sleep(2) 263 | # 领取奖励 264 | # url = f'https://tc.vip.iqiyi.com/taskCenter/task/getTaskRewards?P00001={self.ck}&taskCode={taskcode}&dfp={self.dfp}&platform=b6c13e26323c537d&lang=zh_CN&app_lm=cn&deviceID={self.md5(self.uuid(8))}&token=&multiReward=1&fv=bed99b2cf5722bfe' 265 | url = f"https://tc.vip.iqiyi.com/taskCenter/task/getTaskRewards?P00001={self.ck}&taskCode={taskcode}&lang=zh_CN&platform=b2f2d9af351b8603" 266 | try: 267 | price = self.req(url)['dataNew'][0]["value"] 268 | self.print_now(f"领取{taskcodeList[taskcode]}任务奖励成功, 获得{price}点成长值") 269 | except: 270 | self.print_now(f"领取{taskcodeList[taskcode]}任务奖励可能出错了 也可能没出错 只是你今天跑了第二次") 271 | sleep(5) 272 | 273 | def lottery_draw(self, lottery=True): 274 | """ 275 | 查询剩余抽奖次数和抽奖 276 | True 抽 277 | False 查 278 | """ 279 | 280 | url = "https://iface2.iqiyi.com/aggregate/3.0/lottery_activity" 281 | lottery_params = { 282 | "app_k": "0", 283 | "app_v": "0", 284 | "platform_id": 10, 285 | "dev_os": "2.0.0", 286 | "dev_ua": "COL-AL10", 287 | "net_sts": 1, 288 | "qyid": self.qyid, 289 | "psp_uid": self.uid, 290 | "psp_cki": self.ck, 291 | "psp_status": 3, 292 | "secure_v": 1, 293 | "secure_p": "0", 294 | "req_sn": self.timestamp() 295 | } 296 | # get_change_params = deepcopy(lottery_params) 297 | # get_change_params["lottery_chance"] = 1 298 | # params = get_change_params 299 | # if lottery: 300 | # params = lottery_params 301 | params = lottery_params 302 | data = self.req(url, "get", params) 303 | # if lottery and data.get("code") == 0: 304 | if data.get("code") == 0: 305 | self.print_now(f'抽奖成功, 获得{data["awardName"]}') 306 | return data["daysurpluschance"] 307 | elif data.get("code") == 3: 308 | self.print_now(f"抽奖成功, 但是获得奖励信息错误, 大概率是没用的开通会员优惠券") 309 | return data["daysurpluschance"] 310 | else: 311 | return 0 312 | # elif not lottery and data.get("code") == 0: 313 | # return data["daysurpluschance"] 314 | 315 | def start(self): 316 | self.print_now("正在执行刷观影时长脚本 为减少风控 本过程运行时间较长 大概半个小时") 317 | totalTime = self.get_watch_time() 318 | if totalTime >= 7200: 319 | self.print_now(f"你的账号今日观影时长大于2小时 不执行刷观影时长") 320 | return 321 | for i in range(150): 322 | Time = randint(60, 120) 323 | url = self.getUrl(Time, self.dfp) 324 | self.req(url, 'other') 325 | totalTime += Time 326 | sleep(randint(20, 40)) 327 | if i % 20 == 3: 328 | self.print_now(f"现在已经刷到了{totalTime}秒, 数据同步有延迟, 仅供参考") 329 | if totalTime >= 7600: 330 | break 331 | 332 | def main(self): 333 | if get_iqiyi_dfp: 334 | self.get_dfp() 335 | self.getUid() 336 | self.get_sign() 337 | self.start() 338 | for i in range(10): 339 | change = self.lottery_draw() 340 | if int(change) == 0: 341 | break 342 | sleep(3) 343 | self.sign() 344 | self.dailyTask() 345 | self.print_now(f"任务已经执行完成, 因爱奇艺观影时间同步较慢,这里等待3分钟再查询今日成长值信息,若不需要等待直接查询,请设置环境变量名 sleep_await = 0 默认为等待") 346 | if int(self.sleep_await) == 1: 347 | sleep(180) 348 | self.get_userinfo() 349 | if pushplus_token != "": 350 | self.pushplus("爱奇艺每日任务签到", self.user_info) 351 | if tgbot_token != "" and tg_userId != "": 352 | self.tgpush(self.user_info) 353 | 354 | 355 | if __name__ == '__main__': 356 | iqiyi = Iqiyi(iqy_ck, iqiyi_dfp) 357 | iqiyi.main() 358 | -------------------------------------------------------------------------------- /iqiyiRed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 17/5/2022 19:26 6 | # ------------------------------- 7 | 8 | """ 9 | 1.爱奇艺每月领取会员天数红包脚本 请低调使用 请不要用于商业牟利 10 | 2.每个号每个月能领三个 会员等级大于等于5级可以发给别人领 请自行斟酌设置crontab 11 | 3.cookie获取方式 12 | 1.cookie可以用别人loon、qx等软件的mitm类自动获取再去boxjs里复制出来填写到环境变量或本脚本中 13 | 2.也可以自行抓包 电脑或者手机都可以, 已知电脑不顶号的情况下有效期为三个月 14 | 4.cookie食用方式: 可以只保留P00001=xxx;中xxx的值 也可以整段都要 青龙运行可新建并放入到环境变量 iqy_ck 中 也可以直接填写在本脚本中 15 | """ 16 | cookie = "" 17 | from time import sleep, time 18 | from random import choice 19 | from json import dumps 20 | from hashlib import md5 as md5Encode 21 | from string import digits, ascii_lowercase, ascii_uppercase 22 | from sys import exit, stdout 23 | from os import environ, system 24 | from re import findall 25 | 26 | try: 27 | from requests import Session, get, post 28 | from fake_useragent import UserAgent 29 | except: 30 | print( 31 | "你还没有安装requests库和fake_useragent库 正在尝试自动安装 请在安装结束后重新执行此脚本\n若还是提示本条消息 请自行运行pip3 install requests和pip3 install fake-useragent或者在青龙的依赖管理里安装python的requests和fake-useragent") 32 | system("pip3 install fake-useragent") 33 | system("pip3 install requests") 34 | print("安装完成 脚本退出 请重新执行") 35 | exit(0) 36 | iqy_ck = environ.get("iqy_ck") if environ.get("iqy_ck") else cookie 37 | pushplus_token = environ.get("PUSH_PLUS_TOKEN") if environ.get("PUSH_PLUS_TOKEN") else "" 38 | tgbot_token = environ.get("TG_BOT_TOKEN") if environ.get("TG_BOT_TOKEN") else "" 39 | tg_userId = environ.get("TG_USER_ID") if environ.get("TG_USER_ID") else "" 40 | tg_push_api = environ.get("TG_API_HOST") if environ.get("TG_API_HOST") else "" 41 | if iqy_ck == "": 42 | print("未填写cookie 青龙可在环境变量设置 iqy_ck 或者在本脚本文件上方将获取到的cookie填入cookie中") 43 | exit(0) 44 | if "P00001" in iqy_ck: 45 | iqy_ck = findall(r"P00001=(.*?)(;|$)", iqy_ck)[0][0] 46 | 47 | 48 | class Iqiyi: 49 | def __init__(self, ck): 50 | self.ck = ck 51 | self.session = Session() 52 | self.user_agent = UserAgent().chrome 53 | self.headers = { 54 | "User-Agent": self.user_agent, 55 | "Cookie": f"P00001={self.ck}", 56 | "Content-Type": "application/json" 57 | } 58 | self.msg = "" 59 | self.redNo = "" 60 | self.last_num = 0 61 | 62 | """工具""" 63 | 64 | def req(self, url, req_method="GET", body=None): 65 | data = {} 66 | if req_method.upper() == "GET": 67 | try: 68 | data = self.session.get(url, headers=self.headers, params=body).json() 69 | except: 70 | self.print_now("请求发送失败,可能为网络异常") 71 | # data = self.session.get(url, headers=self.headers, params=body).text 72 | return data 73 | elif req_method.upper() == "POST": 74 | try: 75 | data = self.session.post(url, headers=self.headers, data=dumps(body)).json() 76 | except: 77 | self.print_now("请求发送失败,可能为网络异常") 78 | # data = self.session.post(url, headers=self.headers, data=dumps(body)).text 79 | return data 80 | elif req_method.upper() == "OTHER": 81 | try: 82 | self.session.get(url, headers=self.headers, params=dumps(body)) 83 | except: 84 | self.print_now("请求发送失败,可能为网络异常") 85 | else: 86 | self.print_now("您当前使用的请求方式有误,请检查") 87 | 88 | def timestamp(self, short=False): 89 | if (short): 90 | return int(time()) 91 | return int(time() * 1000) 92 | 93 | def md5(self, str): 94 | m = md5Encode(str.encode(encoding='utf-8')) 95 | return m.hexdigest() 96 | 97 | def uuid(self, num, upper=False): 98 | str = '' 99 | if upper: 100 | for i in range(num): 101 | str += choice(digits + ascii_lowercase + ascii_uppercase) 102 | else: 103 | for i in range(num): 104 | str += choice(digits + ascii_lowercase) 105 | return str 106 | 107 | def pushplus(self, title, content): 108 | url = "http://www.pushplus.plus/send" 109 | headers = { 110 | "Content-Type": "application/json" 111 | } 112 | data = { 113 | "token": pushplus_token, 114 | "title": title, 115 | "content": content 116 | } 117 | try: 118 | post(url, headers=headers, data=dumps(data)) 119 | except: 120 | self.print_now('推送失败') 121 | 122 | def tgpush(self, content): 123 | url = f"https://api.telegram.org/bot{tgbot_token}/sendMessage" 124 | if tg_push_api != "": 125 | url = f"https://{tg_push_api}/bot{tgbot_token}/sendMessage" 126 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 127 | data = {'chat_id': str(tg_userId), 'text': content, 'disable_web_page_preview': 'true'} 128 | try: 129 | post(url, headers=headers, data=data, timeout=10) 130 | except: 131 | self.print_now('推送失败') 132 | 133 | def push(self, msg): 134 | if pushplus_token != "": 135 | self.pushplus("爱奇艺每月领取会员", msg) 136 | if tgbot_token != "" and tg_userId != "": 137 | self.tgpush(f"爱奇艺每月领取会员\n{msg}") 138 | 139 | def print_now(self, content): 140 | print(content) 141 | stdout.flush() 142 | 143 | """获取用户会员等级""" 144 | 145 | def get_level(self): 146 | url = f'https://passport.iqiyi.com/apis/user/info.action?authcookie={self.ck}&fields=userinfo%2Cqiyi_vip&timeout=15000' 147 | data = self.req(url) 148 | if data.get("code") == 'A00000': 149 | self.level = data['data']['qiyi_vip_info']['level'] 150 | else: 151 | self.print_now("获取用户等级信息失败 最大可能是cookie失效了 也可能是网络问题") 152 | exit(0) 153 | 154 | def genRedNo(self): 155 | url = f"https://act.vip.iqiyi.com/level-right/red/gen?fv=b75a9b2a7d208020&P00001={self.ck}" 156 | data = self.req(url) 157 | code = data.get("code") 158 | if code == "A00000": 159 | self.redNo = data["data"]["redNo"] 160 | elif code == "B000205": 161 | self.print_now("当前账号本月已领取等级红包 直接查询") 162 | self.query_redNo() 163 | 164 | def query_redNo(self): 165 | url = f"https://act.vip.iqiyi.com/level-right/red/status?fv=b75a9b2a7d208020&P00001={self.ck}" 166 | data = self.req(url) 167 | code = data.get("code") 168 | if code == "A00000": 169 | self.redNo = data["data"][0]["redNo"] 170 | 171 | def last_redNo(self, redNo): 172 | url = f"https://act.vip.iqiyi.com/bonus/query/queryRed?redNo={redNo}" 173 | data = self.req(url) 174 | if data.get("code") == "A00000": 175 | last_num = data["data"]["totalNum"] - data["data"]["receivedNum"] 176 | return last_num 177 | else: 178 | return 0 179 | 180 | def post_redNo(self): 181 | url = "https://api.limoruirui.com/iqiyi/postRedNo" 182 | body = { 183 | "RedNo": self.redNo, 184 | "last_num": self.last_num 185 | } 186 | req = post(url, json=body) 187 | if req.status_code == 200: 188 | data = req.json() 189 | if data.get("data") == "success": 190 | self.print_now("已将您的红包码提交到助力池") 191 | self.msg += "已将您的红包码提交到助力池" 192 | else: 193 | self.print_now(data["data"]) 194 | else: 195 | self.print_now("提交失败, 可能为池子服务器炸了, 请截图运行时间和日志反馈") 196 | 197 | def get_redNo(self): 198 | url = "https://api.limoruirui.com/iqiyi/getRedNo" 199 | req = get(url) 200 | if req.status_code == 200: 201 | data = req.json() 202 | if data["msg"] == "success": 203 | redNo_list = data["data"] 204 | else: 205 | self.print_now("当前池子红包码为空") 206 | redNo_list = [] 207 | return redNo_list 208 | else: 209 | self.print_now("从池子获取红包码失败, 可能为池子服务器炸了, 请携带日志反馈") 210 | exit(0) 211 | 212 | def receive(self, redNo): 213 | url = f"https://act.vip.iqiyi.com/bonus/api/grabRed?accountType=2&P00001={self.ck}&redNo={redNo}" 214 | data = self.req(url) 215 | code = data.get("code") 216 | if code == "A00000": 217 | receiveDay = data["data"]["receiveDays"] 218 | self.print_now(f"领取成功, 获得{receiveDay}天会员") 219 | self.msg += f"领取成功, 获得{receiveDay}天会员\n" 220 | return False 221 | else: 222 | self.print_now(f"领取失败 原因是{data['msg']}") 223 | if "上限" in data["msg"]: 224 | return True 225 | 226 | def main(self): 227 | self.get_level() 228 | if int(self.level) >= 5: 229 | self.genRedNo() 230 | self.last_num = self.last_redNo(self.redNo) 231 | if self.last_num > 0: 232 | self.print_now(f"您的红包码为{self.redNo}, 正在尝试提交") 233 | self.post_redNo() 234 | else: 235 | self.print_now(f"您本月的会员红包已被领完, 不提交") 236 | redNo_list = self.get_redNo() 237 | if len(self.redNo) == 28 and len(redNo_list) > 6: 238 | redNo_list.insert(0, self.redNo) 239 | self.print_now(f"本次获取到的红包码为\n{redNo_list}") 240 | for redNo in redNo_list: 241 | if redNo == "": 242 | continue 243 | status = self.receive(redNo) 244 | if status: 245 | break 246 | sleep(2) 247 | if self.msg == "": 248 | self.msg = "本次运行啥都没有得到" 249 | self.push(self.msg) 250 | 251 | 252 | if __name__ == '__main__': 253 | iqiyi = Iqiyi(iqy_ck) 254 | iqiyi.main() 255 | -------------------------------------------------------------------------------- /login/telecom_login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/10/24 17:52 6 | # ------------------------------- 7 | """ 8 | 营业厅登录获取token loginAuthCipherAsymmertric参数解密参考自 github@QGCliveDavis https://github.com/QGCliveDavis 感谢大佬 9 | """ 10 | from requests import post 11 | from datetime import datetime 12 | from xml.etree.ElementTree import XML 13 | from uuid import uuid4 14 | from sys import path 15 | if "telecom_login" in __file__: 16 | path.append("../tools") 17 | from rsa_encrypt import RSA_Encrypt 18 | from encrypt_symmetric import Crypt 19 | from tool import print_now 20 | else: 21 | from tools.rsa_encrypt import RSA_Encrypt 22 | from tools.tool import print_now 23 | class TelecomLogin: 24 | def __init__(self, account, pwd): 25 | self.account = account 26 | self.pwd = pwd 27 | self.deviceUid = uuid4().hex 28 | def login(self): 29 | url = "https://appgologin.189.cn:9031/login/client/userLoginNormal" 30 | timestamp = datetime.now().__format__("%Y%m%d%H%M%S") 31 | key = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBkLT15ThVgz6/NOl6s8GNPofd\nWzWbCkWnkaAm7O2LjkM1H7dMvzkiqdxU02jamGRHLX/ZNMCXHnPcW/sDhiFCBN18\nqFvy8g6VYb9QtroI09e176s+ZCtiv7hbin2cCTj99iUpnEloZm19lwHyo69u5UMi\nPMpq0/XKBO8lYhN/gwIDAQAB\n-----END PUBLIC KEY-----" 32 | body = { 33 | "headerInfos": { 34 | "code": "userLoginNormal", 35 | "timestamp": timestamp, 36 | "broadAccount": "", 37 | "broadToken": "", 38 | "clientType": "#9.6.1#channel50#iPhone 14 Pro Max#", 39 | "shopId": "20002", 40 | "source": "110003", 41 | "sourcePassword": "Sid98s", 42 | "token": "", 43 | "userLoginName": self.account 44 | }, 45 | "content": { 46 | "attach": "test", 47 | "fieldData": { 48 | "loginType": "4", 49 | "accountType": "", 50 | "loginAuthCipherAsymmertric": RSA_Encrypt(key).encrypt(f"iPhone 14 15.4.{self.deviceUid[:12]}{self.account}{timestamp}{self.pwd}0$$$0.", b64=True), 51 | "deviceUid": self.deviceUid[:16], 52 | "phoneNum": self.get_phoneNum(self.account), 53 | "isChinatelecom": "0", 54 | "systemVersion": "15.4.0", 55 | "authentication": self.pwd 56 | } 57 | } 58 | } 59 | headers = { 60 | "user-agent": "iPhone 14 Pro Max/9.6.1", 61 | 62 | } 63 | 64 | data = post(url, headers=headers, json=body).json() 65 | code = data["responseData"]["resultCode"] 66 | if code != "0000": 67 | print_now("账号【"+self.account+"】,登陆失败,可能密码错误, 接口日志" + str(data)) 68 | return None 69 | self.token = data["responseData"]["data"]["loginSuccessResult"]["token"] 70 | self.userId = data["responseData"]["data"]["loginSuccessResult"]["userId"] 71 | return True 72 | 73 | def get_ticket(self): 74 | url = "https://appgologin.189.cn:9031/map/clientXML" 75 | body = f"\n\n getSingle\n {datetime.now().__format__('%Y%m%d%H%M%S')}\n \n \n #9.6.1#channel50#iPhone 14 Pro Max#\n 20002\n 110003\n Sid98s\n {self.token}\n {self.account}\n \n \n test\n \n {self.encrypt_userid(self.userId)}\n 4a6862274835b451\n \n \n" 76 | headers = { 77 | "User-Agent": "samsung SM-G9750/9.4.0", 78 | "Content-Type": "text/xml; charset=utf-8", 79 | "Content-Length": "694", 80 | "Host": "appgologin.189.cn:9031", 81 | "Connection": "Keep-Alive", 82 | "Accept-Encoding": "gzip", 83 | "Pragma": "no-cache", 84 | "Cache-Control": "no-cache" 85 | } 86 | xml_data = post(url, headers=headers, data=body).text 87 | doc = XML(xml_data) 88 | secret_ticket = doc.find("ResponseData/Data/Ticket").text 89 | # print("secret: " + secret_ticket) 90 | ticket = self.decrypt_ticket(secret_ticket) 91 | # print("ticket: " + ticket) 92 | return ticket, self.token 93 | def main(self): 94 | if self.login() is None: 95 | return "", "" 96 | userLoginInfo = self.get_ticket() 97 | return userLoginInfo 98 | @staticmethod 99 | def get_phoneNum(phone): 100 | result = "" 101 | for i in phone: 102 | result += chr(ord(i) + 2) 103 | return result 104 | @staticmethod 105 | def decrypt_ticket(secret_ticket): 106 | key = "1234567`90koiuyhgtfrdewsaqaqsqde" 107 | iv = "\0\0\0\0\0\0\0\0" 108 | # ticket = des3_cbc_decrypt(key, bytes(TelecomLogin.process_text(secret_ticket)), iv) 109 | ticket = Crypt("des3", key, iv, "CBC").decrypt(TelecomLogin.process_text(secret_ticket)) 110 | return ticket 111 | @staticmethod 112 | def encrypt_userid(userid): 113 | key = "1234567`90koiuyhgtfrdewsaqaqsqde" 114 | iv = bytes([0] * 8) 115 | targetId = Crypt("des3", key, iv, "CBC").encrypt(userid) 116 | return targetId 117 | 118 | @staticmethod 119 | def process_text(text): 120 | length = len(text) >> 1 121 | bArr = [0] * length 122 | if len(text) % 2 == 0: 123 | i2 = 0 124 | i3 = 0 125 | while i2 < length: 126 | i4 = i3 + 1 127 | indexOf = "0123456789abcdef0123456789ABCDEF".find(text[i3]) 128 | if indexOf != -1: 129 | bArr[i2] = (((indexOf & 15) << 4) + ("0123456789abcdef0123456789ABCDEF".find(text[i4]) & 15)) 130 | i2 += 1 131 | i3 = i4 + 1 132 | else: 133 | print("转化失败 大概率是明文输入错误") 134 | return bArr 135 | -------------------------------------------------------------------------------- /login/unicom_login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2023/2/2 19:00 6 | # cron "" script-path=xxx.py,tag=匹配cron用 7 | # const $ = new Env('某通app短信登录'); 8 | # ------------------------------- 9 | """ 10 | 某通短信登录获取online_token 抄自 小一佬 github@https://github.com/xream 感谢 11 | 1. 此登录脚本只提供另一种方案 建议还是自己抓包 不会有顶号导致无效的问题 12 | 2. 因青龙面板无法进行控制台交互 故设置了两种运行方式 13 | i.面板内新建任务 直接运行按提示增加环境变量即可 14 | ii.docker容器内运行 进入login文件夹内 输入命令 (python3 unicom_login.py 114514)(不要带着括号) 按提示输入对应的东西回车即可 15 | 3. 第一次运行会登录获取appid(此过程顶号) CHINA_UNICOM_APPID 有合法的appid时 则执行登录获取online_token(此过程不会顶号) 16 | """ 17 | from requests import post 18 | from urllib.parse import quote 19 | from time import sleep 20 | from datetime import datetime 21 | from uuid import uuid4 22 | from sys import path, argv 23 | path.append("../tools") 24 | from tool import print_now, get_environ 25 | from rsa_encrypt import RSA_Encrypt 26 | class UnicomLogin: 27 | rsa_key = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDc+CZK9bBA9IU+gZUOc6FUGu7y\nO9WpTNB0PzmgFBh96Mg1WrovD1oqZ+eIF4LjvxKXGOdI79JRdve9NPhQo07+uqGQ\ngE4imwNnRx7PFtCRryiIEcUoavuNtuRVoBAm6qdB0SrctgaqGfLgKvZHOnwTjyNq\njBUxzMeQlEC2czEMSwIDAQAB\n-----END PUBLIC KEY-----" 28 | def __init__(self, account, run_mode): 29 | self.account = account 30 | interim_appid = str(get_environ("CHINA_UNICOM_APPID", output=False)).rstrip("\n") 31 | self.appid = "ChinaunicomMobileBusiness" if len(interim_appid) != 160 else interim_appid 32 | self.run_data = "token" 33 | if self.appid == "ChinaunicomMobileBusiness": 34 | print_now("检测到未填写正确的appid到环境变量 CHINA_UNICOM_APPID 中 当前执行获取appid") 35 | self.run_data = "appid" 36 | self.deviceId = uuid4().hex 37 | self.run_mode = run_mode 38 | def send_sms_code(self): 39 | url = "https://m.client.10010.com/mobileService/sendRadomNum.htm" 40 | body = f"mobile={quote(RSA_Encrypt(UnicomLogin.rsa_key).encrypt(self.account, b64=True))}&version=android@10.0100" 41 | headers = { 42 | "user-agent": "Dalvik/2.1.0 (Linux; U; Android 13; SM-S908U Build/TP1A.220624.014);unicom{version:android@10.0100}", 43 | "content-type": "application/x-www-form-urlencoded" 44 | } 45 | data = post(url, headers=headers, data=body).json() 46 | if data["rsp_code"] == "0000": 47 | print("发送短信验证码成功") 48 | if self.run_mode == "hand": 49 | self.login(input("请输入短信验证码(输入完成后按回车键结束): ")) 50 | return 51 | print_now("请5分钟内新建环境变量 UNICOM_SMS 值为收到的四位数短信验证码 然后再次运行") 52 | 53 | def login(self, captcha): 54 | url = "https://m.client.10010.com/mobileService/radomLogin.htm" 55 | body = f"deviceOS=android13&mobile={quote(RSA_Encrypt(UnicomLogin.rsa_key).encrypt(self.account, b64=True))}&netWay=Wifi&version=android%4010.0100&deviceId={self.deviceId}&password={quote(RSA_Encrypt(UnicomLogin.rsa_key).encrypt(captcha, b64=True))}&keyVersion=&provinceChanel=general&appId={self.appid}&deviceModel=V1936A&androidId={uuid4().hex[8:24]}&deviceBrand=×tamp={datetime.today().__format__('%Y%m%d%H%M%S')}" 56 | if self.run_data == "appid": 57 | body += f"&deviceCode={self.deviceId}" 58 | headers = { 59 | "user-agent": "Dalvik/2.1.0 (Linux; U; Android 13; SM-S908U Build/TP1A.220624.014);unicom{version:android@10.0100}", 60 | "content-type": "application/x-www-form-urlencoded" 61 | } 62 | data = post(url, headers=headers, data=body).json() 63 | # print(data) 64 | if "token_online" in data: 65 | print("登录获取数据成功") 66 | if self.run_data == "appid": 67 | print( 68 | f"请设置环境变量 CHINA_UNICOM_APPID 为 {data['appId']} 然后到app正常登录 再执行一次本脚本获取token") 69 | else: 70 | print(f"请设置环境变量 UNICOM_GAME_ACCOUNT_INFO 为 {self.account}#{self.appid}#{data['token_online']}") 71 | def main(self): 72 | if self.run_mode == "ql": 73 | print_now("如果不是刚刚获取已经运行获取验证码 请先将 UNICOM_SMS 删除或者清空") 74 | captcha = get_environ("UNICOM_SMS", output=False) 75 | if len(captcha) < 4: 76 | self.send_sms_code() 77 | else: 78 | self.login(captcha) 79 | else: 80 | self.send_sms_code() 81 | if __name__ == '__main__': 82 | run_mode = "ql" if len(argv) == 1 else "hand" 83 | if run_mode == "ql": 84 | account = get_environ("LOGIN_UNICOM_PHONE") 85 | else: 86 | account = input("请输入手机号(按回车键结束输入): ") 87 | if account == "": 88 | exit(0) 89 | UnicomLogin(account, run_mode).main() 90 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuanter/misaka/ec8bfa12f90bfb14091faaf983741fb18bc7ae16/logs/.gitkeep -------------------------------------------------------------------------------- /mt_wxpusher.js: -------------------------------------------------------------------------------- 1 | /* 2 | cron: 2 10-12,15-18 * * * 3 | const $ = new Env('美团优惠券查询'); 4 | */ 5 | 6 | 7 | /*========================修改数据区域===========================*/ 8 | 9 | //你wxpusher的token,如AT_ZzQKKQF9xxx 10 | const appToken = "填你wxpusher的token"; 11 | //你wxpusher的topicIds,如['11540'] 12 | const topicIds = []; 13 | //你wxpusher的uids,如["UID_XXX"] 14 | const uids = []; 15 | //需要筛选的青龙环境数据类型 16 | const cookieName = ["MT25_12","MT25_12_ONE","MT25_12_TWO","MT30_15","MT30_15_ONE","MT30_15_TWO","cookie1"]; 17 | //你需要筛选的优惠券金额关键字 18 | const keywords = ['30', '40', '16', '18', '15','12', '13', '25','26']; 19 | 20 | 21 | /*==============================================================*/ 22 | 23 | 24 | 25 | 26 | const $ = new Env('美团优惠券查询') 27 | const axios = require('axios'); 28 | const cheerio = require('cheerio'); 29 | 30 | const couponKeywords = ['神券']; 31 | const matchedCoupons = []; 32 | let cookies = []; 33 | const baseUrl = "https://i.meituan.com/account/magiccard"; 34 | 35 | !(async () => { 36 | //导入环境文件 37 | try { 38 | require.resolve("./ql_api"); 39 | const { 40 | getEnvs 41 | } = require('./ql_api'); 42 | // 存在 43 | // 读取环境变量,动态添加cookies 44 | for(let i = 0; i < cookieName.length; i++){ 45 | let envName = cookieName[i]; 46 | // console.log(envName); 47 | const envs = await getEnvs(envName) 48 | // console.log(envs); 49 | await Envs(envName,envs); 50 | } 51 | } catch(e) { 52 | // 不存在 53 | const { 54 | getEnvs 55 | } = require('./tools/ql_api'); 56 | // 读取环境变量,动态添加cookies 57 | for(let i = 0; i < cookieName.length; i++){ 58 | let envName = cookieName[i]; 59 | const envs = await getEnvs(envName) 60 | // console.log(envs); 61 | await Envs(envName,envs); 62 | } 63 | 64 | } 65 | 66 | //判断数组是否重复 67 | cookies = getRepeatNum(cookies); 68 | // console.log(data); 69 | 70 | await scrapeCoupons(); 71 | })().catch((e) => log(e)).finally(() => $.done()) 72 | 73 | 74 | async function scrapeCoupons() { 75 | const today = new Date(); 76 | const year = today.getFullYear(); 77 | const month = String(today.getMonth() + 1).padStart(2, '0'); 78 | const day = String(today.getDate()).padStart(2, '0'); 79 | const dateString = `${year}-${month}-${day}`; 80 | 81 | // cookie.status == 0代表青龙启用这个CK 82 | const enabledCookies = cookies.filter(cookie => cookie.status == 0); 83 | // console.log(enabledCookies); 84 | const promises = enabledCookies.map(async cookie => { 85 | // console.log(cookie); 86 | const headers = { 87 | Cookie: cookie.value 88 | }; 89 | const url = baseUrl; 90 | try { 91 | const response = await axios.get(url, { headers }); 92 | const html = response.data; 93 | const $ = cheerio.load(html); 94 | $('.moneycard').each((i, el) => { 95 | const moneycardValue = $(el).find('.moneycard-value').text().trim(); 96 | const moneycardDes = $(el).find('.moneycard-des').text().trim(); 97 | const moneycardDesc = $(el).find('.moneycard-desc h6').text().trim(); 98 | const moneycardStatus = $(el).find('.moneycard-status span').text().trim(); 99 | 100 | if (moneycardStatus.includes('已过期')) { 101 | return; 102 | } 103 | 104 | const expirationDate = moneycardStatus.match(/\d{4}-\d{2}-\d{2}/)[0]; 105 | if (moneycardStatus.includes('已使用')) { 106 | if (expirationDate !== dateString) { 107 | return; 108 | } 109 | } 110 | 111 | for (const keyword of keywords) { 112 | if (moneycardValue.includes(keyword)) { 113 | for (const couponKeyword of couponKeywords) { 114 | if (moneycardDesc.includes(couponKeyword)) { 115 | let couponDescription = moneycardDes.split('。')[0] + '。'; 116 | let total = couponDescription.replace(/[^\d.]/g, ""); 117 | let available = moneycardValue.replace(/[^\d.]/g, ""); 118 | let couponCondition = total+"-"+available; 119 | const couponInfo = { 120 | cookieName: cookie.remarks, 121 | couponName: moneycardDesc, 122 | couponCondition:couponCondition, 123 | couponValue: moneycardValue, 124 | couponDescription: couponDescription, 125 | couponStatus: moneycardStatus 126 | }; 127 | 128 | // 判断是否当天使用过的或未使用的优惠券 129 | const expirationDate = moneycardStatus.match(/\d{4}-\d{2}-\d{2}/)[0]; 130 | const isToday = expirationDate === dateString; 131 | const isUsed = moneycardStatus.includes('已使用'); 132 | 133 | if (isToday || !isUsed) { 134 | matchedCoupons.push(couponInfo); 135 | } 136 | 137 | break; 138 | } 139 | } 140 | break; 141 | } 142 | } 143 | }); 144 | } catch (error) { 145 | console.error(error); 146 | } 147 | }); 148 | 149 | await Promise.all(promises); 150 | 151 | console.log(matchedCoupons); 152 | 153 | await sendCouponsToWeChat(); 154 | } 155 | 156 | async function sendCouponsToWeChat() { 157 | const formattedCoupons = matchedCoupons.map(coupon => { 158 | return `

账号: ${coupon.cookieName}
优惠券名称: ${coupon.couponName}
优惠券条件: ${coupon.couponCondition}
优惠券金额: ${coupon.couponValue}
优惠券描述: ${coupon.couponDescription}
优惠券状态: ${coupon.couponStatus}
`; 159 | }); 160 | 161 | const headers = { 162 | "Content-Type": "application/json" 163 | }; 164 | 165 | const body = { 166 | "appToken": appToken, 167 | "content": JSON.stringify(formattedCoupons).replace(/\["/g, '').replace(/\","/g, '').replace(/\"]/g, ''), 168 | "summary": "美团红包列表推送", 169 | "contentType": 2, 170 | "topicIds": topicIds, 171 | "uids": uids, 172 | "url": "https://wxpusher.zjiecode.com", 173 | "verifyPay": false 174 | }; 175 | 176 | try { 177 | const response = await axios.post("https://wxpusher.zjiecode.com/api/send/message", body, { headers }); 178 | console.log(response.data); 179 | } catch (error) { 180 | console.error(error); 181 | } 182 | } 183 | 184 | // 读取环境变量,动态添加cookies 185 | // Object.keys(process.env).forEach(key => { 186 | // console.log(key); 187 | // if (key.startsWith('MT25') || key.startsWith('MT30') || key == "COOKIE_DICT") { 188 | 189 | // cookies.push({ name: key, value: process.env[key], enabled: 1 }); 190 | // } 191 | // }); 192 | 193 | function getRepeatNum(arr){ //计算重复值 194 | if (!Array.isArray(arr)) { 195 | console.log('type error!') 196 | return 197 | } 198 | var array = []; 199 | var temp = [] 200 | for (var i = 0; i < arr.length; i++) { 201 | if (temp.indexOf(arr[i].remarks) === -1) { 202 | temp.push(arr[i].remarks); 203 | array.push(arr[i]) 204 | } 205 | } 206 | return array; 207 | } 208 | 209 | //脚本环境变量获取 210 | async function Envs(name,ckList) { 211 | if (ckList) { 212 | // 213 | try { 214 | ckList.forEach(key =>{ 215 | if(key.name !== name){ 216 | // 跳出循环 217 | // throw Error() 218 | //跳过当前循环 219 | return 220 | } 221 | // console.log(key) 222 | let value = key.value; 223 | if (value.indexOf("@") != -1) { 224 | value.split("@").forEach((item) => { 225 | let temp = key; 226 | temp["value"] = item 227 | cookies.push(temp); 228 | }); 229 | } else if (value.indexOf("\n") != -1) { 230 | value.split("\n").forEach((item) => { 231 | let temp = key; 232 | temp["value"] = item 233 | cookies.push(temp); 234 | }); 235 | } else if (value.indexOf("&") != -1) { 236 | value.split("&").forEach((item) => { 237 | let temp = key; 238 | temp["value"] = item 239 | cookies.push(temp); 240 | }); 241 | } else { 242 | cookies.push(key); 243 | } 244 | }) 245 | } catch(error) { 246 | // 跳出循环后要做的操作 247 | 248 | } 249 | } else { 250 | log(`\n 【${$.name}】:未填写变量 ${ckList}`) 251 | return; 252 | } 253 | 254 | 255 | return true; 256 | } 257 | 258 | 259 | // prettier-ignore 260 | function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,o)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box2000.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let o=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");o=o?1*o:20,o=e&&e.timeout?e.timeout:o;const[r,a]=i.split("@"),h={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:o},headers:{"X-Key":r,Accept:"*/*"}};this.post(h,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),o=JSON.stringify(this.data);s?this.fs.writeFileSync(t,o):i?this.fs.writeFileSync(e,o):this.fs.writeFileSync(t,o)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let o=t;for(const t of i)if(o=Object(o)[t],void 0===o)return s;return o}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),o=s?this.getval(s):"";if(o)try{const t=JSON.parse(o);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,o]=/^@(.*?)\.(.*?)$/.exec(e),r=this.getval(i),a=i?"null"===r?null:r||"{}":"{}";try{const e=JSON.parse(a);this.lodash_set(e,o,t),s=this.setval(JSON.stringify(e),i)}catch(e){const r={};this.lodash_set(r,o,t),s=this.setval(JSON.stringify(r),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){if(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:o,body:r}=t;e(null,{status:s,statusCode:i,headers:o,body:r},r)},t=>e(t));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:o,headers:r,rawBody:a}=t,h=s.decode(a,this.encoding);e(null,{status:i,statusCode:o,headers:r,rawBody:a,body:h},h)},t=>{const{message:i,response:o}=t;e(i,o,o&&s.decode(o.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:o,body:r}=t;e(null,{status:s,statusCode:i,headers:o,body:r},r)},t=>e(t));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:o,...r}=t;this.got[s](o,r).then(t=>{const{statusCode:s,statusCode:o,headers:r,rawBody:a}=t,h=i.decode(a,this.encoding);e(null,{status:s,statusCode:o,headers:r,rawBody:a,body:h},h)},t=>{const{message:s,response:o}=t;e(s,o,o&&i.decode(o.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",o){const r=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,r(o)):this.isQuanX()&&$notify(e,s,i,r(o))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)} 261 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | pycryptodome 3 | PyExecJS==1.5.1 4 | -------------------------------------------------------------------------------- /sfexpress.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/8/1 23:33 6 | # ------------------------------- 7 | # cron "" 8 | # const $ = new Env('沙发速运签到'); 9 | """ 10 | 1. 某快递app签到 脚本仅供学习交流使用, 请在下载后24h内删除 11 | 2. 环境变量说明: 12 | 必须 SF_SIGN : 顺丰app的sign 有效期挺久的(目前测试大于一个月) 13 | 3. 环境变量获取说明: 14 | i. app内手动抓包 开启抓包工具 app内首页点击右上角的签到 15 | 链接 https://mcs-mimp-web.sf-express.com/mcs-mimp/share/app/shareRedirect?sign=xxx&source=SFAPP&... 16 | 此链接内的sign即为所需的值 只保留示例中xxx的部分 17 | ii. 可通过 tools文件夹内的 sfExpressLogin.py 手机号验证码登录自动获取 适合不会抓包或者无法抓包 18 | iii. 方式二不可和app登录共存 自己登录app会顶号导致sign失效 需要登录app的话 请手动抓包 19 | """ 20 | """ 21 | update: 22 | time: 2022/10/9 23 | content: 参考chavy佬(github@chavyleung https://github.com/chavyleung)之前脚本内的旧版本的任务接口, 增加三个以前的每日任务 24 | """ 25 | from requests import Session 26 | from json import dumps 27 | from tools.send_msg import push 28 | from tools.tool import timestamp, md5, print_now, get_environ 29 | 30 | sign = get_environ("SF_SIGN") 31 | if sign == "": 32 | exit(0) 33 | 34 | 35 | class SFExpress: 36 | def __init__(self, sign): 37 | self.session = Session() 38 | self.sign = sign 39 | self.sign = str(self.sign).replace("+", "%2B") 40 | self.sign = str(self.sign).replace("/", "%2F") 41 | 42 | def refersh_cookie(self): 43 | login_url = f"https://mcs-mimp-web.sf-express.com/mcs-mimp/share/app/shareRedirect?sign={self.sign}&source=SFAPP&bizCode=647@RnlvejM1R3VTSVZ6d3BNaXJxRFpOUVVtQkp0ZnFpNDBKdytobm5TQWxMeHpVUXVrVzVGMHVmTU5BVFA1bXlwcw==" 44 | self.headers = { 45 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 46 | "accept-encoding": "gzip, deflate, br", 47 | "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7", 48 | "cache-control": "no-cache", 49 | "pragma": "no-cache", 50 | "sec-ch-ua": "\".Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"103\", \"Chromium\";v=\"103\"", 51 | "sec-ch-ua-mobile": "?0", 52 | "sec-ch-ua-platform": "\"Windows\"", 53 | "sec-fetch-dest": "document", 54 | "sec-fetch-mode": "navigate", 55 | "sec-fetch-site": "none", 56 | "sec-fetch-user": "?1", 57 | "upgrade-insecure-requests": "1", 58 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" 59 | } 60 | req = self.session.get(login_url, headers=self.headers) 61 | self.referer_url = req.url 62 | 63 | def get_sign(self, timestam): 64 | return md5(f"token=wwesldfs29aniversaryvdld29×tamp={timestam}&sysCode=MCS-MIMP-CORE") 65 | 66 | def wx_check_in(self): 67 | # 微信小程序签到 68 | url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/integralTaskSignPlusService/automaticSignFetchPackage" 69 | timestam = timestamp() 70 | body = { 71 | "channelFrom": "MINI_PROGRAM", 72 | # "channelFrom" : "WEIXIN", 73 | "comeFrom": "vioin" 74 | } 75 | headers = { 76 | "Host": "mcs-mimp-web.sf-express.com", 77 | "Accept": "application/json, text/plain, */*", 78 | "timestamp": str(timestam), 79 | "sysCode": "MCS-MIMP-CORE", 80 | "Accept-Language": "zh-CN,zh-Hans;q=0.9", 81 | "Accept-Encoding": "gzip, deflate, br", 82 | "signature": self.get_sign(timestam), 83 | "Content-Type": "application/json;charset=utf-8", 84 | "Origin": "https://mcs-mimp-web.sf-express.com", 85 | "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.26(0x18001a29) NetType/WIFI Language/zh_CN miniProgram/wxd4185d00bf7e08ac ", 86 | "Referer": self.referer_url, 87 | "Content-Length": str(len(dumps(body).replace(" ", ""))), 88 | "Connection": "keep-alive ", 89 | } 90 | print_now(self.session.post(url, headers=headers, json=body).text) 91 | 92 | def app_check_in(self): 93 | # url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~integralTaskSignPlusService~getUnFetchPointAndDiscount" 94 | # url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/integralTaskSignPlusService/automaticSignFetchPackage" 95 | url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~integralTaskSignPlusService~automaticSignFetchPackage" 96 | timestam = timestamp() 97 | body = { 98 | "comeFrom": "vioin", 99 | "channelFrom": "SFAPP" 100 | } 101 | headers = { 102 | "Host": "mcs-mimp-web.sf-express.com", 103 | "Accept": "application/json, text/plain, */*", 104 | "timestamp": str(timestam), 105 | "sysCode": "MCS-MIMP-CORE ", 106 | "Accept-Language": "zh-CN,zh-Hans;q=0.9", 107 | "Accept-Encoding": "gzip, deflate, br", 108 | "signature": self.get_sign(timestam), 109 | "Content-Type": "application/json;charset=utf-8", 110 | "Origin": "https://mcs-mimp-web.sf-express.com", 111 | "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 mediaCode=SFEXPRESSAPP-iOS-ML", 112 | "Referer": self.referer_url, 113 | "Content-Length": str(len(dumps(body).replace(" ", ""))), 114 | "Connection": "keep-alive " 115 | } 116 | print_now(self.session.post(url, headers=headers, json=body).json()) 117 | 118 | # 获取任务信息 status 2 未完成 1待领取奖励 3已完成 119 | def get_task(self): 120 | url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~integralTaskStrategyService~queryPointTaskAndSignFromES" 121 | # url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/appTask/queryPointTaskAndSign" 122 | timestam = timestamp() 123 | headers = { 124 | "Host": "mcs-mimp-web.sf-express.com", 125 | "Accept": "application/json, text/plain, */*", 126 | "timestamp": str(timestam), 127 | "sysCode": "MCS-MIMP-CORE ", 128 | "Accept-Language": "zh-CN,zh-Hans;q=0.9", 129 | "Accept-Encoding": "gzip, deflate, br", 130 | "signature": self.get_sign(timestam), 131 | "Content-Type": "application/json;charset=utf-8", 132 | "Origin": "https://mcs-mimp-web.sf-express.com", 133 | "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.26(0x18001a29) NetType/WIFI Language/zh_CN miniProgram/wxd4185d00bf7e08ac ", 134 | "Referer": self.referer_url, 135 | "Content-Length": "22", 136 | "Connection": "keep-alive ", 137 | } 138 | for i in range(1, 3): 139 | body = {"channelType": f"{i}"} 140 | req = self.session.post(url, headers=headers, json=body) 141 | for task_msg in req.json()["obj"]["taskTitleLevels"]: 142 | task_title = task_msg["title"] 143 | task_status = task_msg["status"] 144 | task_strategyId = task_msg["strategyId"] 145 | task_code = task_msg["taskCode"] 146 | task_id = task_msg["taskId"] 147 | # print(task_title, end=": ") 148 | print_now(task_title) 149 | if task_status == 2: 150 | self.finish_task(task_code) 151 | self.exchange_task(task_strategyId, task_id, task_code) 152 | elif task_status == 1: 153 | self.exchange_task(task_strategyId, task_id, task_code) 154 | elif task_status == 3: 155 | print("当前任务已完成") 156 | 157 | def finish_task(self, task_code): 158 | url = f"https://mcs-mimp-web.sf-express.com/mcs-mimp/task/finishTask?id={task_code}" 159 | print_now(self.session.get(url, headers=self.headers).json()) 160 | 161 | def exchange_task(self, strategyId, task_id, task_code): 162 | url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~integralTaskStrategyService~fetchIntegral" 163 | timestam = timestamp() 164 | body = {"strategyId": strategyId, "taskId": task_id, "taskCode": task_code} 165 | headers = { 166 | "Host": "mcs-mimp-web.sf-express.com", 167 | "Accept": "application/json, text/plain, */*", 168 | "timestamp": str(timestam), 169 | "sysCode": "MCS-MIMP-CORE", 170 | "Accept-Language": "zh-CN,zh-Hans;q=0.9", 171 | "Accept-Encoding": "gzip, deflate, br", 172 | "signature": self.get_sign(timestam), 173 | "Content-Type": "application/json;charset=utf-8", 174 | "Origin": "https://mcs-mimp-web.sf-express.com", 175 | "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.26(0x18001a29) NetType/WIFI Language/zh_CN miniProgram/wxd4185d00bf7e08ac", 176 | "Referer": self.referer_url, 177 | "Content-Length": str(len(dumps(body).replace(" ", ""))), 178 | "Connection": "keep-alive ", 179 | } 180 | print_now(self.session.post(url, headers=headers, json=body).json()) 181 | 182 | def query_score(self): 183 | url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/member/points/balance" 184 | body = {} 185 | timestam = timestamp() 186 | headers = { 187 | "Host": "mcs-mimp-web.sf-express.com", 188 | "Accept": "application/json, text/plain, */*", 189 | "timestamp": str(timestam), 190 | "sysCode": "MCS-MIMP-CORE", 191 | "Accept-Language": "zh-CN,zh-Hans;q=0.9", 192 | "Accept-Encoding": "gzip, deflate, br", 193 | "signature": self.get_sign(timestam), 194 | "Content-Type": "application/json;charset=utf-8", 195 | "Origin": "https://mcs-mimp-web.sf-express.com", 196 | "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.26(0x18001a29) NetType/WIFI Language/zh_CN miniProgram/wxd4185d00bf7e08ac", 197 | "Referer": self.referer_url, 198 | "Content-Length": str(len(dumps(body).replace(" ", ""))), 199 | "Connection": "keep-alive ", 200 | } 201 | data = self.session.post(url, headers=headers, json=body).json() 202 | total_score = data["obj"]["availablePoints"] 203 | print_now(f"您当前账号共有积分{total_score}") 204 | push("顺丰签到", f"您当前账号共有积分{total_score}") 205 | 206 | def old_daily_task(self): 207 | # url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/appTask/queryPointTaskAndSign" 208 | # body = {"channel":"SFAPP","pageType": "APP_MINE_TASK"} 209 | # data = self.session.post(url, json=body).json() 210 | # print(data) 211 | # pageType_list = data["obj"]["taskTitleLevels"] 212 | pageType_list = ["packageProcess", "scanPointMarket", "scanMemberEquity"] 213 | for pageType in pageType_list: 214 | self.do_old_task(pageType) 215 | self.old_task_exchange(pageType) 216 | 217 | def do_old_task(self, pageType): 218 | url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/appTask/scanPageToRecord" 219 | body = {"channel": "SFAPP", "pageType": pageType} 220 | timestam = timestamp() 221 | self.old_headers = { 222 | "Host": "mcs-mimp-web.sf-express.com", 223 | "Accept": "application/json, text/plain, */*", 224 | "timestamp": str(timestam), 225 | "sysCode": "MCS-MIMP-CORE", 226 | "Accept-Language": "zh-CN,zh-Hans;q=0.9", 227 | "Accept-Encoding": "gzip, deflate, br", 228 | "signature": self.get_sign(timestam), 229 | "Content-Type": "application/json;charset=utf-8", 230 | "Origin": "https://mcs-mimp-web.sf-express.com", 231 | "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.26(0x18001a29) NetType/WIFI Language/zh_CN miniProgram/wxd4185d00bf7e08ac", 232 | "Referer": self.referer_url, 233 | "Content-Length": str(len(dumps(body).replace(" ", ""))), 234 | "Connection": "keep-alive ", 235 | } 236 | self.session.post(url, headers=self.old_headers, json=body) 237 | 238 | def old_task_exchange(self, pageType): 239 | url = "https://mcs-mimp-web.sf-express.com/mcs-mimp/appTask/fetchPoint" 240 | body = {"channel": "SFAPP", "pageType": pageType} 241 | print_now(self.session.post(url, headers=self.old_headers, json=body).json()) 242 | 243 | def main(self): 244 | self.refersh_cookie() 245 | # self.wx_check_in() 246 | self.app_check_in() 247 | self.get_task() 248 | self.old_daily_task() 249 | self.query_score() 250 | 251 | 252 | if __name__ == "__main__": 253 | sf = SFExpress(sign) 254 | sf.main() 255 | -------------------------------------------------------------------------------- /tools/aes_encrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/8/22 18:13 6 | # ------------------------------- 7 | """ 8 | aes加密解密工具 目前仅支持ECB/CBC 块长度均为128位 padding只支持pkcs7/zero_padding(aes中没有pkcs5 能用的pkcs5其实是执行的pkcs7) 后续有需要再加 9 | pycryptodome限制 同一个aes加密对象不能即加密又解密 所以当加密和解密都需要执行时 需要重新new一个对象增加额外开销 10 | -- A cipher object is stateful: once you have encrypted a message , you cannot encrypt (or decrypt) another message using the same object.  11 | """ 12 | try: 13 | from Crypto.Cipher import AES 14 | except: 15 | print("检测到还未安装 pycryptodome 请按照md的方法安装") 16 | exit(0) 17 | from binascii import b2a_hex, a2b_hex 18 | from base64 import b64encode, b64decode 19 | class AES_Ctypt: 20 | def __init__(self, key, iv=None, mode="ECB"): 21 | if len(key) % 16 != 0: 22 | key = key + (AES.block_size - len(key) % AES.block_size) * chr(0) 23 | self.key = key.encode("utf-8") 24 | if mode == "ECB": 25 | self.mode = AES.MODE_ECB 26 | elif mode == "CBC": 27 | self.mode = AES.MODE_CBC 28 | else: 29 | print("您选择的加密方式错误") 30 | if iv is None: 31 | self.cipher = AES.new(self.key, self.mode) 32 | else: 33 | if isinstance(iv, str): 34 | self.cipher = AES.new(self.key, self.mode, iv.encode("utf-8")) 35 | else: 36 | print("偏移量不为字符串") 37 | def encrypt(self, data, padding="pkcs7", b64=False): 38 | bs = AES.block_size 39 | pkcs7_padding = lambda s: s + (bs - len(s.encode()) % bs) * chr(bs - len(s.encode()) % bs) 40 | zero_padding = lambda s: s + (bs - len(s) % bs) * chr(0) 41 | pad = pkcs7_padding if padding=="pkcs7" else zero_padding 42 | data = self.cipher.encrypt(pad(data).encode("utf8")) 43 | encrypt_data = b64encode(data) if b64 else b2a_hex(data) # 输出hex或者base64 44 | return encrypt_data.decode('utf8') 45 | def decrypt(self, data, b64=False): 46 | data = b64decode(data) if b64 else a2b_hex(data) 47 | decrypt_data = self.cipher.decrypt(data).decode() 48 | # 去掉padding 49 | # pkcs7_unpadding = lambda s: s.replace(s[-1], "") 50 | # zero_unpadding = lambda s: s.replace(chr(0), "") 51 | # unpadding = pkcs7_unpadding if padding=="pkcs7" else zero_unpadding 52 | unpadding = lambda s: s.replace(s[-1], "") 53 | return unpadding(decrypt_data) 54 | -------------------------------------------------------------------------------- /tools/encrypt_symmetric.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/10/24 22:09 6 | # ------------------------------- 7 | # !/usr/bin/python3 8 | # -- coding: utf-8 -- 9 | # ------------------------------- 10 | # @Author : github@limoruirui https://github.com/limoruirui 11 | # @Time : 2022/8/22 18:13 12 | # ------------------------------- 13 | """ 14 | aes加密解密工具 目前仅支持ECB/CBC 块长度均为128位 padding只支持pkcs7/zero_padding(aes中没有pkcs5 能用的pkcs5其实是执行的pkcs7) 后续有需要再加 15 | pycryptdemo限制 同一个aes加密对象不能即加密又解密 所以当加密和解密都需要执行时 需要重新new一个对象增加额外开销 16 | -- A cipher object is stateful: once you have encrypted a message , you cannot encrypt (or decrypt) another message using the same object.  17 | """ 18 | try: 19 | from Crypto.Cipher import AES, DES, DES3 20 | except: 21 | print("检测到还未安装 pycryptodome 请按照md的方法安装") 22 | exit(0) 23 | from binascii import b2a_hex, a2b_hex 24 | from base64 import b64encode, b64decode 25 | 26 | 27 | class Crypt: 28 | def __init__(self, crypt_type: str, key, iv=None, mode="ECB"): 29 | """ 30 | 31 | :param crypt_type: 对称加密类型 支持AES, DES, DES3 32 | :param key: 密钥 (aes可选 16/32(24位暂不支持 以后遇到有需要再补) des 固定为8 des3 24(暂不支持16 16应该也不会再使用了) 一般都为24 分为8长度的三组 进行三次des加密 33 | :param iv: 偏移量 34 | :param mode: 模式 CBC/ECB 35 | """ 36 | if crypt_type.upper() not in ["AES", "DES", "DES3"]: 37 | raise Exception("加密类型错误, 请重新选择 AES/DES/DES3") 38 | self.crypt_type = AES if crypt_type.upper() == "AES" else DES if crypt_type.upper() == "DES" else DES3 39 | self.block_size = self.crypt_type.block_size 40 | if self.crypt_type == DES: 41 | self.key_size = self.crypt_type.key_size 42 | elif self.crypt_type == DES3: 43 | self.key_size = self.crypt_type.key_size[1] 44 | else: 45 | if len(key) <= 16: 46 | self.key_size = self.crypt_type.key_size[0] 47 | elif len(key) > 24: 48 | self.key_size = self.crypt_type.key_size[2] 49 | else: 50 | self.key_size = self.crypt_type.key_size[1] 51 | print("当前aes密钥的长度只填充到24 若需要32 请手动用 chr(0) 填充") 52 | if len(key) > self.key_size: 53 | key = key[:self.key_size] 54 | else: 55 | if len(key) % self.key_size != 0: 56 | key = key + (self.key_size - len(key) % self.key_size) * chr(0) 57 | self.key = key.encode("utf-8") 58 | if mode == "ECB": 59 | self.mode = self.crypt_type.MODE_ECB 60 | elif mode == "CBC": 61 | self.mode = self.crypt_type.MODE_CBC 62 | else: 63 | raise Exception("您选择的加密模式错误") 64 | if iv is None: 65 | self.cipher = self.crypt_type.new(self.key, self.mode) 66 | else: 67 | if isinstance(iv, str): 68 | iv = iv[:self.block_size] 69 | self.cipher = self.crypt_type.new(self.key, self.mode, iv.encode("utf-8")) 70 | elif isinstance(iv, bytes): 71 | iv = iv[:self.block_size] 72 | self.cipher = self.crypt_type.new(self.key, self.mode, iv) 73 | else: 74 | raise Exception("偏移量不为字符串") 75 | 76 | def encrypt(self, data, padding="pkcs7", b64=False): 77 | """ 78 | 79 | :param data: 目前暂不支持bytes 只支持string 有需求再补 80 | :param padding: pkcs7/pkck5 zero 81 | :param b64: 若需要得到base64的密文 则为True 82 | :return: 83 | """ 84 | pkcs7_padding = lambda s: s + (self.block_size - len(s.encode()) % self.block_size) * chr( 85 | self.block_size - len(s.encode()) % self.block_size) 86 | zero_padding = lambda s: s + (self.block_size - len(s) % self.block_size) * chr(0) 87 | pad = pkcs7_padding if padding == "pkcs7" else zero_padding 88 | data = self.cipher.encrypt(pad(data).encode("utf8")) 89 | encrypt_data = b64encode(data) if b64 else b2a_hex(data) # 输出hex或者base64 90 | return encrypt_data.decode('utf8') 91 | 92 | def decrypt(self, data, b64=False): 93 | """ 94 | 对称加密的解密 95 | :param data: 支持bytes base64 hex list 未做填充 密文应该都是数据块的倍数 带有需求再补 96 | :param b64: 若传入的data为base64格式 则为True 97 | :return: 98 | """ 99 | if isinstance(data, list): 100 | data = bytes(data) 101 | if not isinstance(data, bytes): 102 | data = b64decode(data) if b64 else a2b_hex(data) 103 | decrypt_data = self.cipher.decrypt(data).decode() 104 | # 去掉padding 105 | # pkcs7_unpadding = lambda s: s.replace(s[-1], "") 106 | # zero_unpadding = lambda s: s.replace(chr(0), "") 107 | # unpadding = pkcs7_unpadding if padding=="pkcs7" else zero_unpadding 108 | unpadding = lambda s: s.replace(s[-1], "") 109 | return unpadding(decrypt_data) 110 | -------------------------------------------------------------------------------- /tools/iqiyi_login.py: -------------------------------------------------------------------------------- 1 | # 留作备份 2 | # 扫码获取爱奇艺P00001, 此二维码有效期只有半分钟,但是爱奇艺没给二维码失效判断,所以默认执行6次后未完成扫码就结束 3 | # 实测此方法获取的P00001有效期为三个月,如果只用于签到和日常任务,超过三个月之后还能用,但是无法碰蛋和查询信息 4 | # 第十行若选择本地展示 则需要安装PIL库,若选择tg推送,需在17 18行填写botToken和user_id 5 | from requests import post, get 6 | from random import random 7 | from hashlib import md5 8 | from time import sleep 9 | from os import remove 10 | 11 | qrShowType = '本地展示' # 可选择 本地展示 tg推送 #默认本地展示 适合本地有图形界面的机器使用 tg推送则不需要图形界面,但需要考虑网络问题 12 | if qrShowType == '本地展示': 13 | try: 14 | from PIL import image 15 | except: 16 | print('您当前未安装pillow库,请使用pip3 install pillow安装') 17 | else: 18 | botToken = '' 19 | user_id = '' 20 | 21 | 22 | def tgpush(content): 23 | url = f"https://api.telegram.org/bot{botToken}/sendPhoto" 24 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 25 | data = {'chat_id': str(user_id), 'photo': content} 26 | try: 27 | req = post(url, headers=headers, data=data, timeout=20) 28 | except: 29 | print('推送失败') 30 | 31 | 32 | def getToken(): 33 | url = 'https://passport.iqiyi.com/apis/qrcode/gen_login_token.action' 34 | headers = { 35 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36' 36 | } 37 | data = { 38 | 'agenttype': 1, 39 | 'app_version': '', 40 | 'device_id': '', 41 | 'device_name': '网页端', 42 | 'fromSDK': 1, 43 | 'ptid': '01010021010000000000', 44 | 'sdk_version': '1.0.0', 45 | 'surl': 1 46 | } 47 | return post(url, headers=headers, data=data).json()['data']['token'] 48 | 49 | 50 | def qrcode(token): 51 | url = f'https://qrcode.iqiyipic.com/login/?data=https%3A%2F%2Fpassport.iqiyi.com%2Fapis%2Fqrcode%2Ftoken_login.action%3Ftoken%3D{token}&property=0&salt={md5Encode(f"35f4223bb8f6c8638dc91d94e9b16f5https%3A%2F%2Fpassport.iqiyi.com%2Fapis%2Fqrcode%2Ftoken_login.action%3Ftoken%3D{token}")}&width=162&_={random()}' 52 | if qrShowType == 'tg推送': 53 | tgpush(url) 54 | else: 55 | headers = { 56 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36' 57 | } 58 | req = get(url, headers=headers) 59 | with open('登录二维码.png', 'wb') as f: 60 | f.write(req.content) 61 | image.open('登录二维码.png').show() 62 | 63 | 64 | def login(token): 65 | url = 'https://passport.iqiyi.com/apis/qrcode/is_token_login.action' 66 | headers = { 67 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36' 68 | } 69 | data = { 70 | 'agenttype': 1, 71 | 'app_version': '', 72 | 'device_id': '', 73 | 'fromSDK': 1, 74 | 'ptid': '01010021010000000000', 75 | 'sdk_version': '1.0.0', 76 | 'token': token 77 | } 78 | for i in range(6): 79 | req = post(url, headers=headers, data=data) 80 | code = req.json()['code'] 81 | if code == 'A00000': 82 | cookie = f"您的P00001为{req.cookies.get('P00001')}" 83 | try: 84 | remove('登录二维码.png') 85 | except: 86 | print('当前为tg推送,未生成本地图片,无需删除') 87 | return cookie 88 | else: 89 | sleep(8) 90 | continue 91 | try: 92 | remove('登录二维码.png') 93 | except: 94 | print('当前为tg推送,未生成本地图片,无需删除') 95 | return '本次扫码未成功,可能是二维码失效或者未知原因' 96 | 97 | 98 | def start(): 99 | token = getToken() 100 | qrcode(token) 101 | print(login(token)) 102 | 103 | 104 | def md5Encode(str): 105 | m = md5(str.encode(encoding='utf-8')) 106 | return m.hexdigest() 107 | 108 | 109 | if __name__ == '__main__': 110 | start() 111 | -------------------------------------------------------------------------------- /tools/ql_api.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const got = require('got'); 4 | require('dotenv').config(); 5 | const { readFile } = require('fs/promises'); 6 | const path = require('path'); 7 | 8 | const qlDir = '/ql'; 9 | const fs = require('fs'); 10 | let Fileexists = fs.existsSync('/ql/data/config/auth.json'); 11 | let authFile=""; 12 | if (Fileexists) 13 | authFile="/ql/data/config/auth.json" 14 | else 15 | authFile="/ql/config/auth.json" 16 | //const authFile = path.join(qlDir, 'config/auth.json'); 17 | 18 | const api = got.extend({ 19 | prefixUrl: 'http://127.0.0.1:5600', 20 | retry: { limit: 0 }, 21 | }); 22 | 23 | async function getToken() { 24 | const authConfig = JSON.parse(await readFile(authFile)); 25 | return authConfig.token; 26 | } 27 | 28 | module.exports.getEnvs = async (name) => { 29 | const token = await getToken(); 30 | const body = await api({ 31 | url: 'api/envs', 32 | searchParams: { 33 | searchValue: name, 34 | t: Date.now(), 35 | }, 36 | headers: { 37 | Accept: 'application/json', 38 | authorization: `Bearer ${token}`, 39 | }, 40 | }).json(); 41 | return body.data; 42 | }; 43 | 44 | module.exports.getEnvsCount = async (name) => { 45 | const data = await this.getEnvs(name); 46 | return data.length; 47 | }; 48 | 49 | module.exports.addEnv = async (name,cookie, remarks) => { 50 | const token = await getToken(); 51 | const body = await api({ 52 | method: 'post', 53 | url: 'api/envs', 54 | params: { t: Date.now() }, 55 | json: [{ 56 | name: name, 57 | value: cookie, 58 | remarks, 59 | }], 60 | headers: { 61 | Accept: 'application/json', 62 | authorization: `Bearer ${token}`, 63 | 'Content-Type': 'application/json;charset=UTF-8', 64 | }, 65 | }).json(); 66 | return body; 67 | }; 68 | 69 | module.exports.updateEnv = async (name,cookie, eid, remarks) => { 70 | const token = await getToken(); 71 | const body = await api({ 72 | method: 'put', 73 | url: 'api/envs', 74 | params: { t: Date.now() }, 75 | json: { 76 | name: name, 77 | value: cookie, 78 | _id: eid, 79 | remarks, 80 | }, 81 | headers: { 82 | Accept: 'application/json', 83 | authorization: `Bearer ${token}`, 84 | 'Content-Type': 'application/json;charset=UTF-8', 85 | }, 86 | }).json(); 87 | return body; 88 | }; 89 | 90 | module.exports.updateEnv11 = async (name,cookie, eid, remarks) => { 91 | const token = await getToken(); 92 | const body = await api({ 93 | method: 'put', 94 | url: 'api/envs', 95 | params: { t: Date.now() }, 96 | json: { 97 | name: name, 98 | value: cookie, 99 | id: eid, 100 | remarks, 101 | }, 102 | headers: { 103 | Accept: 'application/json', 104 | authorization: `Bearer ${token}`, 105 | 'Content-Type': 'application/json;charset=UTF-8', 106 | }, 107 | }).json(); 108 | return body; 109 | }; 110 | 111 | module.exports.DisableCk = async (eid) => { 112 | const token = await getToken(); 113 | const body = await api({ 114 | method: 'put', 115 | url: 'api/envs/disable', 116 | params: { t: Date.now() }, 117 | body: JSON.stringify([eid]), 118 | headers: { 119 | Accept: 'application/json', 120 | authorization: `Bearer ${token}`, 121 | 'Content-Type': 'application/json;charset=UTF-8', 122 | }, 123 | }).json(); 124 | return body; 125 | }; 126 | 127 | module.exports.EnableCk = async (eid) => { 128 | const token = await getToken(); 129 | const body = await api({ 130 | method: 'put', 131 | url: 'api/envs/enable', 132 | params: { t: Date.now() }, 133 | body: JSON.stringify([eid]), 134 | headers: { 135 | Accept: 'application/json', 136 | authorization: `Bearer ${token}`, 137 | 'Content-Type': 'application/json;charset=UTF-8', 138 | }, 139 | }).json(); 140 | return body; 141 | }; 142 | 143 | module.exports.getstatus = async(name,eid) => { 144 | const envs = await this.getEnvs(name); 145 | var tempid = 0; 146 | for (let i = 0; i < envs.length; i++) { 147 | tempid = 0; 148 | if (envs[i]._id) { 149 | tempid = envs[i]._id; 150 | } 151 | if (envs[i].id) { 152 | tempid = envs[i].id; 153 | } 154 | if (tempid == eid) { 155 | return envs[i].status; 156 | } 157 | } 158 | return 99; 159 | }; 160 | 161 | module.exports.getEnvById = async(name,eid) => { 162 | const envs = await this.getEnvs(name); 163 | var tempid = 0; 164 | for (let i = 0; i < envs.length; i++) { 165 | tempid = 0; 166 | if (envs[i]._id) { 167 | tempid = envs[i]._id; 168 | } 169 | if (envs[i].id) { 170 | tempid = envs[i].id; 171 | } 172 | if (tempid == eid) { 173 | return envs[i].value; 174 | } 175 | } 176 | return ""; 177 | }; 178 | 179 | module.exports.delEnv = async (eid) => { 180 | const token = await getToken(); 181 | const body = await api({ 182 | method: 'delete', 183 | url: 'api/envs', 184 | params: { t: Date.now() }, 185 | body: JSON.stringify([eid]), 186 | headers: { 187 | Accept: 'application/json', 188 | authorization: `Bearer ${token}`, 189 | 'Content-Type': 'application/json;charset=UTF-8', 190 | }, 191 | }).json(); 192 | return body; 193 | }; 194 | -------------------------------------------------------------------------------- /tools/ql_api.py: -------------------------------------------------------------------------------- 1 | import json, os 2 | import time 3 | from sys import stdout 4 | 5 | import requests,re 6 | 7 | ql_auth_path = '/ql/data/config/auth.json' 8 | ql_config_path = '/ql/data/config/config.sh' 9 | #判断环境变量 10 | flag = 'new' 11 | if not os.path.exists(ql_auth_path): 12 | ql_auth_path = '/ql/config/auth.json' 13 | ql_config_path = '/ql/config/config.sh' 14 | if not os.path.exists(ql_config_path): 15 | ql_config_path = '/ql/config/config.js' 16 | flag = 'old' 17 | # ql_auth_path = r'D:\Docker\ql\config\auth.json' 18 | ql_url = 'http://localhost:5600' 19 | 20 | 21 | def __get_token() -> str or None: 22 | with open(ql_auth_path, 'r', encoding='utf-8') as f: 23 | j_data = json.load(f) 24 | return j_data.get('token') 25 | 26 | 27 | def __get__headers() -> dict: 28 | headers = { 29 | 'Accept': 'application/json', 30 | 'Content-Type': 'application/json;charset=UTF-8', 31 | 'Authorization': 'Bearer ' + __get_token() 32 | } 33 | return headers 34 | 35 | 36 | 37 | 38 | # 封装读取环境变量的方法(读取环境变量的整个CK) 39 | def get_cookie_all(key, default="", output=True): 40 | def no_read(): 41 | if output: 42 | print_now(f"未填写环境变量 {key} 请添加") 43 | return default 44 | return get_cookie_all_data(key) if get_cookie_all_data(key) else no_read() 45 | 46 | 47 | #获取整个ck,包括备注 48 | def get_cookie_all_data(name): 49 | ck_list = [] 50 | remarks_list = [] 51 | cookie = None 52 | cookies = get_config_and_envs(name) 53 | for ck in cookies: 54 | data_temp = {} 55 | if ck["name"] != name: 56 | continue 57 | if ck.get('status') == 0: 58 | # ck_list.append(ck.get('value')) 59 | # 直接添加CK 60 | ck_list.append(ck) 61 | return ck_list 62 | 63 | 64 | 65 | # 封装读取环境变量的方法(只读取环境变量的value) 66 | def get_cookie(key, default="", output=True): 67 | def no_read(): 68 | if output: 69 | print_now(f"未填写环境变量 {key} 请添加") 70 | return default 71 | return get_cookie_data(key) if get_cookie_data(key) else no_read() 72 | 73 | #获取ck的value 74 | def get_cookie_data(name): 75 | ck_list = [] 76 | cookie = None 77 | cookies = get_config_and_envs(name) 78 | for ck in cookies: 79 | if ck["name"] != name: 80 | continue 81 | if ck.get('status') == 0: 82 | ck_list.append(ck.get('value')) 83 | return ck_list 84 | 85 | # 修改print方法 避免某些环境下python执行print 不会去刷新缓存区导致信息第一时间不及时输出 86 | def print_now(content): 87 | print(content) 88 | stdout.flush() 89 | 90 | 91 | # 查询环境变量 92 | def get_envs(name: str = None) -> list: 93 | params = { 94 | 't': int(time.time() * 1000) 95 | } 96 | if name is not None: 97 | params['searchValue'] = name 98 | res = requests.get(ql_url + '/api/envs', headers=__get__headers(), params=params) 99 | j_data = res.json() 100 | if j_data['code'] == 200: 101 | return j_data['data'] 102 | return [] 103 | 104 | 105 | # 查询环境变量+config.sh变量 106 | def get_config_and_envs(name: str = None) -> list: 107 | params = { 108 | 't': int(time.time() * 1000) 109 | } 110 | #返回的数据data 111 | data = [] 112 | if name is not None: 113 | params['searchValue'] = name 114 | res = requests.get(ql_url + '/api/envs', headers=__get__headers(), params=params) 115 | j_data = res.json() 116 | if j_data['code'] == 200: 117 | data = j_data['data'] 118 | with open(ql_config_path, 'r', encoding='utf-8') as f: 119 | while True: 120 | # Get next line from file 121 | line = f.readline() 122 | # If line is empty then end of file reached 123 | if not line : 124 | break; 125 | #print(line.strip()) 126 | exportinfo = line.strip().replace("\"","").replace("\'","") 127 | #去除注释#行 128 | rm_str_list = re.findall(r'^#(.+?)', exportinfo,re.DOTALL) 129 | #print('rm_str_list数据:{}'.format(rm_str_list)) 130 | exportinfolist = [] 131 | if len(rm_str_list) == 1: 132 | exportinfo = "" 133 | #list_all = re.findall(r'export[ ](.+?)', exportinfo,re.DOTALL) 134 | #print('exportinfo数据:{}'.format(exportinfo)) 135 | #以export分隔,字符前面新增标记作为数组0,数组1为后面需要的数据 136 | list_all = ("标记"+exportinfo.replace(" ","").replace(" ","")).split("export") 137 | #print('list_all数据:{}'.format(list_all)) 138 | if len(list_all) > 1: 139 | #以=分割,查找需要的环境名字 140 | tmp = list_all[1].split("=") 141 | if len(tmp) > 1: 142 | 143 | info = tmp[0] 144 | if name in info: 145 | #print('需要查询的环境数据:{}'.format(tmp)) 146 | data_tmp = [] 147 | data_json = { 148 | 'id': None, 149 | 'value': tmp[1], 150 | 'status': 0, 151 | 'name': name, 152 | 'remarks': "", 153 | 'position': None, 154 | 'timestamp': int(time.time()*1000), 155 | 'created': int(time.time()*1000) 156 | } 157 | if flag == 'old': 158 | data_json = { 159 | '_id': None, 160 | 'value': tmp[1], 161 | 'status': 0, 162 | 'name': name, 163 | 'remarks': "", 164 | 'position': None, 165 | 'timestamp': int(time.time()*1000), 166 | 'created': int(time.time()*1000) 167 | } 168 | #print('需要的数据:{}'.format(data_json)) 169 | data.append(data_json) 170 | #print('第二次配置数据:{}'.format(data)) 171 | return data 172 | 173 | 174 | # 新增环境变量 175 | def post_envs(name: str, value: str, remarks: str = None) -> list: 176 | params = { 177 | 't': int(time.time() * 1000) 178 | } 179 | data = [{ 180 | 'name': name, 181 | 'value': value 182 | }] 183 | if remarks is not None: 184 | data[0]['remarks'] = remarks 185 | res = requests.post(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 186 | j_data = res.json() 187 | if j_data['code'] == 200: 188 | return j_data['data'] 189 | return [] 190 | 191 | 192 | # 修改环境变量(2.11.x版本有问题,属于旧版青龙,但是id属于新版本) 193 | def put_envs(_id: str, name: str, value: str, remarks: str = None) -> bool: 194 | params = { 195 | 't': int(time.time() * 1000) 196 | } 197 | 198 | data = { 199 | 'name': name, 200 | 'value': value, 201 | 'id': _id 202 | } 203 | if flag == 'old': 204 | data = { 205 | 'name': name, 206 | 'value': value, 207 | '_id': _id 208 | } 209 | 210 | if remarks is not None: 211 | data['remarks'] = remarks 212 | res = requests.put(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 213 | j_data = res.json() 214 | if j_data['code'] == 200: 215 | return True 216 | return False 217 | 218 | # 修改环境变量1,青龙2.11.0以下版本(不含2.11.0) 219 | def put_envs_old(_id: str, name: str, value: str, remarks: str = None) -> bool: 220 | params = { 221 | 't': int(time.time() * 1000) 222 | } 223 | 224 | data = { 225 | 'name': name, 226 | 'value': value, 227 | '_id': _id 228 | } 229 | 230 | if remarks is not None: 231 | data['remarks'] = remarks 232 | res = requests.put(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 233 | j_data = res.json() 234 | if j_data['code'] == 200: 235 | return True 236 | return False 237 | 238 | 239 | # 修改环境变量2,青龙2.11.0以上版本(含2.11.0) 240 | def put_envs_new(_id: int, name: str, value: str, remarks: str = None) -> bool: 241 | params = { 242 | 't': int(time.time() * 1000) 243 | } 244 | 245 | data = { 246 | 'name': name, 247 | 'value': value, 248 | 'id': _id 249 | } 250 | 251 | if remarks is not None: 252 | data['remarks'] = remarks 253 | res = requests.put(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 254 | j_data = res.json() 255 | if j_data['code'] == 200: 256 | return True 257 | return False 258 | 259 | 260 | # 禁用环境变量 261 | def disable_env(_id: str) -> bool: 262 | params = { 263 | 't': int(time.time() * 1000) 264 | } 265 | data = [_id] 266 | res = requests.put(ql_url + '/api/envs/disable', headers=__get__headers(), params=params, json=data) 267 | j_data = res.json() 268 | if j_data['code'] == 200: 269 | return True 270 | return False 271 | 272 | 273 | # 启用环境变量 274 | def enable_env(_id: str) -> bool: 275 | params = { 276 | 't': int(time.time() * 1000) 277 | } 278 | data = [_id] 279 | res = requests.put(ql_url + '/api/envs/enable', headers=__get__headers(), params=params, json=data) 280 | j_data = res.json() 281 | if j_data['code'] == 200: 282 | return True 283 | return False 284 | -------------------------------------------------------------------------------- /tools/ql_util.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | 5 | # 随机生成数字与小写字母字符串 6 | def get_random_str(rdm_leg: int = 8, status: bool = False): 7 | random_str = '' 8 | base_str = string.octdigits 9 | if status: 10 | base_str = base_str + string.ascii_lowercase 11 | length = len(base_str) - 1 12 | for i in range(rdm_leg): 13 | random_str += base_str[random.randint(0, length)] 14 | return random_str 15 | -------------------------------------------------------------------------------- /tools/rsa_encrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/8/23 13:05 6 | # ------------------------------- 7 | try: 8 | from Crypto.PublicKey.RSA import importKey, construct 9 | from Crypto.Cipher import PKCS1_v1_5 10 | except: 11 | print("检测到还未安装 pycryptodome 请按照md的方法安装") 12 | exit(0) 13 | from base64 import b64encode 14 | 15 | 16 | class RSA_Encrypt: 17 | def __init__(self, key): 18 | if isinstance(key, str): 19 | # 若提供的rsa公钥不为pem格式 则先将hex转化为pem格式 20 | # self.key = bytes.fromhex(key) if "PUBLIC KEY" not in key else key.encode() 21 | self.key = self.public_key(key) if "PUBLIC KEY" not in key else key.encode() 22 | else: 23 | print("提供的公钥格式不正确") 24 | 25 | def public_key(self, rsaExponent, rsaModulus=10001): 26 | e = int(rsaExponent, 16) 27 | n = int(rsaModulus, 16) # snipped for brevity 28 | pubkey = construct((n, e)).export_key() 29 | return pubkey 30 | 31 | def encrypt(self, data, b64=False): 32 | data = data.encode('utf-8') 33 | length = len(data) 34 | default_length = 117 35 | pub_key = importKey(self.key) 36 | cipher = PKCS1_v1_5.new(pub_key) 37 | if length < default_length: 38 | rsa_text = cipher.encrypt(data) 39 | return b64encode(rsa_text).decode() if b64 else rsa_text.hex() 40 | offset = 0 41 | res = [] 42 | while length - offset > 0: 43 | if length - offset > default_length: 44 | res.append(cipher.encrypt(data[offset:offset + default_length])) 45 | else: 46 | res.append(cipher.encrypt(data[offset:])) 47 | offset += default_length 48 | byte_data = b''.join(res) 49 | return b64encode(byte_data).decode() if b64 else byte_data.hex() 50 | -------------------------------------------------------------------------------- /tools/send_msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/8/23 23:31 6 | # ------------------------------- 7 | from requests import post 8 | from json import dumps 9 | from sys import path 10 | path.append("./tools") 11 | from tool import get_environ 12 | 13 | tg_userId = get_environ("TG_USER_ID", "", False) 14 | tgbot_token = get_environ("TG_BOT_TOKEN_ADDED", "", False) if get_environ("TG_BOT_TOKEN_ADDED", "", False) else get_environ("TG_BOT_TOKEN", "", False) 15 | tg_push_api = get_environ("TG_API_HOST", "", False) 16 | pushplus_token = get_environ("PUSH_PLUS_TOKEN_ADDED", "", False) if get_environ("PUSH_PLUS_TOKEN_ADDED", "", False) else get_environ("PUSH_PLUS_TOKEN", "", False) 17 | 18 | def tgpush(title, content): 19 | url = f"https://api.telegram.org/bot{tgbot_token}/sendMessage" 20 | if tg_push_api != "": 21 | url = f"https://{tg_push_api}/bot{tgbot_token}/sendMessage" 22 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 23 | data = {'chat_id': str(tg_userId), 'text': f"{title}\n{content}", 'disable_web_page_preview': 'true'} 24 | try: 25 | post(url, headers=headers, data=data, timeout=10) 26 | except: 27 | print('推送失败') 28 | def pushplus(title, content): 29 | url = "http://www.pushplus.plus/send" 30 | headers = { 31 | "Content-Type": "application/json" 32 | } 33 | data = { 34 | "token": pushplus_token, 35 | "title": title, 36 | "content": content 37 | } 38 | try: 39 | post(url, headers=headers, data=dumps(data)) 40 | except: 41 | print('推送失败') 42 | def push(title, content): 43 | if pushplus_token != "" and pushplus_token != "no": 44 | pushplus(title, content) 45 | if tgbot_token != "" and tgbot_token != "no" and tg_userId != "": 46 | tgpush(title, content) -------------------------------------------------------------------------------- /tools/sfExpressLogin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/9/16 17:20 6 | # ------------------------------- 7 | from json import dumps 8 | from requests import post 9 | from uuid import uuid1 10 | 11 | from tool import print_now, md5, timestamp 12 | 13 | class SFLogin: 14 | def __init__(self): 15 | self.deviceId = str(uuid1()) 16 | def getSytToken(self, body, deviceId, timestamp): 17 | wait_encrypt_str = f"CNsc{md5(body)}9.37.2{deviceId}172b34b80bac04ad148a2729dfb2cd9f{timestamp}" 18 | sytToken = md5(wait_encrypt_str) 19 | return sytToken 20 | def sendMsgCaptcha(self): 21 | url = "https://ccsp-egmas.sf-express.com/cx-app-member/member/app/user/sendCaptcha" 22 | self.phone = input("请输入手机号(输入完成后按回车结束): ") 23 | if len(self.phone) != 11: 24 | print_now("手机号格式错误") 25 | timestamp1 = timestamp() 26 | body = f'{{"mobile":{self.phone},"type":"05"}}' 27 | headers = { 28 | "regioncode": "CN", 29 | "languagecode": "sc", 30 | "screensize": "1080x1920", 31 | "mediacode": "AndroidML", 32 | "systemversion": "12", 33 | "clientversion": "9.37.2", 34 | "model": "SM-G9860", 35 | "carrier": "unknown", 36 | "deviceid": self.deviceId, 37 | "jsbundle": "172b34b80bac04ad148a2729dfb2cd9f", 38 | "timeinterval": str(timestamp1), 39 | "syttoken": self.getSytToken(body, self.deviceId, timestamp1), 40 | "content-type": "application/json; charset=utf-8", 41 | "content-length": str(len(dumps(body).replace(" ", ""))), 42 | "accept-encoding": "gzip", 43 | "user-agent": "okhttp/4.9.1", 44 | "pragma": "no-cache", 45 | "cache-control": "no-cache" 46 | } 47 | data = post(url, headers=headers, data=body).json() 48 | if not data.get("success"): 49 | print(f"发送验证码失败, 请重试, 发送日志为{data}") 50 | def login(self): 51 | url = "https://ccsp-egmas.sf-express.com/cx-app-member/member/app/user/userLogin" 52 | timestamp1 = timestamp() 53 | captcha = input("请输入手机短信验证码(有效期90秒, 输入完成后按回车结束): ") 54 | body = f'{{"captcha":"{captcha}","mobile":"{self.phone}","registerSource":""}}' 55 | headers = { 56 | "regioncode": "CN", 57 | "languagecode": "sc", 58 | "screensize": "1080x1920", 59 | "mediacode": "AndroidML", 60 | "systemversion": "12", 61 | "clientversion": "9.37.2", 62 | "model": "SM-G9860", 63 | "carrier": "unknown", 64 | "deviceid": self.deviceId, 65 | "jsbundle": "172b34b80bac04ad148a2729dfb2cd9f", 66 | "timeinterval": str(timestamp1), 67 | "syttoken": self.getSytToken(body, self.deviceId, timestamp1), 68 | "content-type": "application/json; charset=utf-8", 69 | "content-length": str(len(dumps(body).replace(" ", ""))), 70 | "accept-encoding": "gzip", 71 | "user-agent": "okhttp/4.9.1", 72 | "pragma": "no-cache", 73 | "cache-control": "no-cache" 74 | } 75 | login_data = post(url, headers=headers, data=body).json() 76 | if not login_data.get("success"): 77 | print_now(f"登陆失败, 登录接口日志为{login_data}") 78 | exit(0) 79 | self.menNo = login_data["obj"]["memNo"] 80 | self.userId = login_data["obj"]["memberId"] 81 | def get_sign(self): 82 | url = "https://ccsp-egmas.sf-express.com/cx-app-member/member/app/user/universalSign" 83 | body = f'{{"needReqTime":"1","memNo":"{self.menNo}","mobile":"{self.phone}","userId":"{self.userId}","extra":"","name":"mcs-mimp-web.sf-express.com"}}' 84 | timestamp1 = timestamp() 85 | headers = { 86 | "Host": "ccsp-egmas.sf-express.com", 87 | "User-Agent": "okhttp/4.9.1", 88 | "languageCode": "sc", 89 | "clientVersion": "9.37.2", 90 | "mediaCode": "AndroidML", 91 | "systemVersion": "12", 92 | "regionCode": "CN", 93 | "jsbundle": "172b34b80bac04ad148a2729dfb2cd9f", 94 | "Content-Length": str(len(dumps(body).replace(" ", ""))), 95 | "deviceId": self.deviceId, # 0ea5f454-0086-345f-b14f-d06b65d868b9 96 | "Connection": "keep-alive", 97 | "sytToken": self.getSytToken(body, self.deviceId, timestamp1), 98 | "carrier": "unknown", 99 | "Accept-Language": "zh-Hans-JP;q=1, zh-Hant-JP;q=0.9, en-JP;q=0.8", 100 | "model": "SM-G9860", 101 | "Accept": "*/*", 102 | "Content-Type": "application/json", 103 | "Accept-Encoding": "gzip, deflate, br", 104 | "timeInterval": str(timestamp1), 105 | "screenSize": "1080x1920" 106 | } 107 | req = post(url, headers=headers, data=body) 108 | sign = req.json()["obj"]["sign"] 109 | # sign = str(sign).replace("+", "%2B") 110 | # sign = str(sign).replace("/", "%2F") 111 | print_now("以下是你的sign, 请复制后自行使用, 部分环境下需要如111和112行一样 将 + 转化成%2B / 转化成%2F") 112 | print_now(sign) 113 | return 114 | def main(self): 115 | self.sendMsgCaptcha() 116 | self.login() 117 | self.get_sign() 118 | if __name__ == "__main__": 119 | SFLogin().main() 120 | -------------------------------------------------------------------------------- /tools/tool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/8/22 17:56 6 | # ------------------------------- 7 | """ 8 | 封装一些工具 9 | """ 10 | from hashlib import md5 as md5Encode, sha1 as sha1Encode 11 | from hmac import new 12 | from random import choice, randint 13 | from string import digits, ascii_lowercase, ascii_uppercase 14 | from time import sleep, time 15 | from datetime import datetime, timedelta 16 | from sys import stdout 17 | from os import environ 18 | from json import load 19 | 20 | 21 | # 生成随机字符串 22 | def uuid(num, upper=False): 23 | str = '' 24 | if upper: 25 | for i in range(num): 26 | str += choice(digits + ascii_lowercase + ascii_uppercase) 27 | else: 28 | for i in range(num): 29 | str += choice(digits + ascii_lowercase) 30 | return str 31 | 32 | 33 | # 修改print方法 避免某些环境下python执行print 不会去刷新缓存区导致信息第一时间不及时输出 34 | def print_now(content): 35 | print(content) 36 | stdout.flush() 37 | 38 | 39 | def get_ua(): 40 | with open("../user_agent.json", "rb") as f: 41 | ua_list = load(f)["Chrome"] 42 | ua = choice(ua_list) 43 | return ua 44 | 45 | 46 | # 随机休眠时长 若为0时区 TimeZone为真 47 | def random_sleep(min_time=300, max_time=5400, TimeZone=True): 48 | random_time = randint(min_time, max_time) 49 | print_now(f"随机等待{random_time}秒") 50 | sleep(random_time) 51 | now_time = (datetime.now() + timedelta(hours=8)).__format__("%Y-%m-%d %H:%M:%S") 52 | if TimeZone: 53 | now_time = (datetime.now()).__format__("%Y-%m-%d %H:%M:%S") 54 | print_now(f"等待结束.开始执行 现在时间是------{now_time} ------------") 55 | 56 | 57 | def timestamp(short=False): 58 | if short: 59 | return int(round(time())) 60 | return int(round(time() * 1000)) 61 | 62 | 63 | # md5 64 | def md5(data): 65 | if isinstance(data, str): 66 | data = data.encode("utf8") 67 | m = md5Encode(data) 68 | return m.hexdigest() 69 | 70 | def sha1(data): 71 | if isinstance(data, str): 72 | data = data.encode("utf8") 73 | elif isinstance(data, list): 74 | data = bytes(data) 75 | m = sha1Encode(data) 76 | return m.hexdigest() 77 | # hmac sha1 78 | def hmac_sha1(data, key): 79 | hmac_code = new(key.encode(), data.encode(), sha1Encode) 80 | return hmac_code.hexdigest() 81 | 82 | 83 | # 封装读取环境变量的方法 84 | def get_environ(key, default="", output=True): 85 | def no_read(): 86 | if output: 87 | print_now(f"未填写环境变量 {key} 请添加") 88 | return default 89 | return environ.get(key) if environ.get(key) else no_read() 90 | -------------------------------------------------------------------------------- /tools/wxy_login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 2022/10/6 0:18 6 | # ------------------------------- 7 | """ 8 | 无忧行账号密码登录获取token 9 | 1. 脚本仅供学习交流使用, 请在下载后24h内删除 10 | 2. 给无法抓包或者不会抓包的人使用 请先在app内设置密码 若登录后设置没有密码设置 先退出 再登录 找到密码登录 忘记密码 11 | 3. 环境变量说明 WXY_ACCOUNT_PWD(必需) 12 | WXY_ACCOUNT_PWD 账号&密码 账号密码用&连接 example: 12345678910&123456 13 | """ 14 | from requests import post 15 | from tool import timestamp, md5, get_environ, sha1 16 | 17 | wyx_account_info = get_environ("WXY_ACCOUNT_PWD") 18 | if wyx_account_info == "": 19 | exit(0) 20 | account_info = wyx_account_info.split("&") 21 | account = account_info[0] 22 | password = account_info[1] 23 | 24 | 25 | def timestamp_to_arr(times): 26 | bArr = [0 for i in range(8)] 27 | for i in range(8): 28 | bArr[i] = ((times >> (64 - ((i + 1) << 3))) & 255) 29 | return bArr 30 | 31 | 32 | def get_sign(times): 33 | bArr = [106, 117, 59, 58, 42, 99, 43, 40] 34 | bArr = bArr + timestamp_to_arr(times) 35 | sign = sha1(bArr) 36 | return sign 37 | 38 | 39 | def get_sign_img_code(imgCodeToken, mobile, times): 40 | str = f"country_code=86&imgCodeToken={imgCodeToken}&mobile={mobile}&sign_key=wuyouxing&key&&timeStamp={times}&type=3" 41 | return sha1(str).upper() 42 | 43 | 44 | def login_by_pwd(): 45 | times = timestamp() 46 | url = f"https://app1.jegotrip.com.cn/api/user/v1/phoneUserLogin?n_token=&lang=zh_CN×tamp={times}&sign={get_sign(times)}" 47 | body = { 48 | "countryCode": "86", 49 | "logintype": "2", 50 | "mobile": account, 51 | "password": md5(f"20150727*{password}") 52 | } 53 | data = post(url, json=body).json() 54 | if data["code"] == "0": 55 | print("您的token为(请直接复制使用): ") 56 | print(data["body"]["token"]) 57 | else: 58 | print("登录失败, 登录接口返回的日志为: ") 59 | print(data) 60 | 61 | 62 | if __name__ == "__main__": 63 | login_by_pwd() -------------------------------------------------------------------------------- /wochangyou.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@yuanter https://github.com/yuanter by院长 5 | # @Time : 2023/9/4 02:25 6 | # cron "15 1 0 * * *" script-path=xxx.py,tag=匹配cron用 7 | # const $ = new Env('沃畅游破限速'); 8 | # ------------------------------- 9 | 10 | """ 11 | 说明:首次使用,联通app首页--5g新通信--联通畅游,点击个人中心,手动登录一遍 12 | 1. 沃畅游破限速 支持多账号执行 需要抓包沃畅游,找Authorization值 脚本仅供学习交流使用, 请在下载后24h内删除 13 | 2. cron说明 晚上12点01分15秒开始执行 可直接使用默认cron,亦可以自行修改 14 | 3. 环境变量说明: 15 | 变量名(必须): WoChangYouCK 格式: 抓包沃畅游Authorization,填入Authorization值即可 16 | 单个CK塞多个账号时,以#或者@分隔开:CK1#CK2 17 | 注:本脚本可配合另外一个登录抓包脚本使用,自动填入CK 18 | 19 | wxpusher推送(非必填) 20 | 青龙变量:WoChangYouCK_WXPUSHER_TOKEN wxpusher推送的token 21 | 青龙变量:WoChangYouCK_WXPUSHER_TOPIC_ID wxpusher推送的topicId(主题ID,非UID) 22 | 网址:https://wxpusher.zjiecode.com/admin/main/topics/list 23 | """ 24 | import requests,re, random 25 | import json, os 26 | import time 27 | from sys import stdout 28 | 29 | 30 | 31 | 32 | WXPUSHER_TOKEN = '' # wxpusher推送的token 33 | WXPUSHER_TOPIC_ID = '' # wxpusher推送的topicId 34 | WXPUSHER_CONTENT_TYPE = 2 # wxpusher推送的样式,1表示文字 2表示html(只发送body标签内部的数据即可,不包括body标签),默认为2 35 | # wxpusher消息推送 36 | def wxpusher(title: str, content: str) -> None: 37 | """ 38 | 使用微信的wxpusher推送 39 | """ 40 | if not WXPUSHER_TOKEN or not WXPUSHER_TOPIC_ID: 41 | print("wxpusher 服务的 token 或者 topicId 未设置!!\n取消推送") 42 | return 43 | print("wxpusher 服务启动") 44 | 45 | url = f"https://wxpusher.zjiecode.com/api/send/message" 46 | headers = {"Content-Type": "application/json;charset=utf-8"} 47 | contentType = 2 48 | if not WXPUSHER_CONTENT_TYPE: 49 | contentType = 2 50 | else: 51 | contentType = WXPUSHER_CONTENT_TYPE 52 | if contentType == 2: 53 | content = content.replace("\n", "
") 54 | data = { 55 | "appToken":f"{WXPUSHER_TOKEN}", 56 | "content":f"{content}", 57 | "summary":f"{title}", 58 | "contentType":contentType, 59 | "topicIds":[ 60 | f'{WXPUSHER_TOPIC_ID}' 61 | ], 62 | "verifyPay":False 63 | } 64 | response = requests.post( 65 | url=url, data=json.dumps(data), headers=headers, timeout=15 66 | ).json() 67 | 68 | if response["code"] == 1000: 69 | print("wxpusher推送成功!") 70 | else: 71 | print("wxpusher推送失败!") 72 | print(f"wxpusher推送出错响应内容:{response}" ) 73 | 74 | 75 | ql_auth_path = '/ql/data/config/auth.json' 76 | ql_config_path = '/ql/data/config/config.sh' 77 | #判断环境变量 78 | flag = 'new' 79 | if not os.path.exists(ql_auth_path): 80 | ql_auth_path = '/ql/config/auth.json' 81 | ql_config_path = '/ql/config/config.sh' 82 | if not os.path.exists(ql_config_path): 83 | ql_config_path = '/ql/config/config.js' 84 | flag = 'old' 85 | # ql_auth_path = r'D:\Docker\ql\config\auth.json' 86 | ql_url = 'http://localhost:5600' 87 | 88 | 89 | def __get_token() -> str or None: 90 | with open(ql_auth_path, 'r', encoding='utf-8') as f: 91 | j_data = json.load(f) 92 | return j_data.get('token') 93 | 94 | 95 | def __get__headers() -> dict: 96 | headers = { 97 | 'Accept': 'application/json', 98 | 'Content-Type': 'application/json;charset=UTF-8', 99 | 'Authorization': 'Bearer ' + __get_token() 100 | } 101 | return headers 102 | 103 | # 封装读取环境变量的方法 104 | def get_cookie(key, default="", output=True): 105 | def no_read(): 106 | if output: 107 | print_now(f"未填写环境变量 {key} 请添加") 108 | return default 109 | return get_cookie_data(key) if get_cookie_data(key) else no_read() 110 | 111 | #获取ck 112 | def get_cookie_data(name): 113 | ck_list = [] 114 | remarks_list = [] 115 | cookie = None 116 | cookies = get_config_and_envs(name) 117 | for ck in cookies: 118 | data_temp = {} 119 | if ck["name"] != name: 120 | continue 121 | if ck.get('status') == 0: 122 | # ck_list.append(ck.get('value')) 123 | # 直接添加CK 124 | ck_list.append(ck) 125 | if len(ck_list) < 1: 126 | print('变量{}共配置{}条CK,请添加环境变量,或查看环境变量状态'.format(name,len(ck_list))) 127 | return ck_list 128 | 129 | # 修改print方法 避免某些环境下python执行print 不会去刷新缓存区导致信息第一时间不及时输出 130 | def print_now(content): 131 | print(content) 132 | stdout.flush() 133 | 134 | 135 | # 查询环境变量 136 | def get_envs(name: str = None) -> list: 137 | params = { 138 | 't': int(time.time() * 1000) 139 | } 140 | if name is not None: 141 | params['searchValue'] = name 142 | res = requests.get(ql_url + '/api/envs', headers=__get__headers(), params=params) 143 | j_data = res.json() 144 | if j_data['code'] == 200: 145 | return j_data['data'] 146 | return [] 147 | 148 | 149 | # 查询环境变量+config.sh变量 150 | def get_config_and_envs(name: str = None) -> list: 151 | params = { 152 | 't': int(time.time() * 1000) 153 | } 154 | #返回的数据data 155 | data = [] 156 | if name is not None: 157 | params['searchValue'] = name 158 | res = requests.get(ql_url + '/api/envs', headers=__get__headers(), params=params) 159 | j_data = res.json() 160 | if j_data['code'] == 200: 161 | data = j_data['data'] 162 | with open(ql_config_path, 'r', encoding='utf-8') as f: 163 | while True: 164 | # Get next line from file 165 | line = f.readline() 166 | # If line is empty then end of file reached 167 | if not line : 168 | break; 169 | #print(line.strip()) 170 | exportinfo = line.strip().replace("\"","").replace("\'","") 171 | #去除注释#行 172 | rm_str_list = re.findall(r'^#(.+?)', exportinfo,re.DOTALL) 173 | #print('rm_str_list数据:{}'.format(rm_str_list)) 174 | exportinfolist = [] 175 | if len(rm_str_list) == 1: 176 | exportinfo = "" 177 | #list_all = re.findall(r'export[ ](.+?)', exportinfo,re.DOTALL) 178 | #print('exportinfo数据:{}'.format(exportinfo)) 179 | #以export分隔,字符前面新增标记作为数组0,数组1为后面需要的数据 180 | list_all = ("标记"+exportinfo.replace(" ","").replace(" ","")).split("export") 181 | #print('list_all数据:{}'.format(list_all)) 182 | if len(list_all) > 1: 183 | #以=分割,查找需要的环境名字 184 | tmp = list_all[1].split("=") 185 | if len(tmp) > 1: 186 | 187 | info = tmp[0] 188 | if name in info: 189 | #print('需要查询的环境数据:{}'.format(tmp)) 190 | data_tmp = [] 191 | data_json = { 192 | 'id': None, 193 | 'value': tmp[1], 194 | 'status': 0, 195 | 'name': name, 196 | 'remarks': "", 197 | 'position': None, 198 | 'timestamp': int(time.time()*1000), 199 | 'created': int(time.time()*1000) 200 | } 201 | if flag == 'old': 202 | data_json = { 203 | '_id': None, 204 | 'value': tmp[1], 205 | 'status': 0, 206 | 'name': name, 207 | 'remarks': "", 208 | 'position': None, 209 | 'timestamp': int(time.time()*1000), 210 | 'created': int(time.time()*1000) 211 | } 212 | #print('需要的数据:{}'.format(data_json)) 213 | data.append(data_json) 214 | #print('第二次配置数据:{}'.format(data)) 215 | return data 216 | 217 | 218 | # 新增环境变量 219 | def post_envs(name: str, value: str, remarks: str = None) -> list: 220 | params = { 221 | 't': int(time.time() * 1000) 222 | } 223 | data = [{ 224 | 'name': name, 225 | 'value': value 226 | }] 227 | if remarks is not None: 228 | data[0]['remarks'] = remarks 229 | res = requests.post(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 230 | j_data = res.json() 231 | if j_data['code'] == 200: 232 | return j_data['data'] 233 | return [] 234 | 235 | 236 | # 修改环境变量1,青龙2.11.0以下版本(不含2.11.0) 237 | def put_envs_old(_id: str, name: str, value: str, remarks: str = None) -> bool: 238 | params = { 239 | 't': int(time.time() * 1000) 240 | } 241 | 242 | data = { 243 | 'name': name, 244 | 'value': value, 245 | '_id': _id 246 | } 247 | 248 | if remarks is not None: 249 | data['remarks'] = remarks 250 | res = requests.put(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 251 | j_data = res.json() 252 | if j_data['code'] == 200: 253 | return True 254 | return False 255 | 256 | 257 | # 修改环境变量2,青龙2.11.0以上版本(含2.11.0) 258 | def put_envs_new(_id: int, name: str, value: str, remarks: str = None) -> bool: 259 | params = { 260 | 't': int(time.time() * 1000) 261 | } 262 | 263 | data = { 264 | 'name': name, 265 | 'value': value, 266 | 'id': _id 267 | } 268 | 269 | if remarks is not None: 270 | data['remarks'] = remarks 271 | res = requests.put(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 272 | j_data = res.json() 273 | if j_data['code'] == 200: 274 | return True 275 | return False 276 | 277 | 278 | # 禁用环境变量 279 | def disable_env(_id: str) -> bool: 280 | params = { 281 | 't': int(time.time() * 1000) 282 | } 283 | data = [_id] 284 | res = requests.put(ql_url + '/api/envs/disable', headers=__get__headers(), params=params, json=data) 285 | j_data = res.json() 286 | if j_data['code'] == 200: 287 | return True 288 | return False 289 | 290 | 291 | # 启用环境变量 292 | def enable_env(_id: str) -> bool: 293 | params = { 294 | 't': int(time.time() * 1000) 295 | } 296 | data = [_id] 297 | res = requests.put(ql_url + '/api/envs/enable', headers=__get__headers(), params=params, json=data) 298 | j_data = res.json() 299 | if j_data['code'] == 200: 300 | return True 301 | return False 302 | 303 | # 删除环境变量 304 | def delete_env(_id: str) -> bool: 305 | params = { 306 | 't': int(time.time() * 1000) 307 | } 308 | data = [_id] 309 | res = requests.delete(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 310 | j_data = res.json() 311 | if j_data['code'] == 200: 312 | return True 313 | return False 314 | 315 | 316 | 317 | # WXPUSHER_TOKEN 318 | WoChangYouCK_WXPUSHER_TOKEN_temp = get_cookie("WoChangYouCK_WXPUSHER_TOKEN") 319 | if WoChangYouCK_WXPUSHER_TOKEN_temp != "" and len(WoChangYouCK_WXPUSHER_TOKEN_temp)>0: 320 | WXPUSHER_TOKEN = WoChangYouCK_WXPUSHER_TOKEN_temp[0]["value"] 321 | 322 | # WXPUSHER_TOPIC_ID 323 | WoChangYouCK_WXPUSHER_TOPIC_ID_temp = get_cookie("WoChangYouCK_WXPUSHER_TOPIC_ID") 324 | if WoChangYouCK_WXPUSHER_TOPIC_ID_temp != "" and len(WoChangYouCK_WXPUSHER_TOPIC_ID_temp)>0: 325 | WXPUSHER_TOPIC_ID = WoChangYouCK_WXPUSHER_TOPIC_ID_temp[0]["value"] 326 | 327 | msg = "" 328 | isDebugger = False 329 | 330 | 331 | 332 | 333 | def get_member_info(ck): 334 | authorization = ck["value"] 335 | remarks = ck["remarks"] 336 | headers = { 337 | 'Host': 'game.wostore.cn', 338 | 'Authorization': authorization, 339 | 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/109.0.0.0', 340 | 'Content-Type': 'application/json;charset=utf-8', 341 | 'accept': 'application/json', 342 | 'channelId': 'GAMELTAPP_90005', 343 | 'device': '8', 344 | 'Origin': 'https://web.wostore.cn', 345 | 'Sec-Fetch-Site': 'same-site', 346 | 'Sec-Fetch-Mode': 'cors', 347 | 'Sec-Fetch-Dest': 'empty', 348 | 'Referer': 'https://web.wostore.cn/', 349 | 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 350 | } 351 | 352 | try: 353 | response = requests.get('https://game.wostore.cn/api/app/user/v3/getMemberInfo', headers=headers) 354 | # print(response.text) 355 | # print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】获取个人信息发送成功,响应:{response.json()}") 356 | except Exception as e: 357 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】获取个人信息发送失败,错误信息:{e}") 358 | 359 | 360 | 361 | def send_speed_add(ck): 362 | global msg 363 | authorization = ck["value"] 364 | remarks = ck["remarks"] 365 | url = 'https://game.wostore.cn/api/app/user/qosSpeedUp/add' 366 | headers = { 367 | 'authorization': authorization, 368 | 'Content-Type': 'application/json;charset=utf-8', 369 | "versioncode": "4016", 370 | "channelid": "GAMELTJS_10001", 371 | "device": "1", 372 | "rnversion": "undefined", 373 | "Host": "game.wostore.cn", 374 | # "User-Agent": "okhttp/4.9.2", 375 | 'User-Agent': 'ChinaUnicom.x CFNetwork iOS/15.0.1 unicom{version:iphone_c@10.0700}', 376 | "Accept-Encoding":"gzip" 377 | } 378 | data = { 379 | 'firstTime': '00:00-23:30', 380 | 'secondTime': '23:30-23:59' 381 | } 382 | 383 | try: 384 | response = requests.post(url, headers=headers, data=json.dumps(data)) 385 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】重置加速时间,响应:{response.json()}") 386 | msg += f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】重置加速时间,响应:{response.json()}\n" 387 | except Exception as e: 388 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】 重置加速时间发送失败,错误信息:{e}") 389 | msg += f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】重置加速时间发送失败,错误信息:{e}\n" 390 | 391 | 392 | def send_speed_start(ck): 393 | global msg 394 | authorization = ck["value"] 395 | remarks = ck["remarks"] 396 | headers = { 397 | 'Host': 'game.wostore.cn', 398 | 'channelid': 'GAMELTJS_10001', 399 | 'Accept': 'application/json', 400 | 'Authorization': authorization, 401 | 'rnversion': 'undefined', 402 | 'Accept-Language': 'zh-CN,zh-Hans;q=0.9', 403 | 'Content-Type': 'application/json;charset=utf-8', 404 | 'versioncode': '4014', 405 | # 'User-Agent': 'GloudGame/68 CFNetwork/1312 Darwin/21.0.0', 406 | 'User-Agent': 'ChinaUnicom.x CFNetwork iOS/15.0.1 unicom{version:iphone_c@10.0700}', 407 | 'device': '2', 408 | } 409 | 410 | json_data = { 411 | 'channelId': 'GAMELTJS_10001', 412 | 'privateIp': '10.117.226.153', 413 | } 414 | 415 | try: 416 | response = requests.post('https://game.wostore.cn/api/app/user/v3/qos/start', headers=headers, json=json_data) 417 | # print(response.text) 418 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】立即加速,响应:{response.json()}") 419 | msg += f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】立即加速,响应:{response.json()}\n\n" 420 | except Exception as e: 421 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】加速发送失败,错误信息:{e}") 422 | msg += f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】加速发送失败,错误信息:{e}\n\n" 423 | 424 | 425 | if __name__ == "__main__": 426 | l = [] 427 | ck_list = [] 428 | cklist = get_cookie("WoChangYouCK") 429 | for i in range(len(cklist)): 430 | 431 | #多账号以#分割开的ck 432 | split1 = cklist[i]['value'].split("#") 433 | #多账号以@分割开的ck 434 | split2 = cklist[i]['value'].split("@") 435 | #多账号以换行\n分割开的ck 436 | split3 = cklist[i]['value'].split("\n") 437 | remarks = cklist[i].get("remarks",None) 438 | if len(split1)>1: 439 | for j in range(len(split1)): 440 | info = {} 441 | info['value'] = split1[j] 442 | if remarks is None: 443 | info['remarks'] = split1[j] 444 | else: 445 | info['remarks'] = remarks 446 | ck_list.append(info) 447 | elif len(split2)>1: 448 | for j in range(len(split2)): 449 | info = {} 450 | info['value'] = split2[j] 451 | if remarks is None: 452 | info['remarks'] = split2[j] 453 | else: 454 | info['remarks'] = remarks 455 | ck_list.append(info) 456 | elif len(split3)>1: 457 | for j in range(len(split3)): 458 | info = {} 459 | info['value'] = split3[j] 460 | if remarks is None: 461 | info['remarks'] = split3[j] 462 | else: 463 | info['remarks'] = remarks 464 | ck_list.append(info) 465 | else: 466 | if remarks is None: 467 | cklist[i]['remarks'] = cklist[i]['value'] 468 | ck_list.append(cklist[i]) 469 | if len(ck_list)<1: 470 | print_now('未添加CK,退出程序~') 471 | exit(0) 472 | 473 | 474 | 475 | for i in range(len(ck_list)): 476 | ck = ck_list[i] 477 | print_now(f'开始执行第 {i+1} 个账号') 478 | if ck is None: 479 | print_now("当前账号未填写 跳过\n") 480 | continue 481 | get_member_info(ck) 482 | send_speed_add(ck) 483 | send_speed_start(ck) 484 | #解决随机时间问题 485 | ran_time = random.randint(3, 5) 486 | if isDebugger == False and i != (len(ck_list)-1): 487 | print_now(f"随机休眠{ran_time}秒,执行下一个账号操作\n\n") 488 | time.sleep(ran_time) 489 | print_now("\n") 490 | 491 | print_now("提示:\n测试请在第二天凌晨12点30分后,使用5g信号再测试,部分地区4g不生效。\n“鉴权失败”只代表未开通联通加速会员(非必须开通),非代表破限速失败,请自行测试\n\n") 492 | msg += f'提示:\n测试请在第二天凌晨12点30分后,使用5g信号再测试,部分地区4g不生效。\n“鉴权失败”只代表未开通联通加速会员(非必须开通),非代表破限速失败,请自行测试\n\n' 493 | if WXPUSHER_TOKEN != "" and WXPUSHER_TOPIC_ID != "" and msg != "": 494 | wxpusher("沃畅游破限速",msg) 495 | -------------------------------------------------------------------------------- /wochangyou_token.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@yuanter https://github.com/yuanter by院长 5 | # @Time : 2023/9/6 18:25 6 | # cron "1 1 1 1 1" script-path=xxx.py,tag=匹配cron用 7 | # const $ = new Env('沃畅游短信登录'); 8 | # ------------------------------- 9 | 10 | """ 11 | 沃畅游短信登录 获取access_token环境并自动新增或者更新青龙环境 12 | 青龙变量:WoChangYouCK_Phone 手机号码 13 | 青龙变量:WoChangYouCK_Code 验证码 14 | wxpusher推送(非必填) 15 | 青龙变量:WoChangYouCK_WXPUSHER_TOKEN wxpusher推送的token 16 | 青龙变量:WoChangYouCK_WXPUSHER_TOPIC_ID wxpusher推送的topicId 17 | 18 | 步骤: 19 | 1. 先填写变量WoChangYouCK_Phone(手机号),然后执行本脚本 20 | 2. 获取到验证码后,再填入变量WoChangYouCK_Code(验证码),再次执行脚本 21 | 22 | 请注意: 23 | 变量WoChangYouCK_Code不存在时,会执行发送验证码操作 24 | 变量WoChangYouCK_Code存在时,会自动登录并生成青龙环境WoChangYouCK,同时会在青龙环境备注上手机号。或者自己根据日志自行复制access_token值 25 | 26 | """ 27 | import requests,re 28 | import json, os 29 | import time 30 | from sys import stdout 31 | import base64 32 | 33 | WXPUSHER_TOKEN = '' # wxpusher推送的token 34 | WXPUSHER_TOPIC_ID = '' # wxpusher推送的topicId 35 | WXPUSHER_CONTENT_TYPE = 2 # wxpusher推送的样式,1表示文字 2表示html(只发送body标签内部的数据即可,不包括body标签),默认为2 36 | # wxpusher消息推送 37 | def wxpusher(title: str, content: str) -> None: 38 | """ 39 | 使用微信的wxpusher推送 40 | """ 41 | if not WXPUSHER_TOKEN or not WXPUSHER_TOPIC_ID: 42 | print("wxpusher 服务的 token 或者 topicId 未设置!!\n取消推送") 43 | return 44 | print("wxpusher 服务启动") 45 | 46 | url = f"https://wxpusher.zjiecode.com/api/send/message" 47 | headers = {"Content-Type": "application/json;charset=utf-8"} 48 | contentType = 2 49 | if not WXPUSHER_CONTENT_TYPE: 50 | contentType = 2 51 | else: 52 | contentType = WXPUSHER_CONTENT_TYPE 53 | if contentType == 2: 54 | content = content.replace("\n", "
") 55 | data = { 56 | "appToken":f"{WXPUSHER_TOKEN}", 57 | "content":f"{content}", 58 | "summary":f"{title}", 59 | "contentType":contentType, 60 | "topicIds":[ 61 | f'{WXPUSHER_TOPIC_ID}' 62 | ], 63 | "verifyPay":False 64 | } 65 | response = requests.post( 66 | url=url, data=json.dumps(data), headers=headers, timeout=15 67 | ).json() 68 | 69 | if response["code"] == 1000: 70 | print("wxpusher推送成功!") 71 | else: 72 | print("wxpusher推送失败!") 73 | print(f"wxpusher推送出错响应内容:{response}" ) 74 | 75 | 76 | ql_auth_path = '/ql/data/config/auth.json' 77 | ql_config_path = '/ql/data/config/config.sh' 78 | #判断环境变量 79 | flag = 'new' 80 | if not os.path.exists(ql_auth_path): 81 | ql_auth_path = '/ql/config/auth.json' 82 | ql_config_path = '/ql/config/config.sh' 83 | if not os.path.exists(ql_config_path): 84 | ql_config_path = '/ql/config/config.js' 85 | flag = 'old' 86 | # ql_auth_path = r'D:\Docker\ql\config\auth.json' 87 | ql_url = 'http://localhost:5600' 88 | 89 | 90 | def __get_token() -> str or None: 91 | with open(ql_auth_path, 'r', encoding='utf-8') as f: 92 | j_data = json.load(f) 93 | return j_data.get('token') 94 | 95 | 96 | def __get__headers() -> dict: 97 | headers = { 98 | 'Accept': 'application/json', 99 | 'Content-Type': 'application/json;charset=UTF-8', 100 | 'Authorization': 'Bearer ' + __get_token() 101 | } 102 | return headers 103 | 104 | # 封装读取环境变量的方法 105 | def get_cookie(key, default="", output=True): 106 | def no_read(): 107 | if output: 108 | print_now(f"未填写环境变量 {key} 请添加") 109 | return default 110 | return get_cookie_data(key) if get_cookie_data(key) else no_read() 111 | 112 | #获取ck 113 | def get_cookie_data(name): 114 | ck_list = [] 115 | remarks_list = [] 116 | cookie = None 117 | cookies = get_config_and_envs(name) 118 | for ck in cookies: 119 | data_temp = {} 120 | if ck["name"] != name: 121 | continue 122 | if ck.get('status') == 0: 123 | # ck_list.append(ck.get('value')) 124 | # 直接添加CK 125 | ck_list.append(ck) 126 | if len(ck_list) < 1: 127 | print('变量{}共配置{}条CK,请添加环境变量,或查看环境变量状态'.format(name,len(ck_list))) 128 | return ck_list 129 | 130 | # 修改print方法 避免某些环境下python执行print 不会去刷新缓存区导致信息第一时间不及时输出 131 | def print_now(content): 132 | print(content) 133 | stdout.flush() 134 | 135 | 136 | # 查询环境变量 137 | def get_envs(name: str = None) -> list: 138 | params = { 139 | 't': int(time.time() * 1000) 140 | } 141 | if name is not None: 142 | params['searchValue'] = name 143 | res = requests.get(ql_url + '/api/envs', headers=__get__headers(), params=params) 144 | j_data = res.json() 145 | if j_data['code'] == 200: 146 | return j_data['data'] 147 | return [] 148 | 149 | 150 | # 查询环境变量+config.sh变量 151 | def get_config_and_envs(name: str = None) -> list: 152 | params = { 153 | 't': int(time.time() * 1000) 154 | } 155 | #返回的数据data 156 | data = [] 157 | if name is not None: 158 | params['searchValue'] = name 159 | res = requests.get(ql_url + '/api/envs', headers=__get__headers(), params=params) 160 | j_data = res.json() 161 | if j_data['code'] == 200: 162 | data = j_data['data'] 163 | with open(ql_config_path, 'r', encoding='utf-8') as f: 164 | while True: 165 | # Get next line from file 166 | line = f.readline() 167 | # If line is empty then end of file reached 168 | if not line : 169 | break; 170 | #print(line.strip()) 171 | exportinfo = line.strip().replace("\"","").replace("\'","") 172 | #去除注释#行 173 | rm_str_list = re.findall(r'^#(.+?)', exportinfo,re.DOTALL) 174 | #print('rm_str_list数据:{}'.format(rm_str_list)) 175 | exportinfolist = [] 176 | if len(rm_str_list) == 1: 177 | exportinfo = "" 178 | #list_all = re.findall(r'export[ ](.+?)', exportinfo,re.DOTALL) 179 | #print('exportinfo数据:{}'.format(exportinfo)) 180 | #以export分隔,字符前面新增标记作为数组0,数组1为后面需要的数据 181 | list_all = ("标记"+exportinfo.replace(" ","").replace(" ","")).split("export") 182 | #print('list_all数据:{}'.format(list_all)) 183 | if len(list_all) > 1: 184 | #以=分割,查找需要的环境名字 185 | tmp = list_all[1].split("=") 186 | if len(tmp) > 1: 187 | 188 | info = tmp[0] 189 | if name in info: 190 | #print('需要查询的环境数据:{}'.format(tmp)) 191 | data_tmp = [] 192 | data_json = { 193 | 'id': None, 194 | 'value': tmp[1], 195 | 'status': 0, 196 | 'name': name, 197 | 'remarks': "", 198 | 'position': None, 199 | 'timestamp': int(time.time()*1000), 200 | 'created': int(time.time()*1000) 201 | } 202 | if flag == 'old': 203 | data_json = { 204 | '_id': None, 205 | 'value': tmp[1], 206 | 'status': 0, 207 | 'name': name, 208 | 'remarks': "", 209 | 'position': None, 210 | 'timestamp': int(time.time()*1000), 211 | 'created': int(time.time()*1000) 212 | } 213 | #print('需要的数据:{}'.format(data_json)) 214 | data.append(data_json) 215 | #print('第二次配置数据:{}'.format(data)) 216 | return data 217 | 218 | 219 | # 新增环境变量 220 | def post_envs(name: str, value: str, remarks: str = None) -> list: 221 | params = { 222 | 't': int(time.time() * 1000) 223 | } 224 | data = [{ 225 | 'name': name, 226 | 'value': value 227 | }] 228 | if remarks is not None: 229 | data[0]['remarks'] = remarks 230 | res = requests.post(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 231 | j_data = res.json() 232 | if j_data['code'] == 200: 233 | return j_data['data'] 234 | return [] 235 | 236 | 237 | # 修改环境变量1,青龙2.11.0以下版本(不含2.11.0) 238 | def put_envs_old(_id: str, name: str, value: str, remarks: str = None) -> bool: 239 | params = { 240 | 't': int(time.time() * 1000) 241 | } 242 | 243 | data = { 244 | 'name': name, 245 | 'value': value, 246 | '_id': _id 247 | } 248 | 249 | if remarks is not None: 250 | data['remarks'] = remarks 251 | res = requests.put(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 252 | j_data = res.json() 253 | if j_data['code'] == 200: 254 | return True 255 | return False 256 | 257 | 258 | # 修改环境变量2,青龙2.11.0以上版本(含2.11.0) 259 | def put_envs_new(_id: int, name: str, value: str, remarks: str = None) -> bool: 260 | params = { 261 | 't': int(time.time() * 1000) 262 | } 263 | 264 | data = { 265 | 'name': name, 266 | 'value': value, 267 | 'id': _id 268 | } 269 | 270 | if remarks is not None: 271 | data['remarks'] = remarks 272 | res = requests.put(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 273 | j_data = res.json() 274 | if j_data['code'] == 200: 275 | return True 276 | return False 277 | 278 | 279 | # 禁用环境变量 280 | def disable_env(_id: str) -> bool: 281 | params = { 282 | 't': int(time.time() * 1000) 283 | } 284 | data = [_id] 285 | res = requests.put(ql_url + '/api/envs/disable', headers=__get__headers(), params=params, json=data) 286 | j_data = res.json() 287 | if j_data['code'] == 200: 288 | return True 289 | return False 290 | 291 | 292 | # 启用环境变量 293 | def enable_env(_id: str) -> bool: 294 | params = { 295 | 't': int(time.time() * 1000) 296 | } 297 | data = [_id] 298 | res = requests.put(ql_url + '/api/envs/enable', headers=__get__headers(), params=params, json=data) 299 | j_data = res.json() 300 | if j_data['code'] == 200: 301 | return True 302 | return False 303 | 304 | # 删除环境变量 305 | def delete_env(_id: str) -> bool: 306 | params = { 307 | 't': int(time.time() * 1000) 308 | } 309 | data = [_id] 310 | res = requests.delete(ql_url + '/api/envs', headers=__get__headers(), params=params, json=data) 311 | j_data = res.json() 312 | if j_data['code'] == 200: 313 | return True 314 | return False 315 | 316 | 317 | 318 | 319 | def base64_encode(data): 320 | message_bytes = data.encode('utf-8') # 将字符串转换为字节型 321 | base64_data = base64.b64encode(message_bytes) #进行加密 322 | # base64_data = base64.b64encode(data) # 进行加密 323 | # print(base64_data,type(base64_data),len(base64_data)) 324 | base64_data = base64_data.decode('utf-8') 325 | return base64_data 326 | 327 | def base64_decode(data): 328 | #base64_bytes = data.encode('utf-8') 329 | message_bytes = base64.b64decode(data) 330 | message = message_bytes.decode('utf-8') 331 | return message 332 | 333 | 334 | 335 | # WXPUSHER_TOKEN 336 | WoChangYouCK_WXPUSHER_TOKEN_temp = get_cookie("WoChangYouCK_WXPUSHER_TOKEN") 337 | if WoChangYouCK_WXPUSHER_TOKEN_temp != "" and len(WoChangYouCK_WXPUSHER_TOKEN_temp)>0: 338 | WXPUSHER_TOKEN = WoChangYouCK_WXPUSHER_TOKEN_temp[0]["value"] 339 | 340 | # WXPUSHER_TOPIC_ID 341 | WoChangYouCK_WXPUSHER_TOPIC_ID_temp = get_cookie("WoChangYouCK_WXPUSHER_TOPIC_ID") 342 | if WoChangYouCK_WXPUSHER_TOPIC_ID_temp != "" and len(WoChangYouCK_WXPUSHER_TOPIC_ID_temp)>0: 343 | WXPUSHER_TOPIC_ID = WoChangYouCK_WXPUSHER_TOPIC_ID_temp[0]["value"] 344 | 345 | 346 | phone = "" 347 | msg = "" 348 | 349 | 350 | def send_post(ck): 351 | phone = ck["value"] 352 | phone = base64_encode(phone) 353 | remarks = ck["remarks"] 354 | url = 'https://game.wostore.cn/api/app/user/v3/getVerificationCode' 355 | headers = { 356 | 'authorization': '', 357 | 'Content-Type': 'application/json;charset=utf-8', 358 | "versioncode": "4016", 359 | "channelid": "GAMELTJS_10001", 360 | "device": "1", 361 | "rnversion": "0", 362 | "Host": "game.wostore.cn", 363 | "User-Agent": "okhttp/4.9.2", 364 | "Accept-Encoding":"gzip" 365 | } 366 | data = {"phone":phone } 367 | 368 | try: 369 | response = requests.post(url, headers=headers, data=json.dumps(data)) 370 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】 短信发送成功,响应:{response.json()}") 371 | except Exception as e: 372 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{remarks}】 短信发送失败,错误信息:{e}") 373 | 374 | 375 | def login_post(cookieKey): 376 | global phone 377 | global msg 378 | code = cookieKey["value"] 379 | code = base64_encode(code) 380 | new_phone = base64_encode(phone) 381 | url = 'https://game.wostore.cn/api/app/user/v3/login' 382 | headers = { 383 | 'authorization': '', 384 | 'Content-Type': 'application/json;charset=utf-8', 385 | "versioncode": "4016", 386 | "channelid": "GAMELTJS_10001", 387 | "device": "1", 388 | "rnversion": "0", 389 | "Host": "game.wostore.cn", 390 | "User-Agent": "okhttp/4.9.2", 391 | "Accept-Encoding":"gzip" 392 | } 393 | data = {"identityType":"phoneVerificationCode","identifier": new_phone,"code":code} 394 | 395 | try: 396 | response = requests.post(url, headers=headers, data=json.dumps(data)) 397 | text = response.json() 398 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{phone}】 登录成功,响应:{text}\n") 399 | if text["code"] == 200: 400 | data = text["data"] 401 | access_token = data["access_token"] 402 | print_now(f'成功获取access_token: {access_token} 请复制保存使用\n') 403 | # 获取沃畅游CK 404 | cklist_temp = get_cookie("WoChangYouCK") 405 | flag_temp = False 406 | if len(cklist_temp)>0: 407 | for i in range(len(cklist_temp)): 408 | ck_temp = cklist_temp[i] 409 | if ck_temp["remarks"] == phone: 410 | flag_temp = True 411 | put_flag = True 412 | if flag == "old": 413 | _id = ck_temp.get("_id",None) 414 | if not _id: 415 | _id = ck_temp["id"] 416 | put_flag = put_envs_new(_id, ck_temp['name'], access_token, phone) 417 | else: 418 | put_flag = put_envs_old(_id, ck_temp['name'], access_token, phone) 419 | # print("进入旧版本青龙禁用方法") 420 | # disable_env(_id) 421 | # delete_env(_id) 422 | elif flag == "new": 423 | put_flag = put_envs_new(ck_temp["id"], ck_temp['name'], access_token, phone) 424 | # print("进入新版本青龙禁用方法") 425 | # disable_env(ck_temp["id"]) 426 | # delete_env(ck_temp["id"]) 427 | 428 | if put_flag: 429 | print_now(f"账号【{phone}】自动更新access_token至青龙环境:WoChangYouCK 备注为:{phone}") 430 | msg += f"账号【{phone}】自动更新access_token至青龙环境:WoChangYouCK 备注为:{phone}\n\n" 431 | else: 432 | print_now(f"账号【{phone}】自动更新access_token至青龙环境:失败") 433 | msg += f"账号【{phone}】自动更新access_token至青龙环境:失败\n\n" 434 | if not flag_temp: 435 | post_envs("WoChangYouCK", access_token, phone) 436 | print_now(f"账号【{phone}】自动新增access_token至青龙环境:WoChangYouCK 备注为:{phone}") 437 | msg += f"账号【{phone}】自动新增access_token至青龙环境:WoChangYouCK 备注为:{phone}\n\n" 438 | 439 | 440 | except Exception as e: 441 | print_now(f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{phone}】 登录失败,错误信息:{e}") 442 | msg += f"【{time.strftime('%Y-%m-%d %H:%M:%S')}】 ---- 【{phone}】 登录失败,错误信息:{e}\n\n" 443 | 444 | 445 | 446 | 447 | 448 | # print_now(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 脚本已启动,默认每隔15分钟发送一次POST请求\n") 449 | 450 | if __name__ == "__main__": 451 | l = [] 452 | ck_list = [] 453 | cklist = get_cookie("WoChangYouCK_Phone") 454 | for i in range(len(cklist)): 455 | info = {} 456 | #多账号以#分割开的ck 457 | split1 = cklist[i]['value'].split("#") 458 | #多账号以@分割开的ck 459 | split2 = cklist[i]['value'].split("@") 460 | #多账号以换行\n分割开的ck 461 | split3 = cklist[i]['value'].split("\n") 462 | remarks = cklist[i].get("remarks",None) 463 | if len(split1)>1: 464 | for j in range(len(split1)): 465 | info['value'] = split1[j] 466 | if remarks is None: 467 | info['remarks'] = split1[j] 468 | else: 469 | info['remarks'] = split1[j].split("&")[0] 470 | ck_list.append(info) 471 | elif len(split2)>1: 472 | for j in range(len(split2)): 473 | info['value'] = split2[j] 474 | if remarks is None: 475 | info['remarks'] = split2[j] 476 | else: 477 | info['remarks'] = split2[j].split("&")[0] 478 | ck_list.append(info) 479 | elif len(split3)>1: 480 | for j in range(len(split3)): 481 | info['value'] = split3[j] 482 | 483 | if remarks is None: 484 | info['remarks'] = split3[j] 485 | else: 486 | info['remarks'] = split3[j].split("&")[0] 487 | ck_list.append(info) 488 | else: 489 | if remarks is None or remarks == "": 490 | cklist[i]['remarks'] = cklist[i]['value'] 491 | ck_list.append(cklist[i]) 492 | if len(ck_list)<1: 493 | print_now('未添加CK,退出程序~') 494 | exit(0) 495 | 496 | 497 | 498 | for i in range(len(ck_list)): 499 | ck = ck_list[i] 500 | phone = ck.get("value",None) 501 | if phone is None: 502 | print_now("当前账号未填写 跳过\n") 503 | continue 504 | print_now(f'开始执行第 {i+1} 个账号:{phone}') 505 | code_list = get_cookie("WoChangYouCK_Code") 506 | if len(code_list)>0: 507 | login_post(code_list[0]) 508 | else: 509 | send_post(ck) 510 | if WXPUSHER_TOKEN != "" and WXPUSHER_TOPIC_ID != "" and msg != "": 511 | wxpusher("沃畅游短信登录",msg) 512 | -------------------------------------------------------------------------------- /wyx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -- coding: utf-8 -- 3 | # ------------------------------- 4 | # @Author : github@limoruirui https://github.com/limoruirui 5 | # @Time : 19/5/2022 19:48 6 | # ------------------------------- 7 | """ 8 | 1.无忧行app签到 请低调使用 9 | 2.cookie获取方式 10 | 1.打开app-我的-任务中心 很多链接里(链接里 不是看headers)都有token 复制token的值填入环境变量即可 格式应该是 32位16进制数 11 | 2.有效期不懂 12 | 3.cookie食用方式:只要token的值 32位16进制数 青龙运行可新建并放入到环境变量 WXY_TOKEN 中 13 | """ 14 | from json import loads, dumps 15 | from base64 import b64decode, b64encode 16 | from hashlib import md5 as md5Encode 17 | from random import randint 18 | from os import environ, system 19 | from time import time 20 | 21 | try: 22 | from Crypto.Cipher import AES 23 | from requests import post 24 | except: 25 | print( 26 | "你还没有安装requests库和pycryptodome库 正在尝试自动安装 请在安装结束后重新执行此脚本\n若还是提示本条消息 请自行运行pip3 install requests和pip3 install pycryptodome或者在青龙的依赖管理里安装python的 requests 和 pycryptodome ") 27 | system("pip3 install pycryptodome") 28 | system("pip3 install requests") 29 | print("安装完成 脚本退出 请重新执行") 30 | exit(0) 31 | 32 | token = environ.get("WXY_TOKEN") if environ.get("WXY_TOKEN") else "" 33 | pushplus_token = environ.get("PUSH_PLUS_TOKEN") if environ.get("PUSH_PLUS_TOKEN") else "" 34 | tgbot_token = environ.get("TG_BOT_TOKEN") if environ.get("TG_BOT_TOKEN") else "" 35 | tg_userId = environ.get("TG_USER_ID") if environ.get("TG_USER_ID") else "" 36 | tg_push_api = environ.get("TG_API_HOST") if environ.get("TG_API_HOST") else "" 37 | if token == "": 38 | print("未填写token 请添加环境变量 WXY_TOKEN") 39 | exit(0) 40 | if len(token) != 32: 41 | print("填写的token不对 是一个32位16进制数") 42 | exit(0) 43 | 44 | BLOCK_SIZE = AES.block_size 45 | # 不足BLOCK_SIZE的补位(s可能是含中文,而中文字符utf-8编码占3个位置,gbk是2,所以需要以len(s.encode()),而不是len(s)计算补码) 46 | pad = lambda s: s + (BLOCK_SIZE - len(s.encode()) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s.encode()) % BLOCK_SIZE) 47 | # 去除补位 48 | unpad = lambda s: s[:-ord(s[len(s) - 1:])] 49 | 50 | 51 | class AESCipher: 52 | def __init__(self, secretkey: str): 53 | self.key = secretkey # 密钥 54 | # self.iv = secretkey[0:16] # 偏移量 55 | 56 | def encrypt(self, text): 57 | """ 58 | 加密 :先补位,再AES加密,后base64编码 59 | :param text: 需加密的明文 60 | :return: 61 | """ 62 | # text = pad(text) 包pycrypto的写法,加密函数可以接受str也可以接受bytess 63 | text = pad(text).encode() # 包pycryptodome 的加密函数不接受str 64 | cipher = AES.new(key=self.key.encode(), mode=AES.MODE_ECB) 65 | encrypted_text = cipher.encrypt(text) 66 | # 进行64位的编码,返回得到加密后的bytes,decode成字符串 67 | return b64encode(encrypted_text).decode('utf-8') 68 | 69 | def decrypt(self, encrypted_text): 70 | """ 71 | 解密 :偏移量为key[0:16];先base64解,再AES解密,后取消补位 72 | :param encrypted_text : 已经加密的密文 73 | :return: 74 | """ 75 | encrypted_text = b64decode(encrypted_text) 76 | cipher = AES.new(key=self.key.encode(), mode=AES.MODE_ECB) 77 | decrypted_text = cipher.decrypt(encrypted_text) 78 | return unpad(decrypted_text).decode('utf-8') 79 | 80 | 81 | class WYX: 82 | def __init__(self, token): 83 | self.token = token 84 | self.headers = { 85 | "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", 86 | "Referer": "https://cdn.jegotrip.com.cn/" 87 | } 88 | self.ge = "93EFE107DDE6DE51" 89 | self.he = "online_jego_h5" 90 | self.fe = "01" 91 | self.taskId = "" 92 | self.msg = "" 93 | 94 | def timestamp(self): 95 | return int(time() * 1000) 96 | 97 | def pushplus(self, title, content): 98 | url = "http://www.pushplus.plus/send" 99 | headers = { 100 | "Content-Type": "application/json" 101 | } 102 | data = { 103 | "token": pushplus_token, 104 | "title": title, 105 | "content": content 106 | } 107 | try: 108 | post(url, headers=headers, data=dumps(data)) 109 | except: 110 | print('推送失败') 111 | 112 | def tgpush(self, content): 113 | url = f"https://api.telegram.org/bot{tgbot_token}/sendMessage" 114 | if tg_push_api != "": 115 | url = f"https://{tg_push_api}/bot{tgbot_token}/sendMessage" 116 | headers = {'Content-Type': 'application/x-www-form-urlencoded'} 117 | data = {'chat_id': str(tg_userId), 'text': content, 'disable_web_page_preview': 'true'} 118 | try: 119 | post(url, headers=headers, data=data, timeout=10) 120 | except: 121 | print('推送失败') 122 | 123 | def push(self, msg): 124 | if pushplus_token != "": 125 | self.pushplus("无忧行签到", msg) 126 | if tgbot_token != "" and tg_userId != "": 127 | self.tgpush(f"无忧行签到\n{msg}") 128 | 129 | def md5(self, text): 130 | m = md5Encode(text.encode(encoding='utf-8')) 131 | return m.hexdigest() 132 | 133 | def decrypt_key(self, encrypt_key): 134 | t = b64decode(encrypt_key).decode() 135 | a = t.split(";") 136 | if a and 3 == len(a): 137 | c = self.ge + a[1] 138 | n = self.md5(c)[8:24] 139 | return n 140 | 141 | def gene_encrypt_key(self): 142 | e = f"{self.timestamp()}{randint(100, 999)}" 143 | i = self.ge + e 144 | a = self.md5(i)[8:24] 145 | c = f"{self.he};{e};{self.fe}" 146 | t = b64encode(c.encode("utf-8")).decode() 147 | return a, t 148 | 149 | """查询总积分""" 150 | 151 | def query_total_score(self): 152 | url = f"https://app.jegotrip.com.cn/api/service/member/v1/expireRewardQuery?token={self.token}&h_token={self.token}&lang=zh_CN" 153 | encrypt_key = self.gene_encrypt_key() 154 | key = encrypt_key[0] 155 | sec = encrypt_key[1] 156 | body = { 157 | "sec": sec, 158 | "body": AESCipher(key).encrypt("{}") 159 | } 160 | encrypt_data = post(url, headers=self.headers, json=body).json() 161 | if encrypt_data["code"] == "0": 162 | encrypt_body = encrypt_data["body"] 163 | encrypt_sec = encrypt_data["sec"] 164 | decrypt_data = AESCipher(self.decrypt_key(encrypt_sec)).decrypt(encrypt_body) 165 | total_score = loads(decrypt_data)["tripcoins"] 166 | print(f"查询成功, 你共有{total_score}点积分") 167 | self.msg += f", 你共有{total_score}点积分" 168 | 169 | def get_checkin_taskid(self): 170 | url = f"https://app.jegotrip.com.cn/api/service/v1/mission/sign/querySign?token={self.token}&h_token={self.token}&lang=zh_CN" 171 | encrypt_key = self.gene_encrypt_key() 172 | key = encrypt_key[0] 173 | sec = encrypt_key[1] 174 | body = { 175 | "sec": sec, 176 | "body": AESCipher(key).encrypt("{}") 177 | } 178 | encrypt_data = post(url, headers=self.headers, json=body).json() 179 | if encrypt_data["code"] == "0": 180 | encrypt_body = encrypt_data["body"] 181 | encrypt_sec = encrypt_data["sec"] 182 | decrypt_data = AESCipher(self.decrypt_key(encrypt_sec)).decrypt(encrypt_body) 183 | for checkin_task in eval(decrypt_data)[::-1]: 184 | task_status = checkin_task["isSign"] 185 | if task_status == 2: 186 | self.taskId = checkin_task["id"] 187 | # print(self.taskId) 188 | return self.taskId 189 | 190 | if self.taskId == "": 191 | print("获取任务id失败 退出") 192 | exit(0) 193 | 194 | def checkin(self): 195 | url = f"https://app.jegotrip.com.cn/api/service/v1/mission/sign/userSign?token={self.token}&h_token={self.token}&lang=zh_CN" 196 | encrypt_key = self.gene_encrypt_key() 197 | key = encrypt_key[0] 198 | sec = encrypt_key[1] 199 | body = { 200 | "sec": sec, 201 | "body": AESCipher(key).encrypt(f'{{"signConfigId":{self.get_checkin_taskid()}}}') 202 | } 203 | data = post(url, headers=self.headers, json=body).json() 204 | if data["code"] == "0": 205 | self.msg += "签到成功" 206 | print(self.msg) 207 | else: 208 | self.msg += "签到失败" 209 | print(self.msg) 210 | 211 | def main(self): 212 | self.checkin() 213 | self.query_total_score() 214 | self.push(self.msg) 215 | 216 | 217 | if __name__ == "__main__": 218 | WYX(token).main() 219 | --------------------------------------------------------------------------------