Continue seeded Qinglong script collection

This commit is contained in:
Hermes Agent
2026-05-24 05:33:05 +00:00
parent ca1a4275e4
commit b082da3fe1
392 changed files with 131619 additions and 7 deletions

View File

@@ -0,0 +1,181 @@
# Source: https://github.com/xfmeng970526/ql/blob/main/yu.py
# Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/yu.py
# Repo: xfmeng970526/ql
# Path: yu.py
# UploadedAt: 2023-09-20T12:13:28+08:00
# SHA256: 0548064af1ce7ef8d6d449edb5bb0555d2911a7ea795da689b70f7b325282fdc
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
# -*- coding: utf-8 -*-
# @Time: 2023年04月06日14时26分
import requests
from datetime import datetime, timedelta, timezone
from pathlib import Path
import logging
import json
cron: 3 9,14 * * *
new Env('102-雨云');
项目名称雨云
''''脚本使用说明:
后缀名改成py
白嫖的项目签到白嫖游戏服务器或者稳定的虚拟主机攒着提现也可以2018年以来一直稳定运行的自己可以查一查资料
第一步上传本脚本到青龙本脚本是py不是js 别搞错了)
第二步:去 https://www.rainyun.cc/?ref=MzUxMzA= 注册一个账号(不提现只抢游戏云和主机的话不用实名)
想提现的话6万积分起提现...绑定支付宝提现(稳到,亲测过,也有官方用户群)。
第三步本脚本里第121行122行里设置一下自己注册的账号和密码
本脚本里第121行122行里设置一下自己注册的账号和密码
本脚本里第121行122行里设置一下自己注册的账号和密码
第四步时间规则0 0 23 * * ?    #每天 23 点执行一次 (可以按自己的需求,每天执行一次)
积分规则及说明:本脚本是每天实现自动签到每天300个积分入门级游戏云或者虚拟主机2000积分一周。
这样下来一直用积分续费想提现的话6万积分起提现...绑定支付宝提现(稳到)。
注册地址:
https://www.rainyun.cc/?ref=rain
https://www.rainyun.cc/?ref=rain
提现规则6万积分起提现稳到不过建议用来续费游戏云比较划算
新人完成积分任务以后大概会有7000积分积分商城每天20点刷新自己抢一下一个主机或者游戏云
而2000积分就可以领取一个免费的MC服务器或者主机而且可以用积分进行续费续费也只需要2000积分
前期积分任务做完加上每日签到,足够免费续费一个月了!后面一直用积分续费。
注册地址:
https://www.rainyun.cc/?ref=rain
'''
# 忽略 不验证ssl的提示
import warnings
warnings.filterwarnings('ignore')
class RainYun():
def __init__(self, user: str, pwd: str) -> None:
# 认证信息
self.user = user.lower()
self.pwd = pwd
self.json_data = json.dumps({
"field": self.user,
"password": self.pwd,
})
# 日志输出
self.logger = logging.getLogger(self.user)
formatter = logging.Formatter(datefmt='%Y/%m/%d %H:%M:%S',
fmt="%(asctime)s 雨云 %(levelname)s: 用户<%(name)s> %(message)s")
handler = logging.StreamHandler()
handler.setFormatter(formatter)
self.logger.addHandler(handler)
self.logger.setLevel(logging.INFO)
# 签到结果初始化
self.signin_result = False
# 请求设置
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
"Origin": "https://api.rainyun.com",
"Referer": "https://api.rainyun.com"
})
self.login_url = "https://api.v2.rainyun.com/user/login"
self.signin_url = "https://api.v2.rainyun.com/user/reward/tasks"
self.logout_url = "https://api.v2.rainyun.com/user/logout"
self.query_url = "https://api.v2.rainyun.com/user/"
# 忽略 .cc ssl错误
self.session.verify = False
def login(self) -> None:
"""登录"""
res = self.session.post(
url=self.login_url, headers={"Content-Type": "application/json"}, data=self.json_data)
if res.text.find("200") > -1:
self.logger.info("登录成功")
self.session.headers.update({
"X-CSRF-Token": res.cookies.get("X-CSRF-Token", "")
})
else:
self.logger.error(f"登录失败,响应信息:{res.text}")
def signin(self) -> None:
"""签到"""
res = self.session.post(url=self.signin_url, headers={"Content-Type": "application/json"}, data=json.dumps({
"task_name": "每日签到",
"verifyCode": ""
}))
self.signin_date = datetime.utcnow()
if res.text.find("200") > -1:
self.logger.info("成功签到并领取积分")
self.signin_result = True
else:
self.logger.error(f"签到失败,响应信息:{res.text}")
self.signin_result = False
def logout(self) -> None:
res = self.session.post(url=self.logout_url)
if res.text.find("200") > -1:
self.logger.info('已退出登录')
else:
self.logger.warning(f"退出登录时出了些问题,响应信息:{res.text}")
def query(self) -> None:
res = self.session.get(url=self.query_url)
self.points = None
if res.text.find("200") > -1:
data = res.json()["data"]
self.points = data.get("Points", None) or data["points"]
self.logger.info("积分查询成功为 " + repr(self.points))
else:
self.logger.error(f"积分信息失败,响应信息:{res.text}")
def log(self, log_file: str, max_num=5) -> None:
"""存储本次签到结果的日志"""
# 北京时间
time_string = self.signin_date.replace(tzinfo=timezone.utc).astimezone(
timezone(timedelta(hours=8))).strftime("%Y/%m/%d %H:%M:%S")
file = Path(log_file)
record = {
"date": time_string,
"result": self.signin_result,
"points": self.points
}
previous_records = {}
if file.is_file():
try:
with open(log_file, 'r') as f:
previous_records = json.load(f)
if not previous_records.get(self.user):
previous_records[self.user] = []
previous_records[self.user].insert(0, record)
previous_records[self.user] = previous_records[self.user][:max_num]
except Exception as e:
self.logger.error("序列化日志时出错:"+repr(e))
else:
previous_records[self.user] = [record]
with open(log_file, 'w', encoding='utf-8') as f:
json.dump(previous_records, f, indent=4)
self.logger.info('日志保存成功')
if __name__ == '__main__':
accounts = [
{
"user": "账户", # 账户
"password": "密码" # 密码
}
]
for acc in accounts:
ry = RainYun(acc["user"], acc["password"]) # 实例
ry.login() # 登录
ry.signin() # 签到
ry.query() # 查询积分
ry.logout() # 登出
# 保存日志则打开注释 推荐文件绝对路径
# file = "./rainyun-signin-log.json"
# 日志最大记录数量
# max_num = 5
# ry.log(file, max_num) # 保存日志

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,152 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/web/sudojia_33agilestudio.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/web/sudojia_33agilestudio.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/web/sudojia_33agilestudio.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: cc8d2ad222b3206b91833e9b2724bb7b0a300c5c9a73679ced82953f001dd89b
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* 33台词 https://33.agilestudio.cn/invite?userCode=Rx5X7gjH
* 一个通过台词找影片素材
* 每日签到获得积分
*
* 积分有什么用?
* 官方文档回答:
* 1. 积分可以用来截取图片和剪切视频。
* 2. 积分可以兑换会员。(限普通积分)
*
* export AGILE_STUDIO_ACCOUNTS = 'email#password'
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2024/12/3
*
* const $ = new Env('33台词')
* cron: 1 11 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('33台词');
const agileList = process.env.AGILE_STUDIO_ACCOUNTS ? process.env.AGILE_STUDIO_ACCOUNTS.split(/[\n&]/) : [];
let message = '';
// 接口地址
const baseUrl = 'https://ssv-api.agilestudio.cn'
// 请求头
const headers = {
'User-Agent': sudojia.getRandomUserAgent('PC'),
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate, br, zstd',
'Host': 'ssv-api.agilestudio.cn',
'Origin': 'https://33.agilestudio.cn',
'Content-Type': 'application/json;charset=UTF-8',
};
!(async () => {
await checkUpdate($.name, agileList);
console.log(`\n已随机分配 User-Agent\n\n${headers['user-agent'] || headers['User-Agent']}`);
for (let i = 0; i < agileList.length; i++) {
const index = i + 1;
const [email, password] = agileList[i].split('#');
console.log(`\n*****第[${index}]个${$.name}账号*****`);
console.log('开始登录~');
const loginSuccess = await login(email, password);
if (!loginSuccess) {
break;
}
await $.wait(sudojia.getRandomWait(1e3, 2e3));
message += `📣====${$.name}账号[${index}]====📣\n`;
await main();
await $.wait(sudojia.getRandomWait(1500, 2300));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
async function main() {
await getUserInfo();
await $.wait(sudojia.getRandomWait(1500, 2300));
await dailyCheck();
await $.wait(sudojia.getRandomWait(1500, 2300));
await getPoints();
}
/**
* 登录
*
* @param email
* @param password
* @returns {Promise<boolean>}
*/
async function login(email, password) {
try {
const ts = (new Date).getTime() - 9999;
headers['x-signature'] = generateXSignature(ts);
const data = await sudojia.sendRequest(`${baseUrl}/api/auth/email-login?_platform=web&_versioin=0.2.5&_ts=${ts}`, 'post', headers, {
"email": email,
"password": password
});
if (0 !== data.code) {
console.error(data.msg);
return false;
}
headers['x-token'] = data.data.token;
console.log('登录成功~');
return true;
} catch (e) {
console.error(`登录时发生异常:${e}`);
return false;
}
}
async function getUserInfo() {
try {
const ts = (new Date).getTime() - 9999;
headers['x-signature'] = generateXSignature(ts);
const data = await sudojia.sendRequest(`${baseUrl}/api/user/my-info?_platform=web&_versioin=0.2.5&_ts=${ts}`, 'get', headers);
if (0 !== data.code) {
return console.error(data.msg);
}
console.log(`用户:${data.data.email}`);
message += `用户:${data.data.email}\n`;
} catch (e) {
console.error(`获取用户信息时发生异常:${e}`);
}
}
async function dailyCheck() {
try {
const ts = (new Date).getTime() - 9999;
headers['x-signature'] = generateXSignature(ts);
const data = await sudojia.sendRequest(`${baseUrl}/api/integral/do-daily-check?_platform=web&_versioin=0.2.5&_ts=${ts}`, 'post', headers);
if (0 !== data.code) {
return console.error(data.msg);
}
console.log('签到成功!');
message += `签到成功!\n`;
} catch (e) {
console.error(`签到时发生异常:${e}`);
}
}
async function getPoints() {
try {
const ts = (new Date).getTime() - 9999;
headers['x-signature'] = generateXSignature(ts);
const data = await sudojia.sendRequest(`${baseUrl}/api/user/user-info?_platform=web&_versioin=0.2.5&_ts=${ts}`, 'get', headers);
if (0 !== data.code) {
return console.error(data.msg);
}
console.log(`当前积分:${data.data.integral}`);
message += `当前积分:${data.data.integral}\n\n`;
} catch (e) {
console.error(`获取积分时发生异常:${e}`);
}
}
function generateXSignature(ts) {
return sudojia.md5(`_platform=web,_ts=${ts},_versioin=0.2.5,`);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,719 @@
// # Source: https://github.com/xfmeng970526/ql/blob/main/weibonz.js
// # Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/weibonz.js
// # Repo: xfmeng970526/ql
// # Path: weibonz.js
// # UploadedAt: 2023-09-20T12:13:28+08:00
// # SHA256: c6894d109c74946e5c4bab7a9e3d8892e6103afbc36ace17d55102149f65d17f
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/*
地址https://act.e.weibo.com/web/goodsthings/drawIndex.html?lotteryId=149
网页登录抓CK或者APP抓CK
变量
export weibonzhd=''
多号@或换行
cron: 3 9,14 * * *
new Env('44-微博年终购物清单');
项目名称:微博年终购物清单
*/
const $ = new Env('微博年终购物清单');
const axios = require('axios');
let request = require("request");
request = request.defaults({
jar: true
});
const {
log
} = console;
const Notify = 1; //0为关闭通知1为打开通知,默认为1
const debug = 0; //0为关闭调试1为打开调试,默认为0
let weibonzhd = ($.isNode() ? process.env.weibonzhd : $.getdata("weibonzhd")) || ""
let weibonzhdArr = [];
let data = '';
let msg = '';
var hours = new Date().getMonth();
var timestamp = Math.round(new Date().getTime()).toString();
!(async () => {
if (typeof $request !== "undefined") {
await GetRewrite();
} else {
if (!(await Envs()))
return;
else {
log(`\n\n============================================= \n脚本执行 - 北京时间(UTC+8)${new Date(
new Date().getTime() + new Date().getTimezoneOffset() * 60 * 1000 +
8 * 60 * 60 * 1000).toLocaleString()} \n=============================================\n`);
log(`\n============ 微信公众号:柠檬玩机交流 ============`)
log(`\n=================== 共找到 ${weibonzhdArr.length} 个账号 ===================`)
if (debug) {
log(`【debug】 这是你的全部账号数组:\n ${weibonzhdArr}`);
}
for (let index = 0; index < weibonzhdArr.length; index++) {
let num = index + 1
addNotifyStr(`\n==== 开始【第 ${num} 个账号】====\n`, true)
weibonzhd = weibonzhdArr[index];
await hit()
await $.wait(3000)
await addChance(426,'1000')
await $.wait(3000)
await addChance(430,'1000')
await $.wait(3000)
await addChance(431,'1000')
await $.wait(3000)
await addChance(427,'754198')
await $.wait(3000)
await addChance(427,'754199')
await $.wait(3000)
await addChance(427,'754203')
await hasChance()
}
//await SendMsg(msg);
}
}
})()
.catch((e) => log(e))
.finally(() => $.done())
async function hit() {
return new Promise((resolve) => {
var options = {
method: 'POST',
url: 'https://act.e.weibo.com/api/ac/hit',
headers: {
Accept: 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
Connection: 'keep-alive',
'Content-Length': '15',
'Content-Type': 'application/json; charset=UTF-8',
Cookie: weibonzhd,
Host: 'act.e.weibo.com',
Origin: 'https://act.e.weibo.com',
Referer: 'https://act.e.weibo.com/web/goodsthings/drawIndex.html?lotteryId=149',
'sec-ch-ua': 'sec-ch-ua',
'sec-ch-ua-mobile': '?1',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'content-type': 'application/json',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Weibo (iPhone12,8__weibo__11.8.1__iphone__os14.4)',
},
data: {task_id: 425}
};
if (debug) {
log(`\n【debug】=============== 这是 请求 url ===============`);
log(JSON.stringify(options));
}
axios.request(options).then(async function(response) {
try {
data = response.data;
if (debug) {
log(`\n\n【debug】===============这是 返回data==============`);
log(JSON.stringify(response.data));
}
if (data.code == 100000) {
log(data.msg)
} else
log(data.msg)
} catch (e) {
log(`异常:${data},原因:${data.msg}`)
}
}).catch(function(error) {
console.error(error);
}).then(res => {
//这里处理正确返回
resolve();
});
})
}
async function addChance(task_id,relation_id) {
return new Promise((resolve) => {
var options = {
method: 'POST',
url: 'https://act.e.weibo.com/api/lottery/addChance?lottery_id=149',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
Cookie: weibonzhd,
Host: 'act.e.weibo.com',
Origin: 'https://act.e.weibo.com',
Referer: 'https://act.e.weibo.com/web/goodsthings/drawIndex.html?lotteryId=149',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Weibo (iPhone12,8__weibo__11.8.1__iphone__os14.4)',
},
data: {lottery_id: 149, task_id: task_id, relation_id: relation_id}
};
if (debug) {
log(`\n【debug】=============== 这是 请求 url ===============`);
log(JSON.stringify(options));
}
axios.request(options).then(async function(response) {
try {
data = response.data;
if (debug) {
log(`\n\n【debug】===============这是 返回data==============`);
log(JSON.stringify(response.data));
}
if (data.code == 100000) {
log(data.msg)
} else
log(data.msg)
} catch (e) {
log(`异常:${data},原因:${data.msg}`)
}
}).catch(function(error) {
console.error(error);
}).then(res => {
//这里处理正确返回
resolve();
});
})
}
async function draw() {
return new Promise((resolve) => {
var options = {
method: 'POST',
url: 'https://act.e.weibo.com/api/lottery/draw',
params: {lottery_id: '149'},
headers: {
'Content-Type': 'application/json; charset=UTF-8',
Cookie: weibonzhd,
Host: 'act.e.weibo.com',
Origin: 'https://act.e.weibo.com',
Referer: 'https://act.e.weibo.com/web/goodsthings/drawIndex.html?lotteryId=149',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Weibo (iPhone12,8__weibo__11.8.1__iphone__os14.4)',
'content-type': 'application/json'
},
data: {
lottery_id: 149,
aid: '01A_DItRRK8EHtxj6ITqSsprU6TWEmDbzefAbma0Dz9PKXK-w.',
from: '10B8193010'
}
};
if (debug) {
log(`\n【debug】=============== 这是 请求 url ===============`);
log(JSON.stringify(options));
}
axios.request(options).then(async function(response) {
try {
data = response.data;
if (debug) {
log(`\n\n【debug】===============这是 返回data==============`);
log(JSON.stringify(response.data));
}
if (data.code == 100000) {
log(data)
} else
log(data.msg)
} catch (e) {
log(`异常:${data},原因:${data.msg}`)
}
}).catch(function(error) {
console.error(error);
}).then(res => {
//这里处理正确返回
resolve();
});
})
}
async function hasChance() {
return new Promise((resolve) => {
var options = {
method: 'GET',
url: 'https://act.e.weibo.com/api/lottery/hasChance',
params: {lottery_id: '149'},
headers: {
'Content-Type': 'application/json; charset=UTF-8',
Cookie: weibonzhd,
Host: 'act.e.weibo.com',
Origin: 'https://act.e.weibo.com',
Referer: 'https://act.e.weibo.com/web/goodsthings/drawIndex.html?lotteryId=149',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Weibo (iPhone12,8__weibo__11.8.1__iphone__os14.4)',
'content-type': 'application/json'
},
};
if (debug) {
log(`\n【debug】=============== 这是 请求 url ===============`);
log(JSON.stringify(options));
}
axios.request(options).then(async function(response) {
try {
data = response.data;
if (debug) {
log(`\n\n【debug】===============这是 返回data==============`);
log(JSON.stringify(response.data));
}
if (data.code == 100000) {
log(data)
left =data.data.left_num
for(let i=0;i<left;i++){
draw()
await $.wait(3000)
}
} else
log(data.msg)
} catch (e) {
log(`异常:${data},原因:${data.msg}`)
}
}).catch(function(error) {
console.error(error);
}).then(res => {
//这里处理正确返回
resolve();
});
})
}
async function Envs() {
if (weibonzhd) {
if (weibonzhd.indexOf("@") != -1) {
weibonzhd.split("@").forEach((item) => {
weibonzhdArr.push(item);
});
} else if (weibonzhd.indexOf("\n") != -1) {
weibonzhd.split("\n").forEach((item) => {
weibonzhdArr.push(item);
});
} else {
weibonzhdArr.push(weibonzhd);
}
} else {
log(`\n${$.name}】:未填写变量 weibonzhd`)
return;
}
return true;
}
function addNotifyStr(str, is_log = true) {
if (is_log) {
log(`${str}\n`)
}
msg += `${str}\n`
}
// ============================================发送消息============================================ \\
async function SendMsg(message) {
if (!message)
return;
if (Notify > 0) {
if ($.isNode()) {
var notify = require('./sendNotify');
await notify.sendNotify($.name, message);
} else {
$.msg(message);
}
} else {
log(message);
}
}
function Env(t, e) {
"undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0);
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, r) => {
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 = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`)
}
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
}
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 r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");
r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r;
const [o, h] = i.split("@"), n = {
url: `http://${h}/v1/scripting/evaluate`,
body: {
script_text: t,
mock_type: "cron",
timeout: r
},
headers: {
"X-Key": o,
Accept: "*/*"
}
};
this.post(n, (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),
r = JSON.stringify(this.data);
s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r)
}
}
lodash_get(t, e, s) {
const i = e.replace(/\[(\d+)\]/g, ".$1").split(".");
let r = t;
for (const t of i)
if (r = Object(r)[t], void 0 === r) return s;
return r
}
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), r = s ? this.getval(s) : "";
if (r) try {
const t = JSON.parse(r);
e = t ? this.lodash_get(t, i, "") : e
} catch (t) {
e = ""
}
}
return e
}
setdata(t, e) {
let s = !1;
if (/^@/.test(e)) {
const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i),
h = i ? "null" === o ? null : o || "{}" : "{}";
try {
const e = JSON.parse(h);
this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i)
} catch (e) {
const o = {};
this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), 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 = (() => {})) {
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), e(t, s, i)
})) : 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: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => e(t))) : this.isNode() && (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: s,
statusCode: i,
headers: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => {
const {
message: s,
response: i
} = t;
e(s, i, i && i.body)
}))
}
post(t, e = (() => {})) {
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.post(t, (t, s, i) => {
!t && s && (s.body = i, s.statusCode = s.status), e(t, s, i)
});
else if (this.isQuanX()) t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, {
hints: !1
})), $task.fetch(t).then(t => {
const {
statusCode: s,
statusCode: i,
headers: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => e(t));
else if (this.isNode()) {
this.initGotEnv(t);
const {
url: s,
...i
} = t;
this.got.post(s, i).then(t => {
const {
statusCode: s,
statusCode: i,
headers: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => {
const {
message: s,
response: i
} = t;
e(s, i, i && i.body)
})
}
}
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 = "", r) {
const o = 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;
return {
"open-url": e,
"media-url": s
}
}
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, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) {
let t = ["", "==============📣系统通知📣=============="];
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("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t)
}
wait(t) {
return new Promise(e => setTimeout(e, t))
}
done(t = {}) {
const e = (new Date).getTime(),
s = (e - this.startTime) / 1e3;
this.log("", `🔔${this.name}, 结束! 🕛 ${s}`), this.log(), (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t)
}
}(t, e)
}

View File

@@ -0,0 +1,646 @@
// # Source: https://github.com/xfmeng970526/ql/blob/main/yayi.js
// # Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/yayi.js
// # Repo: xfmeng970526/ql
// # Path: yayi.js
// # UploadedAt: 2023-09-20T12:13:28+08:00
// # SHA256: 9713ec7bd7b07bc955e68a3c41841a399aba3c1d2d339b8eeba9884e586f0e08
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/*
APP牙e家
设置密码
export yayihd='手机号&密码'
多号@或换行隔开
10话费
cron: 3 9,14 * * *
new Env('45-牙e家');
项目名称牙e家
*/
const $ = new Env('45-牙e家');
const axios = require('axios');
let request = require("request");
request = request.defaults({
jar: true
});
const {
log
} = console;
const Notify = 1; //0为关闭通知1为打开通知,默认为1
const debug = 0; //0为关闭调试1为打开调试,默认为0
let yayihd = ($.isNode() ? process.env.yayihd : $.getdata("yayihd")) || ""
let yayihdArr = [];
let data = '';
let msg = '';
var hours = new Date().getMonth();
var timestamp = Math.round(new Date().getTime()).toString();
!(async () => {
if (typeof $request !== "undefined") {
await GetRewrite();
} else {
if (!(await Envs()))
return;
else {
log(`\n\n============================================= \n脚本执行 - 北京时间(UTC+8)${new Date(
new Date().getTime() + new Date().getTimezoneOffset() * 60 * 1000 +
8 * 60 * 60 * 1000).toLocaleString()} \n=============================================\n`);
log(`\n============ 微信公众号:柠檬玩机交流 ============`)
log(`\n=================== 共找到 ${yayihdArr.length} 个账号 ===================`)
if (debug) {
log(`【debug】 这是你的全部账号数组:\n ${yayihdArr}`);
}
for (let index = 0; index < yayihdArr.length; index++) {
let num = index + 1
addNotifyStr(`\n==== 开始【第 ${num} 个账号】====\n`, true)
yayihd = yayihdArr[index];
pass = yayihd.split('&')[1]
phones = yayihd.split('&')[0]
await Userlogin(pass,phones)
log(encodeURIComponent(authcode))
await req('Signlist/openapp')
log(data)
await req('Signlist/toshare')
log(data)
await req('Signlist/toshare')
log(data)
await req('Signlist/toshare')
log(data)
await req1('Hotrecommendlist/torecommend','4879')
log(data)
await req1('Hotrecommendlist/torecommend','4878')
log(data)
await req1('Hotrecommendlist/torecommend','4877')
log(data)
await req1('Hotrecommendlist/torecommend','4876')
log(data)
await req1('Hotrecommendlist/torecommend','4875')
log(data)
}
//await SendMsg(msg);
}
}
})()
.catch((e) => log(e))
.finally(() => $.done())
async function Userlogin(password,phone) {
return new Promise((resolve) => {
var options = {
method: 'POST',
url: 'http://api.kq88.com/Userlogin',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Host: 'api.kq88.com',
'User-Agent': 'okhttp/3.8.1'
},
data: 'password='+password+'&phone='+phone+'&device='
};
if (debug) {
log(`\n【debug】=============== 这是 请求 url ===============`);
log(JSON.stringify(options));
}
axios.request(options).then(async function(response) {
try {
data = response.data;
if (debug) {
log(`\n\n【debug】===============这是 返回data==============`);
authcode = data.listdata.authcode
}
if (data.result == 0) {
authcode = data.listdata.authcode
} else
log(data)
} catch (e) {
log(`异常:${data},原因:${data.message}`)
}
}).catch(function(error) {
console.error(error);
}).then(res => {
//这里处理正确返回
resolve();
});
})
}
async function req1(api,id) {
return new Promise((resolve) => {
var options = {
method: 'POST',
url: 'https://api.kq88.com/'+api,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Host: 'api.kq88.com',
'User-Agent': 'okhttp/3.8.1'
},
data: `code=${encodeURIComponent(authcode)}&ffid=0&commentpics=%5B%5D&sconect=%E5%BE%88%E5%A5%BD%20%E5%AD%A6%E5%88%B0%E4%BA%86%E8%80%81%E5%B8%88%20%E5%8F%97%E6%95%99%E4%BA%86%E3%80%82&id=${id}`
};
if (debug) {
log(`\n【debug】=============== 这是 请求 url ===============`);
log(JSON.stringify(options));
}
axios.request(options).then(async function(response) {
try {
data = response.data;
if (debug) {
log(`\n\n【debug】===============这是 返回data==============`);
log(data)
}
if (data.result == 0) {
} else
log(data)
} catch (e) {
log(`异常:${data},原因:${data.message}`)
}
}).catch(function(error) {
console.error(error);
}).then(res => {
//这里处理正确返回
resolve();
});
})
}
async function req(api) {
return new Promise((resolve) => {
var options = {
method: 'POST',
url: 'https://api.kq88.com/'+api,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Host: 'api.kq88.com',
'User-Agent': 'okhttp/3.8.1'
},
data: 'code='+encodeURIComponent(authcode)
};
if (debug) {
log(`\n【debug】=============== 这是 请求 url ===============`);
log(JSON.stringify(options));
}
axios.request(options).then(async function(response) {
try {
data = response.data;
if (debug) {
log(`\n\n【debug】===============这是 返回data==============`);
log(data)
}
if (data.result == 0) {
} else
log(data)
} catch (e) {
log(`异常:${data},原因:${data.message}`)
}
}).catch(function(error) {
console.error(error);
}).then(res => {
//这里处理正确返回
resolve();
});
})
}
async function Envs() {
if (yayihd) {
if (yayihd.indexOf("@") != -1) {
yayihd.split("@").forEach((item) => {
yayihdArr.push(item);
});
} else if (yayihd.indexOf("\n") != -1) {
yayihd.split("\n").forEach((item) => {
yayihdArr.push(item);
});
} else {
yayihdArr.push(yayihd);
}
} else {
log(`\n${$.name}】:未填写变量 yayihd`)
return;
}
return true;
}
function addNotifyStr(str, is_log = true) {
if (is_log) {
log(`${str}\n`)
}
msg += `${str}\n`
}
// ============================================发送消息============================================ \\
async function SendMsg(message) {
if (!message)
return;
if (Notify > 0) {
if ($.isNode()) {
var notify = require('./sendNotify');
await notify.sendNotify($.name, message);
} else {
$.msg(message);
}
} else {
log(message);
}
}
function Env(t, e) {
"undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0);
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, r) => {
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 = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`)
}
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
}
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 r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");
r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r;
const [o, h] = i.split("@"), n = {
url: `http://${h}/v1/scripting/evaluate`,
body: {
script_text: t,
mock_type: "cron",
timeout: r
},
headers: {
"X-Key": o,
Accept: "*/*"
}
};
this.post(n, (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),
r = JSON.stringify(this.data);
s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r)
}
}
lodash_get(t, e, s) {
const i = e.replace(/\[(\d+)\]/g, ".$1").split(".");
let r = t;
for (const t of i)
if (r = Object(r)[t], void 0 === r) return s;
return r
}
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), r = s ? this.getval(s) : "";
if (r) try {
const t = JSON.parse(r);
e = t ? this.lodash_get(t, i, "") : e
} catch (t) {
e = ""
}
}
return e
}
setdata(t, e) {
let s = !1;
if (/^@/.test(e)) {
const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i),
h = i ? "null" === o ? null : o || "{}" : "{}";
try {
const e = JSON.parse(h);
this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i)
} catch (e) {
const o = {};
this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), 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 = (() => {})) {
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), e(t, s, i)
})) : 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: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => e(t))) : this.isNode() && (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: s,
statusCode: i,
headers: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => {
const {
message: s,
response: i
} = t;
e(s, i, i && i.body)
}))
}
post(t, e = (() => {})) {
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.post(t, (t, s, i) => {
!t && s && (s.body = i, s.statusCode = s.status), e(t, s, i)
});
else if (this.isQuanX()) t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, {
hints: !1
})), $task.fetch(t).then(t => {
const {
statusCode: s,
statusCode: i,
headers: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => e(t));
else if (this.isNode()) {
this.initGotEnv(t);
const {
url: s,
...i
} = t;
this.got.post(s, i).then(t => {
const {
statusCode: s,
statusCode: i,
headers: r,
body: o
} = t;
e(null, {
status: s,
statusCode: i,
headers: r,
body: o
}, o)
}, t => {
const {
message: s,
response: i
} = t;
e(s, i, i && i.body)
})
}
}
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 = "", r) {
const o = 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;
return {
"open-url": e,
"media-url": s
}
}
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, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) {
let t = ["", "==============📣系统通知📣=============="];
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("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t)
}
wait(t) {
return new Promise(e => setTimeout(e, t))
}
done(t = {}) {
const e = (new Date).getTime(),
s = (e - this.startTime) / 1e3;
this.log("", `🔔${this.name}, 结束! 🕛 ${s}`), this.log(), (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t)
}
}(t, e)
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,721 @@
// # Source: https://github.com/xfmeng970526/ql/blob/main/sytt.js
// # Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/sytt.js
// # Repo: xfmeng970526/ql
// # Path: sytt.js
// # UploadedAt: 2023-09-20T12:13:28+08:00
// # SHA256: f2743bee7135f0b733a26d8225a842a5cb079131a11dd9145a0f85c0d9e5ff2f
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/*
cron 8 7 * * * yml_javascript/sytt.js
软件名称:十堰头条
下载地址http://appx.10yan.com.cn/appshare/
或者自己搜索下载
3-17 完成签到、评论、分享、回帖 任务
3-21 关闭评论、回帖功能 需要的自行打开,并自行设置回复内容
感谢所有测试人员
自行安装 axios qs 依赖; 自行安装 axios qs 依赖; 自行安装 axios qs 依赖;
青龙直接node中安装就行
注意事项 一定要仔细阅读一下内容
=============青龙变量格式=============
export yml_sytt_data='手机号&密码'
多账号使用 @ 分割;
=============青龙变量实例=============
我觉得已经不需要例子了 填上账号密码再不回那就别薅羊毛了吧
=============变量解释==========
手机号 密码 填入自己的数据就行
=============变量获取==========
cron: 4 5,19 * * *
new Env('6-十堰头条');
项目名称:十堰头条
*/
const axios = require("axios");
const qs = require("qs");
const $ = new Env('十堰头条');
const notify = $.isNode() ? require('./sendNotify') : '';
let app_yml_sytt_data='';
let user = '';
let pwd = '';
let uid;
!(async () => {
if ($.isNode()) {
//$.isNode()环境执行部分 青龙执行
if (!process.env.yml_sytt_data) {
console.log(`\n${$.name}】:未填写相应变量 yml_sytt_data`);
return;
}
if (process.env.yml_sytt_data && process.env.yml_sytt_data.indexOf('@') > -1) {
app_yml_sytt_data = process.env.yml_sytt_data.split('@');
}else {
app_yml_sytt_data = process.env.yml_sytt_data.split();
}
}
console.log(`-------- 共 ${app_yml_sytt_data.length} 个账号 --------`)
// console.log(app_yml_sytt_data)
console.log(
`\n\n====== 脚本执行 - 北京时间(UTC+8)${new Date(
new Date().getTime() +
new Date().getTimezoneOffset() * 60 * 1000 +
8 * 60 * 60 * 1000
).toLocaleString()} ======\n`);
await wyy();
for (i = 0; i < app_yml_sytt_data.length; i++) {
$.index = i + 1;
console.log(`\n====== 开始【第 ${$.index} 个账号】======`)
// console.log(`这里是分割后:${app_yml_sytt_data}`);
data = app_yml_sytt_data[i].split('&');
// console.log(`====== ${data}`)
user = data[0]
// console.log(`====user==== ${user}`)
pwd = data[1]
// console.log(`====pwd==== ${pwd}`)
//执行任务
await syttdl();
await $.wait(2 * 1000);
await syttqd();
await $.wait(2 * 1000);
await plid();
await $.wait(2 * 1000);
await fxwz();
await $.wait(2 * 1000);
await tzid();
await $.wait(2 * 1000);
}
})()
.catch((e) => $.logErr(e))
.finally(() => $.done())
//每日网抑云
function wyy(timeout = 3 * 1000) {
return new Promise((resolve) => {
let url = {
url: `https://keai.icu/apiwyy/api`
}
$.get(url, async (err, resp, data) => {
try {
data = JSON.parse(data)
$.log(`\n【网抑云时间】: ${data.content} by--${data.music}`);
} catch (e) {
$.logErr(e, resp);
} finally {
resolve()
}
}, timeout)
})
}
// 登录
function syttdl(timeout = 0) {
urldl = `https://app.site.10yan.com.cn/index.php?s=/Api/Loginv3/signInv3&password=${pwd}&username=${user}`
// console.log(urldl)
return new Promise((resolve) => {
let url = {
url: urldl,
headers: { } ,
body: '',
}
// console.log(url);
$.post(url, async (err, resp, data) => {
try {
// console.log(`输出 登录 data开始===================`);
// console.log(data);
// console.log(`输出 登录 data结束===================`);
result = JSON.parse(data);
if (result.code == "200") {
console.log(`登录用户: ${user}`)
$.log(`\n【🎉🎉🎉 恭喜您鸭 🎉🎉🎉】登录状态: ${result.retinfo}`)
// await $.wait(3 * 1000)
}else {
$.log(`\n【🎉 恭喜个屁 🎉】登录状态:${result.retinfo} `)
}
uid = result.data.uid
console.log(`这是你的用户iduid=${uid}`)
} catch (e) {
$.logErr(e, resp);
} finally {
resolve()
}
}, timeout)
})
}
// 签到
function syttqd(timeout = 0) {
return new Promise((resolve) => {
let url = {
url: `https://app.site.10yan.com.cn/index.php?s=/Api/Activityv1/sign&uid=${uid}&source=android&ver=6.2.3&build=145`,
headers:'',
}
// console.log(url);
$.get(url, async (err, resp, data) => {
try {
// console.log(`========输出签到 data开始===========`);
// console.log(data);
// console.log(`========输出签到 data结束=========`);
result = JSON.parse(data);
if (result.code == 200) {
$.log(`\n【🎉🎉🎉 恭喜您鸭 🎉🎉🎉】签到状态:(${result.retinfo}) ,获得 ${result.money}`)
// await $.wait(3 * 1000)
} else if (result.code == 400) {
$.log(`\n【🎉 恭喜个屁 🎉】签到状态: ${result.retinfo}`)
}else {
$.log(`\n【🎉 恭喜个屁 🎉】执行签到:失败 ❌ 了呢,原因未知! `)
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve()
}
}, timeout)
})
}
// 评论任务部分
// 评论id
function plid(timeout = 0) {
// 获取文章id
return new Promise((resolve) => {
let url = {
url: `https://app.site.10yan.com.cn/index.php?s=/Api/Newsv4/newslist&page=1&type=reply&source=android`,
headers: {},
}
// console.log(url);
$.get(url, async (err, resp, data) => {
try {
// console.log(`输出 data开始===================`);
// console.log(data);
// console.log(`输出data结束===================`);
result = JSON.parse(data);
for (let l = 0; l < 3; l++) {
// console.log(`我是l===== ${l}`)
wzid = result.list[l].contentid
console.log(`获取评论文章id=${wzid}`)
console.log(`开始发布评论`)
await fbpl();
console.log(`延迟5秒`)
await $.wait(5 * 1000);
console.log(`删除评论`)
await hqplid();
console.log(`\n`)
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve()
}
}, timeout)
})
}
// 发布评论
function fbpl(timeout = 0) {
let axios = require('axios')
axios
.post(`https://app.site.10yan.com.cn/index.php?s=/Api/Article/artReply/&actiontype=12&contentid=${wzid}&reply=good!&sessionid=801cf37e86eaa651914b3cac0c756f9a&title=%%E6%%88%%91%%E5%%B8%%82%%E4%%B8%%80%%E5%%BD%%A9%%E5%%8F%%8B%%E5%%88%%AE%%E4%%B8%%AD%%E2%%80%%9C%%E5%%A5%%BD%%E8%%BF%%90%%E5%%8D%%81%%E5%%80%%8D%%E2%%80%%9D%%E5%%A4%%B4%%E5%%A5%%9640%%E4%%B8%%87&uid=${uid}&source=android&build=145`, {
})
.then(res => {
// console.log(res.data)
})
.catch(error => {
console.error(error)
})
}
// 获取评论 rid 并 删除评论
function hqplid(timeout = 0) {
let axios = require('axios');
let config = {
method: 'get',
url: `https://app.site.10yan.com.cn/index.php?s=/Api/Article/index/&contentid=${wzid}&page=1&uid=${uid}`,
headers: { }
};
axios(config)
.then(function (response) {
// console.log(`===========`)
// console.log(JSON.stringify(response.data));
// pl_data =response.data.list
// console.log(pl_data)
for ( k = 0; k < response.data.list.length; k++) {
usid = response.data.list[k].userid;
// console.log(usid)
if (usid == `${uid}`) {
// console.log(`====rid 开始=====`)
// console.log(response.data.list[k].pid)
// console.log(`=====rid 结束=====`)
// rid = response.data.list[i].pid
rid = response.data.list[k].pid
// console.log(`我是 rid ${rid}`)
// 删除评论
let axios = require('axios');
let qs = require('qs');
let data = qs.stringify({
'rid': `${rid}`,
'uid': `${uid}`,
// 'source': 'android',
'ver': '6.2.3',
'build': '145'
});
let config = {
method: 'post',
url: 'https://app.site.10yan.com.cn/index.php?s=/Api/Article/delReply/',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data : data
};
axios(config)
.then(function (response) {
// console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
}
})
.catch(function (error) {
console.log(error);
});
}
// 分享任务部分
// 分享
function fxwz(timeout = 0) {
// 获取分享文章列表 id
return new Promise((resolve) => {
let url = {
url: `https://app.site.10yan.com.cn/index.php?s=/Api/Newsv4/newslist&page=1&type=share&ver=6.2.3`,
headers: {},
}
// console.log(url);
$.get(url, async (err, resp, data) => {
try {
// console.log(`输出 data开始===================`);
// console.log(data);
// console.log(`输出data结束===================`);
result = JSON.parse(data);
for (let m = 0; m < 3; m++) {
// console.log(`我是m===== ${m}`)
fxwzid = result.list[m].contentid
console.log(`获取分享文章id=${fxwzid}`)
console.log(`开始分享文章`)
await fxwz1();
console.log(`延迟5秒`)
await $.wait(5 * 1000);
console.log(`\n`)
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve()
}
}, timeout)
})
}
// 文章分享调用函数
function fxwz1(timeout = 0) {
let axios = require('axios');
let config = {
method: 'get',
url: `https://app.site.10yan.com.cn/index.php?s=/Api/Activityv1/getNewsShareTask&contentid=${fxwzid}&uid=${uid}&source=android&ver=6.2.3`,
headers: { }
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
// 帖子id
function tzid(timeout = 0) {
// 获取帖子 文章id
return new Promise((resolve) => {
let url = {
url: `https://app.site.10yan.com.cn/index.php?s=/Api/Dynamic&isrecommend=1&page=1&uid=${uid}`,
headers: {},
}
// console.log(url);
$.get(url, async (err, resp, data) => {
try {
// console.log(`输出data开始===================`);
// console.log(data);
// console.log(`输出data结束===================`);
result = JSON.parse(data);
for (let n = 0; n < 3; n++) {
tzid1 = result.data[n].id
console.log(`开始回帖id=${tzid1}`)
await tzpl();
console.log(`延迟5秒`)
await $.wait(5 * 1000);
console.log(`\n`)
}
} catch (e) {
// $.logErr(e, resp);
} finally {
resolve()
}
}, timeout)
})
}
// 帖子发布评论
function tzpl(timeout = 0) {
var axios = require('axios');
var data = `content=%E5%A4%AA%E6%BC%82%E4%BA%AE%E4%BA%86%E9%B8%AD&pid=${tzid1}&uid=${uid}&source=android&ver=6.2.3&build=145`
var config = {
method: 'post',
url: 'https://app.site.10yan.com.cn/index.php?s=/Api/Dynamic/reply',
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
data : data
};
axios(config)
.then(function (response) {
// console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
//固定板块,无需动
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, r) => {
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 = "box.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
}
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 r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");
r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r;
const [o, h] = i.split("@"), n = {
url: `http://${h}/v1/scripting/evaluate`,
body: {script_text: t, mock_type: "cron", timeout: r},
headers: {"X-Key": o, Accept: "*/*"}
};
this.post(n, (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), r = JSON.stringify(this.data);
s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r)
}
}
lodash_get(t, e, s) {
const i = e.replace(/\[(\d+)\]/g, ".$1").split(".");
let r = t;
for (const t of i) if (r = Object(r)[t], void 0 === r) return s;
return r
}
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), r = s ? this.getval(s) : "";
if (r) try {
const t = JSON.parse(r);
e = t ? this.lodash_get(t, i, "") : e
} catch (t) {
e = ""
}
}
return e
}
setdata(t, e) {
let s = !1;
if (/^@/.test(e)) {
const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i),
h = i ? "null" === o ? null : o || "{}" : "{}";
try {
const e = JSON.parse(h);
this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i)
} catch (e) {
const o = {};
this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), 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), 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: r, body: o} = t;
e(null, {status: s, statusCode: i, headers: r, body: o}, o)
}, 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: r, headers: o, rawBody: h} = t;
e(null, {status: i, statusCode: r, headers: o, rawBody: h}, s.decode(h, this.encoding))
}, t => {
const {message: i, response: r} = t;
e(i, r, r && s.decode(r.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), 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: r, body: o} = t;
e(null, {status: s, statusCode: i, headers: r, body: o}, o)
}, t => e(t)); else if (this.isNode()) {
let i = require("iconv-lite");
this.initGotEnv(t);
const {url: r, ...o} = t;
this.got[s](r, o).then(t => {
const {statusCode: s, statusCode: r, headers: o, rawBody: h} = t;
e(null, {status: s, statusCode: r, headers: o, rawBody: h}, i.decode(h, this.encoding))
}, t => {
const {message: s, response: r} = t;
e(s, r, r && i.decode(r.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 = "", r) {
const o = 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;
return {"open-url": e, "media-url": s}
}
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, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !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)
}
}(t, e)
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,344 @@
# Source: https://github.com/xfmeng970526/ql/blob/main/xsgjz.py
# Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/xsgjz.py
# Repo: xfmeng970526/ql
# Path: xsgjz.py
# UploadedAt: 2023-09-20T12:13:28+08:00
# SHA256: 22259ffaf306b5014daacf34cd5b01ffd38728cee07678abdc66b9fbc1bb9b1a
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
#变量xsgCookie抓取小时工记账的authorization变量
#定时调成5 6-18/6 * * *
cron: 5 6-18/6 * * *
new Env('68-小时工记账');
项目名称小时工记账
from cgitb import text
import json
import time
import requests as r
import requests
import re
import json
import os
#获取名字链接
mzurl = "https://xsg-api.julanling.com/app/user/info"
#获取金币数量链接
jburl = "https://xsg-api.julanling.com/h5/api/activityThirdAccount/coin/getAccount"
#签到链接
signurl = "https://market-gateway.julanling.com/market-center/api2/signIn/signIn"
#转盘链接
zpurl = "https://market-gateway.julanling.com/market-center/api2/dial/luckyDraw"
#转盘金币领奖链接
zpljurl = "https://market-gateway.julanling.com/market-center/api2/dial/receiveDialCoin"
#转盘宝箱领奖链接
zpbxurl = "https://market-gateway.julanling.com/market-center/api2/dial/openBox"
#转盘双倍卡链接
zpsburl = "https://market-gateway.julanling.com/market-center/api2/dial/receiveDoubleCardBag"
#获取宝箱状态
bxzturl= "https://market-gateway.julanling.com/market-center/api2/dial/detailCore?appVersion=4.4.20"
#刷新扭蛋状态
ndsxurl = "https://market-gateway.julanling.com/market-center/api2/gacha/index?os=ANDROID&appVersion=4.4.20"
#扭蛋链接
ndurl = "https://market-gateway.julanling.com/market-center/api2/gacha/luckyDraw"
#扭蛋广告链接
ndadurl = "https://market-gateway.julanling.com/market-center/api2/gacha/finishGachaTask"
#7次广告链接
qiadurl = "https://market-gateway.julanling.com/market-center/api2/assignment/finishAssignment"
if os.environ.get("xsgCookie"):
dvm = os.environ["xsgCookie"]
if dvm != '':
if "@" in dvm:
Coo = dvm.split("@")
elif "&" in dvm:
Coo = dvm.split('&')
else:
Coo = dvm.split('\n')
adv=1
for i in Coo:
headers = {
"security": "cD1jb20uanVsYW5nbGluZy54c2dqeiZjPXhzZ2p6X3lpbmd5b25nYmFvJnY9NC40LjIwJmQ9MzU1MWU0MDFiYjQ0MWVlY2JiNDU5ZjkwMDE1MzJlMzEmdT1ZN2wyVitQNWdOd0RBRFZjR0huQ2VzbXAmdD0xNjczMDk4OTY5.7e9e9d0818df515f6a384d9d5debde40",
"authorization": i,
"user-agent": 'Mozilla/5.0 (Linux; Android 11; M2012K11AC Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/107.0.5304.105 Mobile Safari/537.36;_android{"version":4420,"versionName":"4.4.20","userType":"1","sdkVersion":"30","statusBarHeight":29,"toolBarHeight":73,"imei":"","oaid":"ad58bc17b41a81c7","channel":"xsgjz_yingyongbao","uid":10522}_android',
"content-type": "application/json;charset=UTF-8"
}
print(f'登录第{adv}个账号')
adv=adv+1
#登录验证
resp = r.post(mzurl, headers=headers)
xx = json.loads(resp.text)
if xx["results"] == "null":
print("登录失败请重新获取Authorization")
continue
else:
print("用户ID:"+xx["results"]["nickname"])
#获取金币数量
jb = r.post(jburl, headers=headers)
xb = json.loads(jb.text)
if xb["results"] == "null":
print("获取金币失败请检测Authorization是否可用")
else:
print("目前金币数量:"+str(xb["results"]["credits"]))
print("可提现:"+str(xb["results"]["aboutAmount"]))
print("今日赚取金币数量:"+str(xb["results"]["currentCredits"]))
time.sleep(2)
#签到
qdbody = {"os":"ANDROID","appVersion":"4.4.20","appChannel":"xsgjz_yingyongbao","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9"}
qd = r.post(signurl, headers=headers, json=qdbody)
qdd = json.loads(qd.text)
print("开始签到")
if qdd["errorCode"] == 0:
print("签到成功获取金币:"+str(qdd["results"]["amount"]))
else:
print("签到失败原因:"+str(qdd["errorStr"]))
time.sleep(2)
#转转盘
nc=1
zzpyz = r.get(bxzturl, headers=headers)
zptz = json.loads(zzpyz.text)
zpsycs = str(zptz["results"]["dialValidNum"])
print("转盘剩余次数"+zpsycs)
zpsycs=int(zpsycs)
for o in range(zpsycs):
print("开始第"+str(nc)+"次转盘")
time.sleep(3)
nc=nc+1
body = {"appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
zp = r.post(zpurl, headers=headers,json=body)
zpp = json.loads(zp.text)
if zpp["errorCode"] == 0:
if zpp["results"]["awardType"] == "GOLD":
biz = zpp["results"]["bizNo"]
zpbody = {
"bizNo":biz,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
lj = r.post(zpljurl, headers=headers,json=zpbody)
ljj = json.loads(lj.text)
print("抽到金币"+str(ljj["results"]["amount"]))
elif zpp["results"]["awardType"] == "DOUBLE_VIDEO":
print("抽到双倍卡,需要观看广告")
biz = zpp["results"]["bizNo"]
zpbody = {
"bizNo":biz,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
print("转盘结束,查看可领取那些宝箱")
#转盘5次宝箱奖励body
bx1={"businessType":"XSG_BOX_ONE","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘18次宝箱奖励body
bx2={"businessType":"XSG_BOX_TWO","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘30次宝箱奖励body
bx3={"businessType":"XSG_BOX_THREE","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘55次宝箱奖励body
bx4={"businessType":"XSG_BOX_FOUR","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘宝箱领取
time.sleep(3)
print("开始领转盘5次箱子奖励")
zpbx1 = r.post(zpbxurl, headers=headers,json=bx1)
bxx1 = json.loads(zpbx1.text)
if bxx1["errorCode"] == 0:
results = bxx1['results']
openBoxAwards = results['openBoxAwards']
bx1jb = openBoxAwards[0]['amount']
print("领取成功获得"+str(bx1jb)+"金币")
else:
print("领取失败,原因:"+str(bxx1["errorStr"]))
time.sleep(3)
time.sleep(3)
print("开始领转盘18次箱子奖励")
zpbx2 = r.post(zpbxurl, headers=headers,json=bx2)
bxx2 = json.loads(zpbx2.text)
if bxx2["errorCode"] == 0:
results2 = bxx2['results']
openBoxAwards2 = results2['openBoxAwards']
bx2jb = openBoxAwards2[0]['amount']
print("领取成功获得"+str(bx2jb)+"金币")
bxbizNo2 = bxx2['results']['openBoxAwards'][1]['bizNo']
print("领取箱子双倍卡,需要观看广告")
zpbody = {
"bizNo":bxbizNo2,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
del bxx2
del results2
del openBoxAwards2
del bx2jb
del bxbizNo2
del sb
del sbb
else:
print("领取失败,原因:"+str(bxx2["errorStr"]))
time.sleep(3)
time.sleep(5)
print("开始领转盘30次箱子奖励")
zpbx3 = r.post(zpbxurl, headers=headers,json=bx3)
bxx3 = json.loads(zpbx3.text)
if bxx3["errorCode"] == 0:
results3 = bxx3['results']
openBoxAwards3 = results3['openBoxAwards']
bx3jb = openBoxAwards3[0]['amount']
print("领取成功获得"+str(bx3jb)+"金币")
bxbizNo3 = bxx3['results']['openBoxAwards'][1]['bizNo']
print("领取箱子双倍卡,需要观看广告")
zpbody = {
"bizNo":bxbizNo3,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
del bxx3
del results3
del openBoxAwards3
del bx3jb
del bxbizNo3
del sb
del sbb
else:
print("领取失败,原因:"+str(bxx3["errorStr"]))
time.sleep(3)
time.sleep(3)
print("开始领转盘55次箱子奖励")
zpbx4 = r.post(zpbxurl, headers=headers,json=bx4)
bxx4 = json.loads(zpbx4.text)
if bxx4["errorCode"] == 0:
results4 = bxx4['results']
openBoxAwards4 = results4['openBoxAwards']
bx4jb = openBoxAwards4[0]['amount']
print("领取成功获得"+str(bx4jb)+"金币")
bxbizNo4 = bxx4['results']['openBoxAwards'][1]['bizNo']
print("领取箱子双倍卡,需要观看广告")
zpbody = {
"bizNo":bxbizNo4,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
del bxx4
del results4
del openBoxAwards4
del bx4jb
del bxbizNo4
del sb
del sbb
else:
print("领取失败,原因:"+str(bxx4["errorStr"]))
time.sleep(3)
#扭蛋
vc=1
bc=1
#先刷新扭蛋列表
ndsx = r.get(ndsxurl, headers=headers)
ndsxx = json.loads(ndsx.text)
#判断扭蛋广告可观看次数
ndadcs= ndsxx["results"]["remainVideoTimes"]
print("扭蛋广告剩余次数"+str(ndadcs))
#观看扭蛋广告
for o in range(ndadcs):
print("开始第"+str(bc)+"次观看扭蛋广告")
bc=bc+1
time.sleep(3)
ndadbody={"businessType":"XSG_DAILY_GACHA_INC_VIDEOS","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","version":"4.4.20","os":"ANDROID","appVersion":"4.4.20","appChannel":"unknow"}
ndad = r.post(ndadurl, headers=headers,json=ndadbody)
nddad = json.loads(ndad.text)
if nddad['errorCode'] == 0:
print("获得"+str(nddad["results"]["amount"])+"次抽奖次数")
print("目前有"+str(nddad["results"]["remainTimes"])+"次抽奖次数")
time.sleep(3)
else:
print("扭蛋失败原因"+nddad['errorStr'])
ndsx = r.get(ndsxurl, headers=headers)
ndsxx = json.loads(ndsx.text)
#判断扭蛋次数
ndsycs = ndsxx["results"]["remainTimes"]
print("扭蛋剩余次数"+str(ndsycs))
#开始扭蛋
for o in range(ndsycs):
print("开始第"+str(vc)+"次扭蛋")
vc=vc+1
time.sleep(3)
ndbody={"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","version":"4.4.20","os":"ANDROID","appVersion":"4.4.20","appChannel":"unknow"}
nd = r.post(ndurl, headers=headers,json=ndbody)
ndd = json.loads(nd.text)
if ndd['errorCode'] == 0:
if ndd["results"]["awardType"] == 'ADVERT':
print("抽到了空气广告")
else:
print("抽到"+str(ndd["results"]["name"]))
else:
print("扭蛋失败原因"+ndd['errorStr'])
time.sleep(3)
#看广告7次
for c in range(7):
qiadbody={"businessType":"XSG_MONEY_CENTER_INCENTIVE_VIDEO","os":"ANDROID","appVersion":"4.4.20","appChannel":"xsgjz_yingyongbao","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9"}
adws = r.post(qiadurl, headers=headers,json=qiadbody)
adwss = json.loads(adws.text)
if adwss['errorCode'] == 0:
adwssjb = adwss["results"]["awardInfos"]
adwssjbb = adwssjb[0]['amount']
print("获得金币"+str(adwssjbb)+"")
print("等待20秒,才可以观看广告")
time.sleep(21)
else:
break

View File

@@ -0,0 +1,344 @@
// # Source: https://github.com/xfmeng970526/ql/blob/main/xsgjz.js
// # Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/xsgjz.js
// # Repo: xfmeng970526/ql
// # Path: xsgjz.js
// # UploadedAt: 2023-09-20T12:13:28+08:00
// # SHA256: 465b4e71ad7980bc522a9279da88127790ea9fb64c263a088215d6d2010e0a91
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
#变量xsgCookie抓取小时工记账的authorization变量
cron: 5 6-18/6 * * *
new Env('68-小时工记账');
项目名称小时工记账
from cgitb import text
import json
import time
import requests as r
import requests
import re
import json
import os
#获取名字链接
mzurl = "https://xsg-api.julanling.com/app/user/info"
#获取金币数量链接
jburl = "https://xsg-api.julanling.com/h5/api/activityThirdAccount/coin/getAccount"
#签到链接
signurl = "https://market-gateway.julanling.com/market-center/api2/signIn/signIn"
#转盘链接
zpurl = "https://market-gateway.julanling.com/market-center/api2/dial/luckyDraw"
#转盘金币领奖链接
zpljurl = "https://market-gateway.julanling.com/market-center/api2/dial/receiveDialCoin"
#转盘宝箱领奖链接
zpbxurl = "https://market-gateway.julanling.com/market-center/api2/dial/openBox"
#转盘双倍卡链接
zpsburl = "https://market-gateway.julanling.com/market-center/api2/dial/receiveDoubleCardBag"
#获取宝箱状态
bxzturl= "https://market-gateway.julanling.com/market-center/api2/dial/detailCore?appVersion=4.4.20"
#刷新扭蛋状态
ndsxurl = "https://market-gateway.julanling.com/market-center/api2/gacha/index?os=ANDROID&appVersion=4.4.20"
#扭蛋链接
ndurl = "https://market-gateway.julanling.com/market-center/api2/gacha/luckyDraw"
#扭蛋广告链接
ndadurl = "https://market-gateway.julanling.com/market-center/api2/gacha/finishGachaTask"
#7次广告链接
qiadurl = "https://market-gateway.julanling.com/market-center/api2/assignment/finishAssignment"
if os.environ.get("xsgCookie"):
dvm = os.environ["xsgCookie"]
if dvm != '':
if "@" in dvm:
Coo = dvm.split("@")
elif "&" in dvm:
Coo = dvm.split('&')
else:
Coo = dvm.split('\n')
adv=1
for i in Coo:
headers = {
"security": "cD1jb20uanVsYW5nbGluZy54c2dqeiZjPXhzZ2p6X3lpbmd5b25nYmFvJnY9NC40LjIwJmQ9MzU1MWU0MDFiYjQ0MWVlY2JiNDU5ZjkwMDE1MzJlMzEmdT1ZN2wyVitQNWdOd0RBRFZjR0huQ2VzbXAmdD0xNjczMDk4OTY5.7e9e9d0818df515f6a384d9d5debde40",
"authorization": i,
"user-agent": 'Mozilla/5.0 (Linux; Android 11; M2012K11AC Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/107.0.5304.105 Mobile Safari/537.36;_android{"version":4420,"versionName":"4.4.20","userType":"1","sdkVersion":"30","statusBarHeight":29,"toolBarHeight":73,"imei":"","oaid":"ad58bc17b41a81c7","channel":"xsgjz_yingyongbao","uid":10522}_android',
"content-type": "application/json;charset=UTF-8"
}
print(f'登录第{adv}个账号')
adv=adv+1
#登录验证
resp = r.post(mzurl, headers=headers)
xx = json.loads(resp.text)
if xx["results"] == "null":
print("登录失败请重新获取Authorization")
continue
else:
print("用户ID:"+xx["results"]["nickname"])
#获取金币数量
jb = r.post(jburl, headers=headers)
xb = json.loads(jb.text)
if xb["results"] == "null":
print("获取金币失败请检测Authorization是否可用")
else:
print("目前金币数量:"+str(xb["results"]["credits"]))
print("可提现:"+str(xb["results"]["aboutAmount"]))
print("今日赚取金币数量:"+str(xb["results"]["currentCredits"]))
time.sleep(2)
#签到
qdbody = {"os":"ANDROID","appVersion":"4.4.20","appChannel":"xsgjz_yingyongbao","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9"}
qd = r.post(signurl, headers=headers, json=qdbody)
qdd = json.loads(qd.text)
print("开始签到")
if qdd["errorCode"] == 0:
print("签到成功获取金币:"+str(qdd["results"]["amount"]))
else:
print("签到失败原因:"+str(qdd["errorStr"]))
time.sleep(2)
#转转盘
nc=1
zzpyz = r.get(bxzturl, headers=headers)
zptz = json.loads(zzpyz.text)
zpsycs = str(zptz["results"]["dialValidNum"])
print("转盘剩余次数"+zpsycs)
zpsycs=int(zpsycs)
for o in range(zpsycs):
print("开始第"+str(nc)+"次转盘")
time.sleep(3)
nc=nc+1
body = {"appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
zp = r.post(zpurl, headers=headers,json=body)
zpp = json.loads(zp.text)
if zpp["errorCode"] == 0:
if zpp["results"]["awardType"] == "GOLD":
biz = zpp["results"]["bizNo"]
zpbody = {
"bizNo":biz,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
lj = r.post(zpljurl, headers=headers,json=zpbody)
ljj = json.loads(lj.text)
print("抽到金币"+str(ljj["results"]["amount"]))
elif zpp["results"]["awardType"] == "DOUBLE_VIDEO":
print("抽到双倍卡,需要观看广告")
biz = zpp["results"]["bizNo"]
zpbody = {
"bizNo":biz,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
print("转盘结束,查看可领取那些宝箱")
#转盘5次宝箱奖励body
bx1={"businessType":"XSG_BOX_ONE","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘18次宝箱奖励body
bx2={"businessType":"XSG_BOX_TWO","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘30次宝箱奖励body
bx3={"businessType":"XSG_BOX_THREE","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘55次宝箱奖励body
bx4={"businessType":"XSG_BOX_FOUR","appChannel":"xsgjz_yingyongbao","appVersion":"4.4.20","appPackage":"com.julangling.xsgjz","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","operatingSystem":"ANDROID"}
#转盘宝箱领取
time.sleep(3)
print("开始领转盘5次箱子奖励")
zpbx1 = r.post(zpbxurl, headers=headers,json=bx1)
bxx1 = json.loads(zpbx1.text)
if bxx1["errorCode"] == 0:
results = bxx1['results']
openBoxAwards = results['openBoxAwards']
bx1jb = openBoxAwards[0]['amount']
print("领取成功获得"+str(bx1jb)+"金币")
else:
print("领取失败,原因:"+str(bxx1["errorStr"]))
time.sleep(3)
time.sleep(3)
print("开始领转盘18次箱子奖励")
zpbx2 = r.post(zpbxurl, headers=headers,json=bx2)
bxx2 = json.loads(zpbx2.text)
if bxx2["errorCode"] == 0:
results2 = bxx2['results']
openBoxAwards2 = results2['openBoxAwards']
bx2jb = openBoxAwards2[0]['amount']
print("领取成功获得"+str(bx2jb)+"金币")
bxbizNo2 = bxx2['results']['openBoxAwards'][1]['bizNo']
print("领取箱子双倍卡,需要观看广告")
zpbody = {
"bizNo":bxbizNo2,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
del bxx2
del results2
del openBoxAwards2
del bx2jb
del bxbizNo2
del sb
del sbb
else:
print("领取失败,原因:"+str(bxx2["errorStr"]))
time.sleep(3)
time.sleep(5)
print("开始领转盘30次箱子奖励")
zpbx3 = r.post(zpbxurl, headers=headers,json=bx3)
bxx3 = json.loads(zpbx3.text)
if bxx3["errorCode"] == 0:
results3 = bxx3['results']
openBoxAwards3 = results3['openBoxAwards']
bx3jb = openBoxAwards3[0]['amount']
print("领取成功获得"+str(bx3jb)+"金币")
bxbizNo3 = bxx3['results']['openBoxAwards'][1]['bizNo']
print("领取箱子双倍卡,需要观看广告")
zpbody = {
"bizNo":bxbizNo3,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
del bxx3
del results3
del openBoxAwards3
del bx3jb
del bxbizNo3
del sb
del sbb
else:
print("领取失败,原因:"+str(bxx3["errorStr"]))
time.sleep(3)
time.sleep(3)
print("开始领转盘55次箱子奖励")
zpbx4 = r.post(zpbxurl, headers=headers,json=bx4)
bxx4 = json.loads(zpbx4.text)
if bxx4["errorCode"] == 0:
results4 = bxx4['results']
openBoxAwards4 = results4['openBoxAwards']
bx4jb = openBoxAwards4[0]['amount']
print("领取成功获得"+str(bx4jb)+"金币")
bxbizNo4 = bxx4['results']['openBoxAwards'][1]['bizNo']
print("领取箱子双倍卡,需要观看广告")
zpbody = {
"bizNo":bxbizNo4,
"appChannel":"xsgjz_yingyongbao",
"appVersion":"4.4.20",
"appPackage":"com.julangling.xsgjz",
"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9",
"operatingSystem":"ANDROID"
}
time.sleep(3)
sb = r.post(zpsburl, headers=headers,json=zpbody)
sbb = json.loads(sb.text)
print("观看成功剩余翻倍奖励次数"+str(sbb["results"]["dialCardBag"]["DOUBLE"]))
del bxx4
del results4
del openBoxAwards4
del bx4jb
del bxbizNo4
del sb
del sbb
else:
print("领取失败,原因:"+str(bxx4["errorStr"]))
time.sleep(3)
#扭蛋
vc=1
bc=1
#先刷新扭蛋列表
ndsx = r.get(ndsxurl, headers=headers)
ndsxx = json.loads(ndsx.text)
#判断扭蛋广告可观看次数
ndadcs= ndsxx["results"]["remainVideoTimes"]
print("扭蛋广告剩余次数"+str(ndadcs))
#观看扭蛋广告
for o in range(ndadcs):
print("开始第"+str(bc)+"次观看扭蛋广告")
bc=bc+1
time.sleep(3)
ndadbody={"businessType":"XSG_DAILY_GACHA_INC_VIDEOS","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","version":"4.4.20","os":"ANDROID","appVersion":"4.4.20","appChannel":"unknow"}
ndad = r.post(ndadurl, headers=headers,json=ndadbody)
nddad = json.loads(ndad.text)
if nddad['errorCode'] == 0:
print("获得"+str(nddad["results"]["amount"])+"次抽奖次数")
print("目前有"+str(nddad["results"]["remainTimes"])+"次抽奖次数")
time.sleep(3)
else:
print("扭蛋失败原因"+nddad['errorStr'])
ndsx = r.get(ndsxurl, headers=headers)
ndsxx = json.loads(ndsx.text)
#判断扭蛋次数
ndsycs = ndsxx["results"]["remainTimes"]
print("扭蛋剩余次数"+str(ndsycs))
#开始扭蛋
for o in range(ndsycs):
print("开始第"+str(vc)+"次扭蛋")
vc=vc+1
time.sleep(3)
ndbody={"deviceToken":"19a9e4453155dcbc348f5fbff0c075c9","version":"4.4.20","os":"ANDROID","appVersion":"4.4.20","appChannel":"unknow"}
nd = r.post(ndurl, headers=headers,json=ndbody)
ndd = json.loads(nd.text)
if ndd['errorCode'] == 0:
if ndd["results"]["awardType"] == 'ADVERT':
print("抽到了空气广告")
else:
print("抽到"+str(ndd["results"]["name"]))
else:
print("扭蛋失败原因"+ndd['errorStr'])
time.sleep(3)
#看广告7次
for c in range(7):
qiadbody={"businessType":"XSG_MONEY_CENTER_INCENTIVE_VIDEO","os":"ANDROID","appVersion":"4.4.20","appChannel":"xsgjz_yingyongbao","deviceToken":"19a9e4453155dcbc348f5fbff0c075c9"}
adws = r.post(qiadurl, headers=headers,json=qiadbody)
adwss = json.loads(adws.text)
if adwss['errorCode'] == 0:
adwssjb = adwss["results"]["awardInfos"]
adwssjbb = adwssjb[0]['amount']
print("获得金币"+str(adwssjbb)+"个")
print("等待20秒,才可以观看广告")
time.sleep(21)
else:
break

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,311 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/client/sudojia_opposhop.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/client/sudojia_opposhop.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/client/sudojia_opposhop.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: d6fa1c866188a3794e41b934cbd49a4d18e795230809f23dd9d60583c7f61bfb
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* OPPO商城 APP
*
* 打开抓包、进入我的 - 签到任务
* 抓包 URLhttps://hd.opposhop.cn/api/cn/oapi/users/web/member/check?unpaid=0 获取 Cookie 和 User-Agent
* export OPPOSHOP_COOKIE = 'xxxxxxxxx'
* export OPPO_USER_AGENT = 'Mozilla/5.0 (Linux; Android 10; xxxxxxxxx'
* export OPPO_ACTIVITY_IDS = '签到活动ID#任务列表活动ID'
* OPPO Activity ID 获取说明https://rh-docs.netlify.app/docs/list/client/opposhop/#%E8%8E%B7%E5%8F%96%E8%AF%B4%E6%98%8E
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2024/08/23
*
* const $ = new Env('OPPO商城')
* cron: 25 12 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('OPPO商城');
const oppoList = process.env.OPPOSHOP_COOKIE ? process.env.OPPOSHOP_COOKIE.split(/[\n&]/) : [];
// UserAgent 配置
const UserAgent = process.env.OPPO_USER_AGENT;
// const UserAgent = 'Mozilla/5.0 (Linux; Android 9; OPPO R9s Build/PQ3A.190605.07291528; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36 oppostore/402700 ColorOS/ brand/OPPO model/OPPO R9s;kyc/h5face;kyc/2.0;netType:NETWORK_WIFI;appVersion:402700;packageName:com.oppo.store';
// 消息推送
let message = '';
// 接口地址
const baseUrl = 'https://hd.opposhop.cn'
// 活动集合ID签到活动ID#任务列表活动ID
const activityIdsFromEnv = process.env.OPPO_ACTIVITY_IDS || '1838147945355288576#1838149802563739648';
// 按照 # 分割字符串
const activityIds = activityIdsFromEnv.split('#');
// 签到活动ID
const signActivityId = activityIds[0] || '1838147945355288576';
// 任务列表活动ID
const taskActivityId = activityIds[1] || '1838149802563739648';
// 判断User-Agent
if (!UserAgent) {
console.error('请先填写OPPO商城的 User-Agent、变量名【OPPO_USER_AGENT】');
process.exit(0);
}
// 请求头
const headers = {
'Host': 'hd.opposhop.cn',
'User-Agent': UserAgent,
'Accept-Encoding': 'gzip, deflate',
};
// 签到天数对应奖励ID
const signInDaysMap = {
1327: 3,
1328: 5,
1329: 10,
1330: 15
};
!(async () => {
await checkUpdate($.name, oppoList);
for (let i = 0; i < oppoList.length; i++) {
const index = i + 1;
$.signDayNum = 1;
headers.Cookie = oppoList[i];
console.log(`\n*****第[${index}]个${$.name}账号*****`);
if (!await isLogin()) {
console.error('Cookie 已失效');
await notify.sendNotify(`「Cookie失效通知」`, `${$.name}账号[${index}] Cookie 已失效,请重新登录获取 Cookie\n\n`);
continue;
}
await $.wait(sudojia.getRandomWait(800, 1200))
await main();
await $.wait(sudojia.getRandomWait(2000, 2500));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
async function main() {
await getUserInfo()
await $.wait(sudojia.getRandomWait(1200, 2000));
await getSignInStatus();
await $.wait(sudojia.getRandomWait(1200, 2000));
await getSignDays();
await $.wait(sudojia.getRandomWait(1200, 2000));
await getTaskList();
// 领取累计签到奖励
console.log(`当前累计签到[${$.signDayNum}]天\n`);
for (const [awardId, days] of Object.entries(signInDaysMap)) {
// 只有签到天数达到才领取
if ($.signDayNum >= days) {
console.log(`开始领取[${days}]天累计签到奖励`);
await $.wait(sudojia.getRandomWait(1e3, 2e3));
await receiveSignInAward(parseInt(awardId));
} else {
console.log(`不满足${days}天,跳过领取`)
await $.wait(sudojia.getRandomWait(1e3, 2e3));
}
}
}
/**
* 检测 Cookie 是否有效
* @returns {Promise<boolean>}
*/
async function isLogin() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/task/isLogin`, 'get', headers);
return 403 !== data.code;
} catch (e) {
console.error(`检测 Cookie 是否有效时发生异常 -> `, e);
}
}
/**
* 获取用户信息
*
* @return {Promise<boolean>}
*/
async function getUserInfo() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/users/web/member/check?unpaid=0`, 'get', headers);
if (data.data) {
console.log(`OPPO会员${data.data.name}`);
message += `OPPO会员${data.data.name}\n`;
}
} catch (e) {
console.error(`获取用户信息时发生异常 -> `, e);
}
}
/**
* 获取签到状态
*
* @returns {Promise<void>}
*/
async function getSignInStatus() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/cumulativeSignIn/getSignInDetail?activityId=${signActivityId}`, 'get', headers);
if (data.data) {
if (data.data.todaySignIn) {
console.log('今日已签到');
message += `今日已签到\n`;
return;
}
await $.wait(sudojia.getRandomWait(1200, 1800));
await sign();
} else {
console.error('获取签到状态失败 -> ', data);
}
} catch (e) {
console.error(`获取签到状态时发生异常 -> `, e);
}
}
/**
* 签到
*
* @returns {Promise<void>}
*/
async function sign() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/cumulativeSignIn/signIn`, 'post', headers, {
"activityId": signActivityId
});
if (data.data) {
console.log(`签到成功,积分+${data.data.awardValue}`);
message += `签到成功\n`;
} else {
console.error('签到失败 -> ', data);
}
} catch (e) {
console.error(`签到时发生异常 -> `, e);
}
}
/**
* 获取签到天数
*
* @returns {Promise<void>}
*/
async function getSignDays() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/cumulativeSignIn/getSignInDetail?activityId=${signActivityId}`, 'get', headers);
if (data.data) {
$.signDayNum = data.data.signInDayNum;
console.log(`已连续签到${$.signDayNum}`);
message += `已连续签到${$.signDayNum}\n`;
} else {
console.error('获取签到天数失败 -> ', data);
}
} catch (e) {
console.error(`获取签到天数时发生异常 -> `, e);
}
}
/**
* 获取任务列表
*
* @returns {Promise<void>}
*/
async function getTaskList() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/task/queryTaskList?activityId=${taskActivityId}&source=c`, 'get', headers);
if (data.data) {
const taskList = data.data.taskDTOList;
for (const task of taskList) {
// 排除黑卡和购物
if (6 === task.taskType) {
continue;
}
console.log(`开始[${task.taskName}]任务...`);
await $.wait(sudojia.getRandomWait(1000, 1500));
await completeTask(task.taskId, task.activityId);
await $.wait(sudojia.getRandomWait(2e3, 4e3));
await receiveAward(task.taskName, task.taskId, task.activityId);
await $.wait(sudojia.getRandomWait(1e3, 2e3));
}
message += `\n`;
} else {
console.error('获取任务列表失败 -> ', data.message);
}
} catch (e) {
console.error(`获取任务列表时发生异常 -> `, e);
}
}
/**
* 完成任务
*
* @param taskId
* @param activityId
*
* @returns {Promise<void>}
*/
async function completeTask(taskId, activityId) {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/taskReport/signInOrShareTask?taskId=${taskId}&activityId=${activityId}&taskType=1`, 'get', headers);
if (data.data) {
console.log(`${data.message}`);
} else {
console.error('操作失败 -> ', data.message);
}
} catch (e) {
console.error(`完成任务时发生异常 -> `, e);
}
}
/**
* 领取奖励
*
* @param taskName
* @param taskId
* @param activityId
* @returns {Promise<void>}
*/
async function receiveAward(taskName, taskId, activityId) {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/task/receiveAward?taskId=${taskId}&activityId=${activityId}`, 'get', headers);
if (data.data) {
message += `完成[${taskName}]任务,积分+${data.data.awardValue}\n`;
console.log(`领取成功,积分+${data.data.awardValue}`);
} else {
console.error('领取失败 -> ', data.message);
}
} catch (e) {
console.error(`领取奖励时发生异常 -> `, e);
}
}
/**
* 领取连续签到奖励
*
* @param awardId 1327: 3天奖励
* 1328: 5天奖励
* 1329: 10天奖励
* 1330: 15天奖励
*
* @returns {Promise<void>}
*/
async function receiveSignInAward(awardId) {
try {
const data = await sudojia.sendRequest(`${baseUrl}/api/cn/oapi/marketing/cumulativeSignIn/drawCumulativeAward`, 'post', headers, {
"activityId": signActivityId,
"awardId": awardId
});
if (data.data) {
const days = signInDaysMap[awardId] || '未知';
const awardValue = data.data.awardValue;
if (awardValue.trim().length > 0) {
console.log(`领取累计${days}天奖励成功,获得[${awardValue}]积分\n`);
} else {
console.log(`领取累计${days}天奖励成功,获得[${awardValue}]\n`);
}
} else {
console.error('领取连续签到奖励失败 -> ', data.message);
}
} catch (e) {
console.error(`领取连续签到奖励时发生异常 -> `, e);
}
}

View File

@@ -0,0 +1,125 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/web/sudojia_sspanel.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/web/sudojia_sspanel.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/web/sudojia_sspanel.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: 8bd3374a2bddc90f5a4577c605285a665d61dde740ce6ae4eaad72eb42ea37a5
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* 机场每日签到
*
* 如何鉴别是 SSPANEL 面板?
* 网站拉到最下面有 Powered by SSPANEL 就是 SSPANEL 面板框架的机场
* 格式要求网站1,邮箱1:密码1&网站2,邮箱2:密码2
* export SITE_ACCOUNTS = 'https://paolu.com,abc@gmail.com:123456'
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2021/9/25
* @lastModifyTime: 2024/09/16
*
* const $ = new Env('SSPANEL面板签到')
* cron: 35 9 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('SSPANEL面板签到');
const {default: axios} = require("axios");
const accountList = process.env.SITE_ACCOUNTS ? process.env.SITE_ACCOUNTS.split(/[\n&]/) : [];
// 消息推送
let message = '';
// 请求头
const headers = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"User-Agent": sudojia.getRandomUserAgent('PC'),
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate, br, zstd',
};
!(async () => {
await checkUpdate($.name, accountList);
console.log(`\n已随机分配 User-Agent\n\n${headers['user-agent'] || headers['User-Agent']}`);
// 校验格式
const isValidFormat = accountList.every(account => {
const parts = account.split(',');
if (parts.length !== 2) {
return false;
}
const [site, credentials] = parts;
const credParts = credentials.split(':');
return !(credParts.length !== 2 || !site || !credentials);
});
if (!isValidFormat) {
console.error('格式错误请确保遵循要求格式网站1,邮箱1:密码1&网站2,邮箱2:密码2');
process.exit(0);
}
for (let i = 0; i < accountList.length; i++) {
const index = i + 1;
const [rawUrl, emailPwd] = accountList[i].split(',');
const [email, pwd] = emailPwd.split(':');
const url = rawUrl.endsWith('/') ? rawUrl.slice(0, -1) : rawUrl;
console.log(`\n*****第[${index}]个${$.name}账号*****`);
console.log(`设定的机场网站是:${url}`);
await $.wait(sudojia.getRandomWait(300, 666));
message += `📣====${$.name}账号[${index}]====📣\n`;
await login(url, email, pwd);
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
/**
* 登录
*
* @returns {*}
*/
async function login(url, email, pwd) {
try {
const options = {
url: `${url}/auth/login`,
method: 'POST',
headers: headers,
data: `email=${email}&passwd=${pwd}&code=`
}
const response = await axios(options);
if (1 !== response.data.ret) {
return console.error(`登录失败:${response.data.msg}`);
}
const cookies = response.headers['set-cookie'];
headers.Cookie = cookies.join('; ');
console.log('登录成功~');
await $.wait(sudojia.getRandomWait(800, 1200));
await checkin(url);
} catch (e) {
console.error(`登录时发生异常:${e}`);
}
}
/**
* 签到
*
* @returns {*}
*/
async function checkin(url) {
try {
const data = await sudojia.sendRequest(`${url}/user/checkin`, 'post', headers, {});
if (1 !== data.ret) {
return console.error(`签到失败:${data.msg}`);
}
const {lastUsedTraffic, unUsedTraffic} = data.trafficInfo;
console.log(`签到成功,${data.msg}`);
console.log(`总套餐:${data.traffic}`);
console.log(`已使用:${lastUsedTraffic}`);
console.log(`剩余流量:${unUsedTraffic}`);
message += `签到成功,${data.msg}\n`;
message += `总套餐:${data.traffic}\n`;
message += `已使用:${lastUsedTraffic}\n`;
message += `剩余流量:${unUsedTraffic}\n\n`;
} catch (e) {
console.error(`签到时发生异常:${e}`);
}
}

View File

@@ -0,0 +1,762 @@
# Source: https://github.com/xfmeng970526/ql/blob/main/SendNotify.py
# Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/SendNotify.py
# Repo: xfmeng970526/ql
# Path: SendNotify.py
# UploadedAt: 2023-09-20T12:13:28+08:00
# SHA256: aec54ebb91cd04c64ac7b9a09fcbbd6e18c92cdac8e9cc74320b6c095650e452
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import base64
import hashlib
import hmac
import json
import os
import re
import threading
import time
import urllib.parse
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr
import requests
# 原先的 print 函数和主线程的锁
_print = print
mutex = threading.Lock()
# 定义新的 print 函数
def print(text, *args, **kw):
"""
使输出有序进行,不出现多线程同一时间输出导致错乱的问题。
"""
with mutex:
_print(text, *args, **kw)
# 通知服务
# fmt: off
push_config = {
'HITOKOTO': False, # 启用一言(随机句子)
'BARK_PUSH': '', # bark IP 或设备码https://api.day.app/DxHcxxxxxRxxxxxxcm/
'BARK_ARCHIVE': '', # bark 推送是否存档
'BARK_GROUP': '', # bark 推送分组
'BARK_SOUND': '', # bark 推送声音
'BARK_ICON': '', # bark 推送图标
'CONSOLE': True, # 控制台输出
'DD_BOT_SECRET': '', # 钉钉机器人的 DD_BOT_SECRET
'DD_BOT_TOKEN': '', # 钉钉机器人的 DD_BOT_TOKEN
'FSKEY': '', # 飞书机器人的 FSKEY
'GOBOT_URL': '', # go-cqhttp
# 推送到个人QQhttp://127.0.0.1/send_private_msg
# 群http://127.0.0.1/send_group_msg
'GOBOT_QQ': '', # go-cqhttp 的推送群或用户
# GOBOT_URL 设置 /send_private_msg 时填入 user_id=个人QQ
# /send_group_msg 时填入 group_id=QQ群
'GOBOT_TOKEN': '', # go-cqhttp 的 access_token
'GOTIFY_URL': '', # gotify地址,如https://push.example.de:8080
'GOTIFY_TOKEN': '', # gotify的消息应用token
'GOTIFY_PRIORITY': 0, # 推送消息优先级,默认为0
'IGOT_PUSH_KEY': '', # iGot 聚合推送的 IGOT_PUSH_KEY
'PUSH_KEY': '', # server 酱的 PUSH_KEY兼容旧版与 Turbo 版
'DEER_KEY': '', # PushDeer 的 PUSHDEER_KEY
'DEER_URL': '', # PushDeer 的 PUSHDEER_URL
'CHAT_URL': '', # synology chat url
'CHAT_TOKEN': '', # synology chat token
'PUSH_PLUS_TOKEN': '', # push+ 微信推送的用户令牌
'PUSH_PLUS_USER': '', # push+ 微信推送的群组编码
'QMSG_KEY': '', # qmsg 酱的 QMSG_KEY
'QMSG_TYPE': '', # qmsg 酱的 QMSG_TYPE
'QYWX_ORIGIN': '', # 企业微信代理地址
'QYWX_AM': '', # 企业微信应用
'QYWX_KEY': '', # 企业微信机器人
'TG_BOT_TOKEN': '', # tg 机器人的 TG_BOT_TOKEN1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ
'TG_USER_ID': '', # tg 机器人的 TG_USER_ID1434078534
'TG_API_HOST': '', # tg 代理 api
'TG_PROXY_AUTH': '', # tg 代理认证参数
'TG_PROXY_HOST': '', # tg 机器人的 TG_PROXY_HOST
'TG_PROXY_PORT': '', # tg 机器人的 TG_PROXY_PORT
'AIBOTK_KEY': '', # 智能微秘书 个人中心的apikey 文档地址http://wechat.aibotk.com/docs/about
'AIBOTK_TYPE': '', # 智能微秘书 发送目标 room 或 contact
'AIBOTK_NAME': '', # 智能微秘书 发送群名 或者好友昵称和type要对应好
'SMTP_SERVER': '', # SMTP 发送邮件服务器,形如 smtp.exmail.qq.com:465
'SMTP_SSL': 'false', # SMTP 发送邮件服务器是否使用 SSL填写 true 或 false
'SMTP_EMAIL': '', # SMTP 收发件邮箱,通知将会由自己发给自己
'SMTP_PASSWORD': '', # SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
'SMTP_NAME': '', # SMTP 收发件人姓名,可随意填写
'PUSHME_KEY': '', # PushMe 酱的 PUSHME_KEY
}
notify_function = []
# fmt: on
# 首先读取 面板变量 或者 github action 运行变量
for k in push_config:
if os.getenv(k):
v = os.getenv(k)
push_config[k] = v
def bark(title: str, content: str) -> None:
"""
使用 bark 推送消息。
"""
if not push_config.get("BARK_PUSH"):
print("bark 服务的 BARK_PUSH 未设置!!\n取消推送")
return
print("bark 服务启动")
if push_config.get("BARK_PUSH").startswith("http"):
url = f'{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
else:
url = f'https://api.day.app/{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
bark_params = {
"BARK_ARCHIVE": "isArchive",
"BARK_GROUP": "group",
"BARK_SOUND": "sound",
"BARK_ICON": "icon",
}
params = ""
for pair in filter(
lambda pairs: pairs[0].startswith("BARK_")
and pairs[0] != "BARK_PUSH"
and pairs[1]
and bark_params.get(pairs[0]),
push_config.items(),
):
params += f"{bark_params.get(pair[0])}={pair[1]}&"
if params:
url = url + "?" + params.rstrip("&")
response = requests.get(url).json()
if response["code"] == 200:
print("bark 推送成功!")
else:
print("bark 推送失败!")
def console(title: str, content: str) -> None:
"""
使用 控制台 推送消息。
"""
# print(f"{title}\n\n{content}")
def dingding_bot(title: str, content: str) -> None:
"""
使用 钉钉机器人 推送消息。
"""
if not push_config.get("DD_BOT_SECRET") or not push_config.get("DD_BOT_TOKEN"):
print("钉钉机器人 服务的 DD_BOT_SECRET 或者 DD_BOT_TOKEN 未设置!!\n取消推送")
return
print("钉钉机器人 服务启动")
timestamp = str(round(time.time() * 1000))
secret_enc = push_config.get("DD_BOT_SECRET").encode("utf-8")
string_to_sign = "{}\n{}".format(timestamp, push_config.get("DD_BOT_SECRET"))
string_to_sign_enc = string_to_sign.encode("utf-8")
hmac_code = hmac.new(
secret_enc, string_to_sign_enc, digestmod=hashlib.sha256
).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
url = f'https://oapi.dingtalk.com/robot/send?access_token={push_config.get("DD_BOT_TOKEN")}&timestamp={timestamp}&sign={sign}'
headers = {"Content-Type": "application/json;charset=utf-8"}
data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
response = requests.post(
url=url, data=json.dumps(data), headers=headers, timeout=15
).json()
if not response["errcode"]:
print("钉钉机器人 推送成功!")
else:
print("钉钉机器人 推送失败!")
def feishu_bot(title: str, content: str) -> None:
"""
使用 飞书机器人 推送消息。
"""
if not push_config.get("FSKEY"):
print("飞书 服务的 FSKEY 未设置!!\n取消推送")
return
print("飞书 服务启动")
url = f'https://open.feishu.cn/open-apis/bot/v2/hook/{push_config.get("FSKEY")}'
data = {"msg_type": "text", "content": {"text": f"{title}\n\n{content}"}}
response = requests.post(url, data=json.dumps(data)).json()
if response.get("StatusCode") == 0:
print("飞书 推送成功!")
else:
print("飞书 推送失败!错误信息如下:\n", response)
def go_cqhttp(title: str, content: str) -> None:
"""
使用 go_cqhttp 推送消息。
"""
if not push_config.get("GOBOT_URL") or not push_config.get("GOBOT_QQ"):
print("go-cqhttp 服务的 GOBOT_URL 或 GOBOT_QQ 未设置!!\n取消推送")
return
print("go-cqhttp 服务启动")
url = f'{push_config.get("GOBOT_URL")}?access_token={push_config.get("GOBOT_TOKEN")}&{push_config.get("GOBOT_QQ")}&message={title}\n{content}'
response = requests.get(url).json()
if response["status"] == "ok":
print("go-cqhttp 推送成功!")
else:
print("go-cqhttp 推送失败!")
def gotify(title: str, content: str) -> None:
"""
使用 gotify 推送消息。
"""
if not push_config.get("GOTIFY_URL") or not push_config.get("GOTIFY_TOKEN"):
print("gotify 服务的 GOTIFY_URL 或 GOTIFY_TOKEN 未设置!!\n取消推送")
return
print("gotify 服务启动")
url = f'{push_config.get("GOTIFY_URL")}/message?token={push_config.get("GOTIFY_TOKEN")}'
data = {
"title": title,
"message": content,
"priority": push_config.get("GOTIFY_PRIORITY"),
}
response = requests.post(url, data=data).json()
if response.get("id"):
print("gotify 推送成功!")
else:
print("gotify 推送失败!")
def iGot(title: str, content: str) -> None:
"""
使用 iGot 推送消息。
"""
if not push_config.get("IGOT_PUSH_KEY"):
print("iGot 服务的 IGOT_PUSH_KEY 未设置!!\n取消推送")
return
print("iGot 服务启动")
url = f'https://push.hellyw.com/{push_config.get("IGOT_PUSH_KEY")}'
data = {"title": title, "content": content}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=data, headers=headers).json()
if response["ret"] == 0:
print("iGot 推送成功!")
else:
print(f'iGot 推送失败!{response["errMsg"]}')
def serverJ(title: str, content: str) -> None:
"""
通过 serverJ 推送消息。
"""
if not push_config.get("PUSH_KEY"):
print("serverJ 服务的 PUSH_KEY 未设置!!\n取消推送")
return
print("serverJ 服务启动")
data = {"text": title, "desp": content.replace("\n", "\n\n")}
if push_config.get("PUSH_KEY").find("SCT") != -1:
url = f'https://sctapi.ftqq.com/{push_config.get("PUSH_KEY")}.send'
else:
url = f'https://sc.ftqq.com/{push_config.get("PUSH_KEY")}.send'
response = requests.post(url, data=data).json()
if response.get("errno") == 0 or response.get("code") == 0:
print("serverJ 推送成功!")
else:
print(f'serverJ 推送失败!错误码:{response["message"]}')
def pushdeer(title: str, content: str) -> None:
"""
通过PushDeer 推送消息
"""
if not push_config.get("DEER_KEY"):
print("PushDeer 服务的 DEER_KEY 未设置!!\n取消推送")
return
print("PushDeer 服务启动")
data = {
"text": title,
"desp": content,
"type": "markdown",
"pushkey": push_config.get("DEER_KEY"),
}
url = "https://api2.pushdeer.com/message/push"
if push_config.get("DEER_URL"):
url = push_config.get("DEER_URL")
response = requests.post(url, data=data).json()
if len(response.get("content").get("result")) > 0:
print("PushDeer 推送成功!")
else:
print("PushDeer 推送失败!错误信息:", response)
def chat(title: str, content: str) -> None:
"""
通过Chat 推送消息
"""
if not push_config.get("CHAT_URL") or not push_config.get("CHAT_TOKEN"):
print("chat 服务的 CHAT_URL或CHAT_TOKEN 未设置!!\n取消推送")
return
print("chat 服务启动")
data = "payload=" + json.dumps({"text": title + "\n" + content})
url = push_config.get("CHAT_URL") + push_config.get("CHAT_TOKEN")
response = requests.post(url, data=data)
if response.status_code == 200:
print("Chat 推送成功!")
else:
print("Chat 推送失败!错误信息:", response)
def pushplus_bot(title: str, content: str) -> None:
"""
通过 push+ 推送消息。
"""
if not push_config.get("PUSH_PLUS_TOKEN"):
print("PUSHPLUS 服务的 PUSH_PLUS_TOKEN 未设置!!\n取消推送")
return
print("PUSHPLUS 服务启动")
url = "http://www.pushplus.plus/send"
data = {
"token": push_config.get("PUSH_PLUS_TOKEN"),
"title": title,
"content": content,
"topic": push_config.get("PUSH_PLUS_USER"),
}
body = json.dumps(data).encode(encoding="utf-8")
headers = {"Content-Type": "application/json"}
response = requests.post(url=url, data=body, headers=headers).json()
if response["code"] == 200:
print("PUSHPLUS 推送成功!")
else:
url_old = "http://pushplus.hxtrip.com/send"
headers["Accept"] = "application/json"
response = requests.post(url=url_old, data=body, headers=headers).json()
if response["code"] == 200:
print("PUSHPLUS(hxtrip) 推送成功!")
else:
print("PUSHPLUS 推送失败!")
def qmsg_bot(title: str, content: str) -> None:
"""
使用 qmsg 推送消息。
"""
if not push_config.get("QMSG_KEY") or not push_config.get("QMSG_TYPE"):
print("qmsg 的 QMSG_KEY 或者 QMSG_TYPE 未设置!!\n取消推送")
return
print("qmsg 服务启动")
url = f'https://qmsg.zendee.cn/{push_config.get("QMSG_TYPE")}/{push_config.get("QMSG_KEY")}'
payload = {"msg": f'{title}\n\n{content.replace("----", "-")}'.encode("utf-8")}
response = requests.post(url=url, params=payload).json()
if response["code"] == 0:
print("qmsg 推送成功!")
else:
print(f'qmsg 推送失败!{response["reason"]}')
def wecom_app(title: str, content: str) -> None:
"""
通过 企业微信 APP 推送消息。
"""
if not push_config.get("QYWX_AM"):
print("QYWX_AM 未设置!!\n取消推送")
return
QYWX_AM_AY = re.split(",", push_config.get("QYWX_AM"))
if 4 < len(QYWX_AM_AY) > 5:
print("QYWX_AM 设置错误!!\n取消推送")
return
print("企业微信 APP 服务启动")
corpid = QYWX_AM_AY[0]
corpsecret = QYWX_AM_AY[1]
touser = QYWX_AM_AY[2]
agentid = QYWX_AM_AY[3]
try:
media_id = QYWX_AM_AY[4]
except IndexError:
media_id = ""
wx = WeCom(corpid, corpsecret, agentid)
# 如果没有配置 media_id 默认就以 text 方式发送
if not media_id:
message = title + "\n\n" + content
response = wx.send_text(message, touser)
else:
response = wx.send_mpnews(title, content, media_id, touser)
if response == "ok":
print("企业微信推送成功!")
else:
print("企业微信推送失败!错误信息如下:\n", response)
class WeCom:
def __init__(self, corpid, corpsecret, agentid):
self.CORPID = corpid
self.CORPSECRET = corpsecret
self.AGENTID = agentid
self.ORIGIN = "https://qyapi.weixin.qq.com"
if push_config.get("QYWX_ORIGIN"):
self.ORIGIN = push_config.get("QYWX_ORIGIN")
def get_access_token(self):
url = f"{self.ORIGIN}/cgi-bin/gettoken"
values = {
"corpid": self.CORPID,
"corpsecret": self.CORPSECRET,
}
req = requests.post(url, params=values)
data = json.loads(req.text)
return data["access_token"]
def send_text(self, message, touser="@all"):
send_url = f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
send_values = {
"touser": touser,
"msgtype": "text",
"agentid": self.AGENTID,
"text": {"content": message},
"safe": "0",
}
send_msges = bytes(json.dumps(send_values), "utf-8")
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
def send_mpnews(self, title, message, media_id, touser="@all"):
send_url = f"https://{self.HOST}/cgi-bin/message/send?access_token={self.get_access_token()}"
send_values = {
"touser": touser,
"msgtype": "mpnews",
"agentid": self.AGENTID,
"mpnews": {
"articles": [
{
"title": title,
"thumb_media_id": media_id,
"author": "Author",
"content_source_url": "",
"content": message.replace("\n", "<br/>"),
"digest": message,
}
]
},
}
send_msges = bytes(json.dumps(send_values), "utf-8")
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
def wecom_bot(title: str, content: str) -> None:
"""
通过 企业微信机器人 推送消息。
"""
if not push_config.get("QYWX_KEY"):
print("企业微信机器人 服务的 QYWX_KEY 未设置!!\n取消推送")
return
print("企业微信机器人服务启动")
origin = "https://qyapi.weixin.qq.com"
if push_config.get("QYWX_ORIGIN"):
origin = push_config.get("QYWX_ORIGIN")
url = f"{origin}/cgi-bin/webhook/send?key={push_config.get('QYWX_KEY')}"
headers = {"Content-Type": "application/json;charset=utf-8"}
data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
response = requests.post(
url=url, data=json.dumps(data), headers=headers, timeout=15
).json()
if response["errcode"] == 0:
print("企业微信机器人推送成功!")
else:
print("企业微信机器人推送失败!")
def telegram_bot(title: str, content: str) -> None:
"""
使用 telegram 机器人 推送消息。
"""
if not push_config.get("TG_BOT_TOKEN") or not push_config.get("TG_USER_ID"):
print("tg 服务的 bot_token 或者 user_id 未设置!!\n取消推送")
return
print("tg 服务启动")
if push_config.get("TG_API_HOST"):
url = f"https://{push_config.get('TG_API_HOST')}/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
else:
url = (
f"https://api.telegram.org/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
)
headers = {"Content-Type": "application/x-www-form-urlencoded"}
payload = {
"chat_id": str(push_config.get("TG_USER_ID")),
"text": f"{title}\n\n{content}",
"disable_web_page_preview": "true",
}
proxies = None
if push_config.get("TG_PROXY_HOST") and push_config.get("TG_PROXY_PORT"):
if push_config.get("TG_PROXY_AUTH") is not None and "@" not in push_config.get(
"TG_PROXY_HOST"
):
push_config["TG_PROXY_HOST"] = (
push_config.get("TG_PROXY_AUTH")
+ "@"
+ push_config.get("TG_PROXY_HOST")
)
proxyStr = "http://{}:{}".format(
push_config.get("TG_PROXY_HOST"), push_config.get("TG_PROXY_PORT")
)
proxies = {"http": proxyStr, "https": proxyStr}
response = requests.post(
url=url, headers=headers, params=payload, proxies=proxies
).json()
if response["ok"]:
print("tg 推送成功!")
else:
print("tg 推送失败!")
def aibotk(title: str, content: str) -> None:
"""
使用 智能微秘书 推送消息。
"""
if (
not push_config.get("AIBOTK_KEY")
or not push_config.get("AIBOTK_TYPE")
or not push_config.get("AIBOTK_NAME")
):
print("智能微秘书 的 AIBOTK_KEY 或者 AIBOTK_TYPE 或者 AIBOTK_NAME 未设置!!\n取消推送")
return
print("智能微秘书 服务启动")
if push_config.get("AIBOTK_TYPE") == "room":
url = "https://api-bot.aibotk.com/openapi/v1/chat/room"
data = {
"apiKey": push_config.get("AIBOTK_KEY"),
"roomName": push_config.get("AIBOTK_NAME"),
"message": {"type": 1, "content": f"【青龙快讯】\n\n{title}\n{content}"},
}
else:
url = "https://api-bot.aibotk.com/openapi/v1/chat/contact"
data = {
"apiKey": push_config.get("AIBOTK_KEY"),
"name": push_config.get("AIBOTK_NAME"),
"message": {"type": 1, "content": f"【青龙快讯】\n\n{title}\n{content}"},
}
body = json.dumps(data).encode(encoding="utf-8")
headers = {"Content-Type": "application/json"}
response = requests.post(url=url, data=body, headers=headers).json()
print(response)
if response["code"] == 0:
print("智能微秘书 推送成功!")
else:
print(f'智能微秘书 推送失败!{response["error"]}')
def smtp(title: str, content: str) -> None:
"""
使用 SMTP 邮件 推送消息。
"""
if (
not push_config.get("SMTP_SERVER")
or not push_config.get("SMTP_SSL")
or not push_config.get("SMTP_EMAIL")
or not push_config.get("SMTP_PASSWORD")
or not push_config.get("SMTP_NAME")
):
print(
"SMTP 邮件 的 SMTP_SERVER 或者 SMTP_SSL 或者 SMTP_EMAIL 或者 SMTP_PASSWORD 或者 SMTP_NAME 未设置!!\n取消推送"
)
return
print("SMTP 邮件 服务启动")
message = MIMEText(content, "plain", "utf-8")
message["From"] = formataddr(
(
Header(push_config.get("SMTP_NAME"), "utf-8").encode(),
push_config.get("SMTP_EMAIL"),
)
)
message["To"] = formataddr(
(
Header(push_config.get("SMTP_NAME"), "utf-8").encode(),
push_config.get("SMTP_EMAIL"),
)
)
message["Subject"] = Header(title, "utf-8")
try:
smtp_server = (
smtplib.SMTP_SSL(push_config.get("SMTP_SERVER"))
if push_config.get("SMTP_SSL") == "true"
else smtplib.SMTP(push_config.get("SMTP_SERVER"))
)
smtp_server.login(
push_config.get("SMTP_EMAIL"), push_config.get("SMTP_PASSWORD")
)
smtp_server.sendmail(
push_config.get("SMTP_EMAIL"),
push_config.get("SMTP_EMAIL"),
message.as_bytes(),
)
smtp_server.close()
print("SMTP 邮件 推送成功!")
except Exception as e:
print(f"SMTP 邮件 推送失败!{e}")
def pushme(title: str, content: str) -> None:
"""
使用 PushMe 推送消息。
"""
if not push_config.get("PUSHME_KEY"):
print("PushMe 服务的 PUSHME_KEY 未设置!!\n取消推送")
return
print("PushMe 服务启动")
url = f'https://push.i-i.me/?push_key={push_config.get("PUSHME_KEY")}'
data = {
"title": title,
"content": content,
}
response = requests.post(url, data=data)
if response.status_code == 200 and response.text == "success":
print("PushMe 推送成功!")
else:
print(f"PushMe 推送失败!{response.status_code} {response.text}")
def one() -> str:
"""
获取一条一言。
:return:
"""
url = "https://v1.hitokoto.cn/"
res = requests.get(url).json()
return res["hitokoto"] + " ----" + res["from"]
if push_config.get("BARK_PUSH"):
notify_function.append(bark)
if push_config.get("CONSOLE"):
notify_function.append(console)
if push_config.get("DD_BOT_TOKEN") and push_config.get("DD_BOT_SECRET"):
notify_function.append(dingding_bot)
if push_config.get("FSKEY"):
notify_function.append(feishu_bot)
if push_config.get("GOBOT_URL") and push_config.get("GOBOT_QQ"):
notify_function.append(go_cqhttp)
if push_config.get("GOTIFY_URL") and push_config.get("GOTIFY_TOKEN"):
notify_function.append(gotify)
if push_config.get("IGOT_PUSH_KEY"):
notify_function.append(iGot)
if push_config.get("PUSH_KEY"):
notify_function.append(serverJ)
if push_config.get("DEER_KEY"):
notify_function.append(pushdeer)
if push_config.get("CHAT_URL") and push_config.get("CHAT_TOKEN"):
notify_function.append(chat)
if push_config.get("PUSH_PLUS_TOKEN"):
notify_function.append(pushplus_bot)
if push_config.get("QMSG_KEY") and push_config.get("QMSG_TYPE"):
notify_function.append(qmsg_bot)
if push_config.get("QYWX_AM"):
notify_function.append(wecom_app)
if push_config.get("QYWX_KEY"):
notify_function.append(wecom_bot)
if push_config.get("TG_BOT_TOKEN") and push_config.get("TG_USER_ID"):
notify_function.append(telegram_bot)
if (
push_config.get("AIBOTK_KEY")
and push_config.get("AIBOTK_TYPE")
and push_config.get("AIBOTK_NAME")
):
notify_function.append(aibotk)
if (
push_config.get("SMTP_SERVER")
and push_config.get("SMTP_SSL")
and push_config.get("SMTP_EMAIL")
and push_config.get("SMTP_PASSWORD")
and push_config.get("SMTP_NAME")
):
notify_function.append(smtp)
if push_config.get("PUSHME_KEY"):
notify_function.append(pushme)
def send(title: str, content: str) -> None:
if not content:
print(f"{title} 推送内容为空!")
return
# 根据标题跳过一些消息推送环境变量SKIP_PUSH_TITLE 用回车分隔
skipTitle = os.getenv("SKIP_PUSH_TITLE")
if skipTitle:
if title in re.split("\n", skipTitle):
print(f"{title} 在SKIP_PUSH_TITLE环境变量内跳过推送")
return
hitokoto = push_config.get("HITOKOTO")
text = one() if hitokoto else ""
content += "大自然的搬运工\nhttp://www.bedee.top/\n\n" + text
ts = [
threading.Thread(target=mode, args=(title, content), name=mode.__name__)
for mode in notify_function
]
[t.start() for t in ts]
[t.join() for t in ts]
def main():
send("title", "content")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,164 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/web/sudojia_v2ex.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/web/sudojia_v2ex.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/web/sudojia_v2ex.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: e79de91c9a8a74b74490bd2e55f3dadbc876f960a00be966caf61fde2f50c7ae
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* v2ex 每日签到 https://www.v2ex.com/
*
* export V2EX_COOKIE = 'xxxxx'
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2024/5/22
*
* const $ = new Env('V2EX每日签到')
* cron: 0 9 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('V2EX每日签到');
const cheerio = require('cheerio');
const v2exList = process.env.V2EX_COOKIE ? process.env.V2EX_COOKIE.split(/[\n&]/) : [];
let message = '';
// 接口地址
const baseUrl = 'https://www.v2ex.com';
// 请求头
const headers = {
'Accept-Encoding': `gzip, deflate, br`,
'Connection': `keep-alive`,
'Accept': `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`,
"User-Agent": sudojia.getRandomUserAgent('PC'),
};
!(async () => {
await checkUpdate($.name, v2exList);
console.log(`\n已随机分配 User-Agent\n\n${headers['user-agent'] || headers['User-Agent']}`);
for (let i = 0; i < v2exList.length; i++) {
const index = i + 1;
headers.Cookie = v2exList[i];
console.log(`\n*****第[${index}]个${$.name}账号*****`);
const isCookie = await checkCookie();
if (!isCookie) {
console.error('Cookie 已失效');
await notify.sendNotify(`「Cookie失效通知」`, `${$.name}账号[${index}] Cookie 已失效,请重新登录获取 Cookie\n\n`);
continue;
}
message += `📣====${$.name}账号[${index}]====📣\n`;
await $.wait(sudojia.getRandomWait(800, 1200));
await main();
await $.wait(sudojia.getRandomWait(2000, 3000));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
async function main() {
await getOnce();
await wait();
await getInfo();
}
/**
* 检测 Cookie 有效返回 true
*
* @return {Promise<boolean>}
*/
async function checkCookie() {
try {
const data = await sudojia.sendRequest('https://v2ex.com/', 'get', headers);
return data.indexOf('登出') > -1;
} catch (e) {
console.error(`检测 Cookie 状态发生异常:${e}`);
return false;
}
}
/**
* 获取once
*
* @returns {Promise<void>}
*/
async function getOnce() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/mission/daily`, 'GET', headers, {})
const $ = cheerio.load(data);
const targetLink = $('a.top').eq(1);
const userName = targetLink.text();
message += `【用户名称】${userName}\n`
if (data.indexOf('每日登录奖励已领取') < 0) {
console.log('开始签到...')
const once = $('input[type="button"]')[0].attribs['onclick'].match(/once=(\d+)/)[1];
await wait();
await checkIn(once);
} else {
message += `【签到状态】已经签到过了\n`
console.log('已经签到过了');
}
} catch (e) {
console.error(`获取 once 发生异常:${e}`);
}
}
/**
* 签到
*
* @param once
* @returns {Promise<void>}
*/
async function checkIn(once) {
try {
const data = await sudojia.sendRequest(`${baseUrl}/mission/daily/redeem?once=${once}`, 'GET', headers, {})
if (data.indexOf('每日登录奖励已领取') > -1) {
console.log('签到成功');
message += `【签到状态】签到成功!\n`
const continueDays = data.match(/已连续登录 (\d+?) 天/)[1];
message += `【签到统计】已连续签到${continueDays}\n`
} else {
console.log('签到失败');
}
} catch (e) {
console.error(`签到时发生异常:${e}`);
}
}
/**
* 获取用户信息
*
* @return {Promise<void>}
*/
async function getInfo() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/balance`, 'GET', headers, {})
const $ = cheerio.load(data);
const balanceArea = $('.balance_area').first();
// 提取文本内容
const text = balanceArea.text();
// 使用正则表达式匹配数字
const matches = text.match(/\d+/g);
let goldAmount = 0;
let silverAmount = 0;
let bronzeAmount = 0;
// 如果匹配到三个数字,则分别赋值给金币、银币和铜币
if (matches && matches.length === 3) {
goldAmount = parseInt(matches[0], 10);
silverAmount = parseInt(matches[1], 10);
bronzeAmount = parseInt(matches[2], 10);
} else if (matches && matches.length === 2) {
silverAmount = parseInt(matches[0], 10);
bronzeAmount = parseInt(matches[1], 10);
}
message += `【账户余额】${goldAmount}金币 ${silverAmount}银币 ${bronzeAmount}铜币\n\n`
} catch (e) {
console.error(`获取获取用户信息时发生异常:${e}`);
}
}
async function wait() {
await $.wait(sudojia.getRandomWait(2000, 3000));
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,694 @@
# Source: https://github.com/NaroisCool/naro-scripts/blob/master/notify.py
# Raw: https://raw.githubusercontent.com/NaroisCool/naro-scripts/master/notify.py
# Repo: NaroisCool/naro-scripts
# Path: notify.py
# UploadedAt: 2025-10-28T05:54:28+08:00
# SHA256: fef1ad8139e93869700df4511cb0027799e5341762d312d1e23e98ff74fcca36
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import base64
import hashlib
import hmac
import json
import os
import re
import threading
import time
import urllib.parse
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr
import requests
# 原先的 print 函数和主线程的锁
_print = print
mutex = threading.Lock()
# 定义新的 print 函数
def print(text, *args, **kw):
"""
使输出有序进行,不出现多线程同一时间输出导致错乱的问题。
"""
with mutex:
_print(text, *args, **kw)
# 通知服务
# fmt: off
push_config = {
'HITOKOTO': False, # 启用一言(随机句子)
'BARK_PUSH': '', # bark IP 或设备码https://api.day.app/DxHcxxxxxRxxxxxxcm/
'BARK_ARCHIVE': '', # bark 推送是否存档
'BARK_GROUP': '', # bark 推送分组
'BARK_SOUND': '', # bark 推送声音
'BARK_ICON': '', # bark 推送图标
'CONSOLE': True, # 控制台输出
'DD_BOT_SECRET': '', # 钉钉机器人的 DD_BOT_SECRET
'DD_BOT_TOKEN': '', # 钉钉机器人的 DD_BOT_TOKEN
'FSKEY': '', # 飞书机器人的 FSKEY
'GOBOT_URL': '', # go-cqhttp
# 推送到个人QQhttp://127.0.0.1/send_private_msg
# 群http://127.0.0.1/send_group_msg
'GOBOT_QQ': '', # go-cqhttp 的推送群或用户
# GOBOT_URL 设置 /send_private_msg 时填入 user_id=个人QQ
# /send_group_msg 时填入 group_id=QQ群
'GOBOT_TOKEN': '', # go-cqhttp 的 access_token
'GOTIFY_URL': '', # gotify地址,如https://push.example.de:8080
'GOTIFY_TOKEN': '', # gotify的消息应用token
'GOTIFY_PRIORITY': 0, # 推送消息优先级,默认为0
'IGOT_PUSH_KEY': '', # iGot 聚合推送的 IGOT_PUSH_KEY
'PUSH_KEY': '', # server 酱的 PUSH_KEY兼容旧版与 Turbo 版
'DEER_KEY': '', # PushDeer 的 PUSHDEER_KEY
'DEER_URL': '', # PushDeer 的 PUSHDEER_URL
'CHAT_URL': '', # synology chat url
'CHAT_TOKEN': '', # synology chat token
'PUSH_PLUS_TOKEN': '', # push+ 微信推送的用户令牌
'PUSH_PLUS_USER': '', # push+ 微信推送的群组编码
'QMSG_KEY': '', # qmsg 酱的 QMSG_KEY
'QMSG_TYPE': '', # qmsg 酱的 QMSG_TYPE
'QYWX_AM': '', # 企业微信应用
'QYWX_KEY': '', # 企业微信机器人
'TG_BOT_TOKEN': '', # tg 机器人的 TG_BOT_TOKEN1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ
'TG_USER_ID': '', # tg 机器人的 TG_USER_ID1434078534
'TG_API_HOST': '', # tg 代理 api
'TG_PROXY_AUTH': '', # tg 代理认证参数
'TG_PROXY_HOST': '', # tg 机器人的 TG_PROXY_HOST
'TG_PROXY_PORT': '', # tg 机器人的 TG_PROXY_PORT
'AIBOTK_KEY': '', # 智能微秘书 个人中心的apikey 文档地址http://wechat.aibotk.com/docs/about
'AIBOTK_TYPE': '', # 智能微秘书 发送目标 room 或 contact
'AIBOTK_NAME': '', # 智能微秘书 发送群名 或者好友昵称和type要对应好
'SMTP_SERVER': '', # SMTP 发送邮件服务器,形如 smtp.exmail.qq.com:465
'SMTP_SSL': 'false', # SMTP 发送邮件服务器是否使用 SSL填写 true 或 false
'SMTP_EMAIL': '', # SMTP 收发件邮箱,通知将会由自己发给自己
'SMTP_PASSWORD': '', # SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
'SMTP_NAME': '', # SMTP 收发件人姓名,可随意填写
}
notify_function = []
# fmt: on
# 首先读取 面板变量 或者 github action 运行变量
for k in push_config:
if os.getenv(k):
v = os.getenv(k)
push_config[k] = v
def bark(title: str, content: str) -> None:
"""
使用 bark 推送消息。
"""
if not push_config.get("BARK_PUSH"):
print("bark 服务的 BARK_PUSH 未设置!!\n取消推送")
return
print("bark 服务启动")
if push_config.get("BARK_PUSH").startswith("http"):
url = f'{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
else:
url = f'https://api.day.app/{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
bark_params = {
"BARK_ARCHIVE": "isArchive",
"BARK_GROUP": "group",
"BARK_SOUND": "sound",
"BARK_ICON": "icon",
}
params = ""
for pair in filter(
lambda pairs: pairs[0].startswith("BARK_")
and pairs[0] != "BARK_PUSH"
and pairs[1]
and bark_params.get(pairs[0]),
push_config.items(),
):
params += f"{bark_params.get(pair[0])}={pair[1]}&"
if params:
url = url + "?" + params.rstrip("&")
response = requests.get(url).json()
if response["code"] == 200:
print("bark 推送成功!")
else:
print("bark 推送失败!")
def console(title: str, content: str) -> None:
"""
使用 控制台 推送消息。
"""
print(f"{title}\n\n{content}")
def dingding_bot(title: str, content: str) -> None:
"""
使用 钉钉机器人 推送消息。
"""
if not push_config.get("DD_BOT_SECRET") or not push_config.get("DD_BOT_TOKEN"):
print("钉钉机器人 服务的 DD_BOT_SECRET 或者 DD_BOT_TOKEN 未设置!!\n取消推送")
return
print("钉钉机器人 服务启动")
timestamp = str(round(time.time() * 1000))
secret_enc = push_config.get("DD_BOT_SECRET").encode("utf-8")
string_to_sign = "{}\n{}".format(
timestamp, push_config.get("DD_BOT_SECRET"))
string_to_sign_enc = string_to_sign.encode("utf-8")
hmac_code = hmac.new(
secret_enc, string_to_sign_enc, digestmod=hashlib.sha256
).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
url = f'https://oapi.dingtalk.com/robot/send?access_token={push_config.get("DD_BOT_TOKEN")}&timestamp={timestamp}&sign={sign}'
headers = {"Content-Type": "application/json;charset=utf-8"}
data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
response = requests.post(
url=url, data=json.dumps(data), headers=headers, timeout=15
).json()
if not response["errcode"]:
print("钉钉机器人 推送成功!")
else:
print("钉钉机器人 推送失败!")
def feishu_bot(title: str, content: str) -> None:
"""
使用 飞书机器人 推送消息。
"""
if not push_config.get("FSKEY"):
print("飞书 服务的 FSKEY 未设置!!\n取消推送")
return
print("飞书 服务启动")
url = f'https://open.feishu.cn/open-apis/bot/v2/hook/{push_config.get("FSKEY")}'
data = {"msg_type": "text", "content": {"text": f"{title}\n\n{content}"}}
response = requests.post(url, data=json.dumps(data)).json()
if response.get("StatusCode") == 0:
print("飞书 推送成功!")
else:
print("飞书 推送失败!错误信息如下:\n", response)
def go_cqhttp(title: str, content: str) -> None:
"""
使用 go_cqhttp 推送消息。
"""
if not push_config.get("GOBOT_URL") or not push_config.get("GOBOT_QQ"):
print("go-cqhttp 服务的 GOBOT_URL 或 GOBOT_QQ 未设置!!\n取消推送")
return
print("go-cqhttp 服务启动")
url = f'{push_config.get("GOBOT_URL")}?access_token={push_config.get("GOBOT_TOKEN")}&{push_config.get("GOBOT_QQ")}&message=标题:{title}\n内容:{content}'
response = requests.get(url).json()
if response["status"] == "ok":
print("go-cqhttp 推送成功!")
else:
print("go-cqhttp 推送失败!")
def gotify(title: str, content: str) -> None:
"""
使用 gotify 推送消息。
"""
if not push_config.get("GOTIFY_URL") or not push_config.get("GOTIFY_TOKEN"):
print("gotify 服务的 GOTIFY_URL 或 GOTIFY_TOKEN 未设置!!\n取消推送")
return
print("gotify 服务启动")
url = f'{push_config.get("GOTIFY_URL")}/message?token={push_config.get("GOTIFY_TOKEN")}'
data = {"title": title, "message": content,
"priority": push_config.get("GOTIFY_PRIORITY")}
response = requests.post(url, data=data).json()
if response.get("id"):
print("gotify 推送成功!")
else:
print("gotify 推送失败!")
def iGot(title: str, content: str) -> None:
"""
使用 iGot 推送消息。
"""
if not push_config.get("IGOT_PUSH_KEY"):
print("iGot 服务的 IGOT_PUSH_KEY 未设置!!\n取消推送")
return
print("iGot 服务启动")
url = f'https://push.hellyw.com/{push_config.get("IGOT_PUSH_KEY")}'
data = {"title": title, "content": content}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=data, headers=headers).json()
if response["ret"] == 0:
print("iGot 推送成功!")
else:
print(f'iGot 推送失败!{response["errMsg"]}')
def serverJ(title: str, content: str) -> None:
"""
通过 serverJ 推送消息。
"""
if not push_config.get("PUSH_KEY"):
print("serverJ 服务的 PUSH_KEY 未设置!!\n取消推送")
return
print("serverJ 服务启动")
data = {"text": title, "desp": content.replace("\n", "\n\n")}
if push_config.get("PUSH_KEY").find("SCT") != -1:
url = f'https://sctapi.ftqq.com/{push_config.get("PUSH_KEY")}.send'
else:
url = f'https://sc.ftqq.com/{push_config.get("PUSH_KEY")}.send'
response = requests.post(url, data=data).json()
if response.get("errno") == 0 or response.get("code") == 0:
print("serverJ 推送成功!")
else:
print(f'serverJ 推送失败!错误码:{response["message"]}')
def pushdeer(title: str, content: str) -> None:
"""
通过PushDeer 推送消息
"""
if not push_config.get("DEER_KEY"):
print("PushDeer 服务的 DEER_KEY 未设置!!\n取消推送")
return
print("PushDeer 服务启动")
data = {"text": title, "desp": content, "type": "markdown",
"pushkey": push_config.get("DEER_KEY")}
url = 'https://api2.pushdeer.com/message/push'
if push_config.get("DEER_URL"):
url = push_config.get("DEER_URL")
response = requests.post(url, data=data).json()
if len(response.get("content").get("result")) > 0:
print("PushDeer 推送成功!")
else:
print("PushDeer 推送失败!错误信息:", response)
def chat(title: str, content: str) -> None:
"""
通过Chat 推送消息
"""
if not push_config.get("CHAT_URL") or not push_config.get("CHAT_TOKEN"):
print("chat 服务的 CHAT_URL或CHAT_TOKEN 未设置!!\n取消推送")
return
print("chat 服务启动")
data = 'payload=' + json.dumps({'text': title + '\n' + content})
url = push_config.get("CHAT_URL") + push_config.get("CHAT_TOKEN")
response = requests.post(url, data=data)
if response.status_code == 200:
print("Chat 推送成功!")
else:
print("Chat 推送失败!错误信息:", response)
def pushplus_bot(title: str, content: str) -> None:
"""
通过 push+ 推送消息。
"""
if not push_config.get("PUSH_PLUS_TOKEN"):
print("PUSHPLUS 服务的 PUSH_PLUS_TOKEN 未设置!!\n取消推送")
return
print("PUSHPLUS 服务启动")
url = "http://www.pushplus.plus/send"
data = {
"token": push_config.get("PUSH_PLUS_TOKEN"),
"title": title,
"content": content,
"topic": push_config.get("PUSH_PLUS_USER"),
}
body = json.dumps(data).encode(encoding="utf-8")
headers = {"Content-Type": "application/json"}
response = requests.post(url=url, data=body, headers=headers).json()
if response["code"] == 200:
print("PUSHPLUS 推送成功!")
else:
url_old = "http://pushplus.hxtrip.com/send"
headers["Accept"] = "application/json"
response = requests.post(
url=url_old, data=body, headers=headers).json()
if response["code"] == 200:
print("PUSHPLUS(hxtrip) 推送成功!")
else:
print("PUSHPLUS 推送失败!")
def qmsg_bot(title: str, content: str) -> None:
"""
使用 qmsg 推送消息。
"""
if not push_config.get("QMSG_KEY") or not push_config.get("QMSG_TYPE"):
print("qmsg 的 QMSG_KEY 或者 QMSG_TYPE 未设置!!\n取消推送")
return
print("qmsg 服务启动")
url = f'https://qmsg.zendee.cn/{push_config.get("QMSG_TYPE")}/{push_config.get("QMSG_KEY")}'
payload = {
"msg": f'{title}\n\n{content.replace("----", "-")}'.encode("utf-8")}
response = requests.post(url=url, params=payload).json()
if response["code"] == 0:
print("qmsg 推送成功!")
else:
print(f'qmsg 推送失败!{response["reason"]}')
def wecom_app(title: str, content: str) -> None:
"""
通过 企业微信 APP 推送消息。
"""
if not push_config.get("QYWX_AM"):
print("QYWX_AM 未设置!!\n取消推送")
return
QYWX_AM_AY = re.split(",", push_config.get("QYWX_AM"))
if 4 < len(QYWX_AM_AY) > 5:
print("QYWX_AM 设置错误!!\n取消推送")
return
print("企业微信 APP 服务启动")
corpid = QYWX_AM_AY[0]
corpsecret = QYWX_AM_AY[1]
touser = QYWX_AM_AY[2]
agentid = QYWX_AM_AY[3]
try:
media_id = QYWX_AM_AY[4]
except IndexError:
media_id = ""
wx = WeCom(corpid, corpsecret, agentid)
# 如果没有配置 media_id 默认就以 text 方式发送
if not media_id:
message = title + "\n\n" + content
response = wx.send_text(message, touser)
else:
response = wx.send_mpnews(title, content, media_id, touser)
if response == "ok":
print("企业微信推送成功!")
else:
print("企业微信推送失败!错误信息如下:\n", response)
class WeCom:
def __init__(self, corpid, corpsecret, agentid):
self.CORPID = corpid
self.CORPSECRET = corpsecret
self.AGENTID = agentid
def get_access_token(self):
url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
values = {
"corpid": self.CORPID,
"corpsecret": self.CORPSECRET,
}
req = requests.post(url, params=values)
data = json.loads(req.text)
return data["access_token"]
def send_text(self, message, touser="@all"):
send_url = (
"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="
+ self.get_access_token()
)
send_values = {
"touser": touser,
"msgtype": "text",
"agentid": self.AGENTID,
"text": {"content": message},
"safe": "0",
}
send_msges = bytes(json.dumps(send_values), "utf-8")
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
def send_mpnews(self, title, message, media_id, touser="@all"):
send_url = (
"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="
+ self.get_access_token()
)
send_values = {
"touser": touser,
"msgtype": "mpnews",
"agentid": self.AGENTID,
"mpnews": {
"articles": [
{
"title": title,
"thumb_media_id": media_id,
"author": "Author",
"content_source_url": "",
"content": message.replace("\n", "<br/>"),
"digest": message,
}
]
},
}
send_msges = bytes(json.dumps(send_values), "utf-8")
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
def wecom_bot(title: str, content: str) -> None:
"""
通过 企业微信机器人 推送消息。
"""
if not push_config.get("QYWX_KEY"):
print("企业微信机器人 服务的 QYWX_KEY 未设置!!\n取消推送")
return
print("企业微信机器人服务启动")
url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={push_config.get('QYWX_KEY')}"
headers = {"Content-Type": "application/json;charset=utf-8"}
data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
response = requests.post(
url=url, data=json.dumps(data), headers=headers, timeout=15
).json()
if response["errcode"] == 0:
print("企业微信机器人推送成功!")
else:
print("企业微信机器人推送失败!")
def telegram_bot(title: str, content: str) -> None:
"""
使用 telegram 机器人 推送消息。
"""
if not push_config.get("TG_BOT_TOKEN") or not push_config.get("TG_USER_ID"):
print("tg 服务的 bot_token 或者 user_id 未设置!!\n取消推送")
return
print("tg 服务启动")
if push_config.get("TG_API_HOST"):
url = f"https://{push_config.get('TG_API_HOST')}/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
else:
url = (
f"https://api.telegram.org/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
)
headers = {"Content-Type": "application/x-www-form-urlencoded"}
payload = {
"chat_id": str(push_config.get("TG_USER_ID")),
"text": f"{title}\n\n{content}",
"disable_web_page_preview": "true",
}
proxies = None
if push_config.get("TG_PROXY_HOST") and push_config.get("TG_PROXY_PORT"):
if push_config.get("TG_PROXY_AUTH") is not None and "@" not in push_config.get(
"TG_PROXY_HOST"
):
push_config["TG_PROXY_HOST"] = (
push_config.get("TG_PROXY_AUTH")
+ "@"
+ push_config.get("TG_PROXY_HOST")
)
proxyStr = "http://{}:{}".format(
push_config.get("TG_PROXY_HOST"), push_config.get("TG_PROXY_PORT")
)
proxies = {"http": proxyStr, "https": proxyStr}
response = requests.post(
url=url, headers=headers, params=payload, proxies=proxies
).json()
if response["ok"]:
print("tg 推送成功!")
else:
print("tg 推送失败!")
def aibotk(title: str, content: str) -> None:
"""
使用 智能微秘书 推送消息。
"""
if not push_config.get("AIBOTK_KEY") or not push_config.get("AIBOTK_TYPE") or not push_config.get("AIBOTK_NAME"):
print("智能微秘书 的 AIBOTK_KEY 或者 AIBOTK_TYPE 或者 AIBOTK_NAME 未设置!!\n取消推送")
return
print("智能微秘书 服务启动")
if push_config.get("AIBOTK_TYPE") == 'room':
url = "https://api-bot.aibotk.com/openapi/v1/chat/room"
data = {
"apiKey": push_config.get("AIBOTK_KEY"),
"roomName": push_config.get("AIBOTK_NAME"),
"message": {"type": 1, "content": f'【青龙快讯】\n\n{title}\n{content}'}
}
else:
url = "https://api-bot.aibotk.com/openapi/v1/chat/contact"
data = {
"apiKey": push_config.get("AIBOTK_KEY"),
"name": push_config.get("AIBOTK_NAME"),
"message": {"type": 1, "content": f'【青龙快讯】\n\n{title}\n{content}'}
}
body = json.dumps(data).encode(encoding="utf-8")
headers = {"Content-Type": "application/json"}
response = requests.post(url=url, data=body, headers=headers).json()
print(response)
if response["code"] == 0:
print("智能微秘书 推送成功!")
else:
print(f'智能微秘书 推送失败!{response["error"]}')
def smtp(title: str, content: str) -> None:
"""
使用 SMTP 邮件 推送消息。
"""
if not push_config.get("SMTP_SERVER") or not push_config.get("SMTP_SSL") or not push_config.get("SMTP_EMAIL") or not push_config.get("SMTP_PASSWORD") or not push_config.get("SMTP_NAME"):
print("SMTP 邮件 的 SMTP_SERVER 或者 SMTP_SSL 或者 SMTP_EMAIL 或者 SMTP_PASSWORD 或者 SMTP_NAME 未设置!!\n取消推送")
return
print("SMTP 邮件 服务启动")
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = formataddr((Header(push_config.get(
"SMTP_NAME"), 'utf-8').encode(), push_config.get("SMTP_EMAIL")))
message['To'] = formataddr((Header(push_config.get(
"SMTP_NAME"), 'utf-8').encode(), push_config.get("SMTP_EMAIL")))
message['Subject'] = Header(title, 'utf-8')
try:
smtp_server = smtplib.SMTP_SSL(push_config.get("SMTP_SERVER")) if push_config.get(
"SMTP_SSL") == 'true' else smtplib.SMTP(push_config.get("SMTP_SERVER"))
smtp_server.login(push_config.get("SMTP_EMAIL"),
push_config.get("SMTP_PASSWORD"))
smtp_server.sendmail(push_config.get("SMTP_EMAIL"),
push_config.get("SMTP_EMAIL"), message.as_bytes())
smtp_server.close()
print("SMTP 邮件 推送成功!")
except Exception as e:
print(f'SMTP 邮件 推送失败!{e}')
def one() -> str:
"""
获取一条一言。
:return:
"""
url = "https://v1.hitokoto.cn/"
res = requests.get(url).json()
return res["hitokoto"] + " ----" + res["from"]
if push_config.get("BARK_PUSH"):
notify_function.append(bark)
if push_config.get("CONSOLE"):
notify_function.append(console)
if push_config.get("DD_BOT_TOKEN") and push_config.get("DD_BOT_SECRET"):
notify_function.append(dingding_bot)
if push_config.get("FSKEY"):
notify_function.append(feishu_bot)
if push_config.get("GOBOT_URL") and push_config.get("GOBOT_QQ"):
notify_function.append(go_cqhttp)
if push_config.get("GOTIFY_URL") and push_config.get("GOTIFY_TOKEN"):
notify_function.append(gotify)
if push_config.get("IGOT_PUSH_KEY"):
notify_function.append(iGot)
if push_config.get("PUSH_KEY"):
notify_function.append(serverJ)
if push_config.get("DEER_KEY"):
notify_function.append(pushdeer)
if push_config.get("CHAT_URL") and push_config.get("CHAT_TOKEN"):
notify_function.append(chat)
if push_config.get("PUSH_PLUS_TOKEN"):
notify_function.append(pushplus_bot)
if push_config.get("QMSG_KEY") and push_config.get("QMSG_TYPE"):
notify_function.append(qmsg_bot)
if push_config.get("QYWX_AM"):
notify_function.append(wecom_app)
if push_config.get("QYWX_KEY"):
notify_function.append(wecom_bot)
if push_config.get("TG_BOT_TOKEN") and push_config.get("TG_USER_ID"):
notify_function.append(telegram_bot)
if push_config.get("AIBOTK_KEY") and push_config.get("AIBOTK_TYPE") and push_config.get("AIBOTK_NAME"):
notify_function.append(aibotk)
if push_config.get("SMTP_SERVER") and push_config.get("SMTP_SSL") and push_config.get("SMTP_EMAIL") and push_config.get("SMTP_PASSWORD") and push_config.get("SMTP_NAME"):
notify_function.append(smtp)
def send(title: str, content: str) -> None:
if not content:
print(f"{title} 推送内容为空!")
return
# 根据标题跳过一些消息推送环境变量SKIP_PUSH_TITLE 用回车分隔
skipTitle = os.getenv("SKIP_PUSH_TITLE")
if skipTitle:
if (title in re.split("\n", skipTitle)):
print(f"{title} 在SKIP_PUSH_TITLE环境变量内跳过推送")
return
hitokoto = push_config.get("HITOKOTO")
text = one() if hitokoto else ""
content += "\n\n" + text
ts = [
threading.Thread(target=mode, args=(
title, content), name=mode.__name__)
for mode in notify_function
]
[t.start() for t in ts]
[t.join() for t in ts]
def main():
send("title", "content")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,585 @@
# Source: https://github.com/LinYuanovo/AutoTaskScripts/blob/main/web/%E5%8F%B8%E6%9C%BA%E7%A4%BE.py
# Raw: https://raw.githubusercontent.com/LinYuanovo/AutoTaskScripts/main/web/%E5%8F%B8%E6%9C%BA%E7%A4%BE.py
# Repo: LinYuanovo/AutoTaskScripts
# Path: web/司机社.py
# UploadedAt: 2025-08-27T15:31:08+08:00
# SHA256: 1e5eeeaf1e385c86b5a73c385a7bcae653c01fda214429c626e720e8b3fa1b54
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
作者: 临渊
日期: 2025/6/17
name: 司机社
入口: 网站 (https://sjs47.com/)
功能: 登录、签到
变量: sijishe='邮箱&密码' 或者 'cookie'
自动检测,多个账号用换行分割
使用邮箱密码将会进行登录必须有ocr服务地址
使用cookie将会直接使用
定时: 一天两次
cron: 10 9,10 * * *
------------更新日志------------
2025/6/17 V1.0 初始化,完成签到功能
2025/7/28 V1.1 修改头部注释,以便拉库
2025/8/27 V1.2 增加尝试获取最新域名
"""
import requests
import os
import re
import urllib.parse
import logging
import traceback
import base64
import random
import time
import json
from bs4 import BeautifulSoup
from datetime import datetime
DDDD_OCR_URL = os.getenv("DDDD_OCR_URL") or "" # dddd_ocr地址
DEFAULT_GUIDE_URL = "https://47447.net/" # 默认发布地址
DEFAULT_HOST = "sjs47.com" # 默认域名
class AutoTask:
def __init__(self, site_name, default_host):
"""
初始化自动任务类
:param site_name: 站点名称,用于日志显示
:param default_host: 默认域名
"""
self.site_name = site_name
self.default_host = default_host
self.cookie_file = f"{site_name}_cookie.json"
self.setup_logging()
def setup_logging(self):
"""
配置日志系统
"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s\t- %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
handlers=[
logging.StreamHandler()
]
)
def check_env(self):
"""
检查环境变量
:return: 邮箱和密码或者cookie
"""
try:
env = os.getenv("sijishe")
if not env:
logging.error("[检查环境变量]没有找到环境变量sijishe")
return
envs = env.split('\n')
for env in envs:
if '&' in env:
email, password = env.split('&')
yield email, password, None
else:
yield None, None, env
except Exception as e:
logging.error(f"[检查环境变量]发生错误: {str(e)}\n{traceback.format_exc()}")
raise
def get_host(self):
"""
获取最新域名
:return: 域名
"""
try:
url = DEFAULT_GUIDE_URL
response = requests.get(url)
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
links = soup.find_all('a')
for link in links:
link_text = link.get_text(strip=True)
if re.search(r'打开网站', link_text):
href_value = link.get('href')
if href_value.startswith("http"):
host = href_value.split("//")[1]
logging.info(f"[获取最新域名]最新域名: {host}")
return host
else:
return href_value
return DEFAULT_HOST
except Exception as e:
logging.error(f"[获取最新域名]发生错误: {str(e)}\n{traceback.format_exc()}")
return DEFAULT_HOST
def get_param(self, host, session):
"""
获取参数
:param host: 域名
:param session: 会话对象
:return: formhash, seccodehash, loginhash
"""
try:
url = f"https://{host}/member.php?mod=logging&action=login&infloat=yes&frommessage&inajax=1&ajaxtarget=messagelogin"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
pattern = r'name="formhash" value="([a-zA-Z0-9]{8})"'
match = re.search(pattern, response.text)
if match:
formhash = match.group(1)
else:
logging.error("[获取formhash]无法获取formhash")
return None, None, None
pattern = r'seccode_([a-zA-Z0-9]{6})'
match = re.search(pattern, response.text)
if match:
seccodehash = match.group(1)
else:
logging.error("[获取seccodehash]无法获取seccodehash")
return None, None, None
pattern = r'main_messaqge_([a-zA-Z0-9]{5})'
match = re.search(pattern, response.text)
if match:
loginhash = match.group(1)
else:
logging.error("[获取loginhash]无法获取loginhash")
return None, None, None
return formhash, seccodehash, loginhash
except requests.RequestException as e:
logging.warning(f"[获取参数]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return None, None, None
except Exception as e:
logging.error(f"[获取参数]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return None, None, None
def get_captcha_img(self, host, seccodehash, session):
"""
获取验证码图片
:param host: 域名
:param seccodehash: seccodehash
:param session: 会话对象
:return: 验证码图片
"""
try:
url = f"https://{host}/misc.php?mod=seccode&update={random.randint(10000, 99999)}&idhash={seccodehash}"
headers = {
'referer': f'https://{host}/member.php?mod=logging&action=login',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
img_base64 = base64.b64encode(response.content).decode('utf-8')
return img_base64
except Exception as e:
logging.error(f"[获取验证码图片]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return None
def get_captcha_text(self, img_base64, ocr_url):
"""
获取验证码文字
:param img_base64: 验证码base64
:param ocr_url: OCR服务地址
:return: 验证码文字
"""
try:
payload = {
'image': img_base64
}
response = requests.post(ocr_url, data=payload).json()
if response['code'] == 200:
return response['data']
else:
logging.error(f"[获取验证码]发生错误: {response['message']}")
return None
except Exception as e:
logging.error(f"[获取验证码]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def check_captcha(self, host, captcha, session, seccodehash):
"""
检查验证码
:param host: 域名
:param captcha: 验证码文字
:param session: 会话对象
:param seccodehash: seccodehash
:return: 是否正确
"""
try:
url = f"https://{host}/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash={seccodehash}&secverify={captcha}"
headers = {
'referer': f'https://{host}/member.php?mod=logging&action=login',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
pattern = r'<!\[CDATA\[(.*?)\]\]>'
match = re.search(pattern, response.text)
if match:
text = match.group(1)
if "succeed" in text:
return True
else:
return False
else:
logging.warning("[检查验证码]响应格式异常")
return False
except requests.RequestException as e:
logging.error(f"[检查验证码]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[检查验证码]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def login_in(self, host, username, password, formhash, captcha, session, loginhash, seccodehash):
"""
登录
:param host: 域名
:param username: 邮箱
:param password: 密码
:param formhash: formhash
:param captcha: 验证码文字
:param session: 会话对象
:param loginhash: loginhash
:param seccodehash: seccodehash
:return: 是否成功
"""
try:
url = f"https://{host}/member.php?mod=logging&action=login&loginsubmit=yes&loginhash={loginhash}&inajax=1"
payload = f"formhash={formhash}&referer=https://{host}/home.php?mod=spacecp&ac=credit&showcredit=1&loginfield=email&username={username}&password={password}&questionid=0&answer=&seccodehash={seccodehash}&seccodemodid=member::logging&seccodeverify={captcha}&cookietime=2592000"
headers = {
'Referer': f'https://{host}/home.php?mod=spacecp&ac=credit&showcredit=1',
'content-type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
payload = urllib.parse.quote(payload, safe='=&')
response = session.post(url, headers=headers, data=payload)
response.raise_for_status()
pattern = r'<!\[CDATA\[(.*?)\]\]>'
match = re.search(pattern, response.text)
if match:
text = match.group(1)
if "欢迎您回来" in text:
username_pattern = r'欢迎您回来,(.*?),现在将转入登录前页面'
username_match = re.search(username_pattern, text)
if username_match:
pattern = r'<font color="#00FFCC">(.*?)</font> (.*?)'
match = re.search(pattern, text)
if match:
level = match.group(1)
nickname = match.group(2)
logging.info(f"[登录]成功,当前账号: {level} {nickname}")
else:
logging.info(f"[登录]成功,当前账号: {username_match.group(1)}")
return True
else:
logging.warning("[登录]登录失败")
return False
else:
logging.warning("[登录]响应格式异常")
return False
except requests.RequestException as e:
logging.error(f"[登录]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[登录]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def read_cookie_file(self):
"""
读取cookie文件
:return: cookie字符串或None
"""
try:
if os.path.exists(self.cookie_file):
with open(self.cookie_file, 'r', encoding='utf-8') as f:
cookie_data = json.load(f)
if cookie_data.get('accounts'):
logging.info(f"[读取Cookie文件]成功读取{self.cookie_file}")
return cookie_data['accounts']
return None
except Exception as e:
logging.error(f"[读取Cookie文件]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def write_cookie_file(self, cookies, email=None):
"""
写入cookie文件
:param cookies: cookie字符串
:param email: 账号邮箱,用于标识不同账号
"""
try:
# 读取现有cookie文件
existing_data = {}
if os.path.exists(self.cookie_file):
with open(self.cookie_file, 'r', encoding='utf-8') as f:
existing_data = json.load(f)
# 准备新的cookie数据
cookie_data = {
'site_name': self.site_name,
'host': self.default_host,
'accounts': existing_data.get('accounts', {}),
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
# 更新或添加账号cookie
if email:
cookie_data['accounts'][email] = {
'cookies': cookies,
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
else:
# 如果没有提供email使用默认键
cookie_data['accounts']['default'] = {
'cookies': cookies,
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
with open(self.cookie_file, 'w', encoding='utf-8') as f:
json.dump(cookie_data, f, ensure_ascii=False, indent=2)
logging.info(f"[写入Cookie文件]成功写入{self.cookie_file}")
except Exception as e:
logging.error(f"[写入Cookie文件]发生错误: {str(e)}\n{traceback.format_exc()}")
def get_session_cookies(self, session):
"""
获取session的cookies字符串
:param session: 会话对象
:return: cookie字符串
"""
try:
cookies = []
for cookie in session.cookies:
cookies.append(f"{cookie.name}={cookie.value}")
return '; '.join(cookies)
except Exception as e:
logging.error(f"[获取Session Cookies]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def check_cookie_valid(self, host, session):
"""
检查cookie是否有效
:param host: 域名
:param session: 会话对象
:return: 是否有效
"""
try:
url = f"https://{host}/home.php?mod=space"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
if "请先登录" in response.text:
logging.warning("[Cookie检测]Cookie已失效")
return False
logging.info("[Cookie检测]Cookie有效")
return True
except Exception as e:
logging.error(f"[Cookie检测]发生错误: {str(e)}\n{traceback.format_exc()}")
return False
def get_sign_hash(self, host, session):
"""
获取签到hash
:param host: 域名
:param session: 会话对象
:return: 签到hash
"""
try:
url = f"https://{host}/k_misign-sign.html"
headers = {
'priority': 'u=1, i',
'x-requested-with': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host,
'Connection': 'keep-alive'
}
response = session.get(url, headers=headers)
response.raise_for_status()
pattern = r'formhash=([a-zA-Z0-9]{8})'
match = re.search(pattern, response.text)
if match:
formhash = match.group(1)
return formhash
else:
logging.warning("[获取签到hash]无法获取签到hash")
return None
except requests.RequestException as e:
logging.error(f"[获取签到hash]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return None
def signin(self, host, session, sign_hash):
"""
签到
:param host: 域名
:param session: 会话对象
:param sign_hash: 签到hash
"""
try:
if not sign_hash:
logging.error("sign_hash为空无法进行签到")
return
url = f"https://{host}/k_misign-sign.html?operation=qiandao&format=button&formhash={sign_hash}&inajax=1&ajaxtarget=midaben_sign"
payload = {}
headers = {
'priority': 'u=1, i',
'x-requested-with': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host,
'Connection': 'keep-alive'
}
response = session.get(url, headers=headers)
response.raise_for_status()
# 使用正则表达式匹配CDATA中的内容
if "签到成功" in response.text:
# 获得随机奖励 248车票 和 。 </p>
pattern = r'获得随机奖励 (.*?)车票 和 (.*?)。'
match = re.search(pattern, response.text)
if match:
logging.info(f"[签到]成功,获得{match.group(1)}车票和{match.group(2)}车票")
else:
logging.info("[签到]成功")
elif "今日已签" in response.text:
logging.info("[签到]今日已签到")
else:
logging.warning(f"[签到]失败,返回内容: {response.text}")
except requests.RequestException as e:
logging.error(f"[签到]发生网络错误: {str(e)}\n{traceback.format_exc()}")
except Exception as e:
logging.error(f"[签到]发生未知错误: {str(e)}\n{traceback.format_exc()}")
def run(self, ocr_url):
"""
执行登录任务的主函数
:param ocr_url: OCR服务地址
"""
try:
logging.info(f"{self.site_name}】开始执行任务")
self.default_host = self.get_host()
# 首先尝试读取cookie文件
accounts = self.read_cookie_file()
if accounts:
logging.info("[Cookie文件]检测到cookie文件将尝试使用")
for email, account_data in accounts.items():
session = requests.Session()
for cookie_item in account_data['cookies'].split(';'):
key, value = cookie_item.split('=', 1)
session.cookies.set(key.strip(), value.strip())
# 检查cookie是否有效
if self.check_cookie_valid(self.default_host, session):
logging.info(f"[Cookie文件]账号 {email} 的Cookie有效")
# 执行签到任务
sign_hash = self.get_sign_hash(self.default_host, session)
if sign_hash:
self.signin(self.default_host, session, sign_hash)
return session
else:
logging.warning(f"[Cookie文件]账号 {email} 的Cookie已失效")
logging.info("[Cookie文件]所有账号的Cookie都已失效尝试使用邮箱密码登录")
# 检查环境变量中是否有邮箱密码
env = os.getenv("sijishe")
if not env or '&' not in env:
logging.error("[Cookie文件]所有Cookie已失效且环境变量中未找到邮箱密码无法继续")
return None
# 删除失效的cookie文件
try:
os.remove(self.cookie_file)
logging.info(f"[Cookie文件]已删除失效的cookie文件: {self.cookie_file}")
except Exception as e:
logging.error(f"[Cookie文件]删除失效cookie文件失败: {str(e)}")
for index, (email, password, cookie) in enumerate(self.check_env(), 1):
logging.info("")
logging.info(f"------【账号{index}】开始执行任务------")
session = requests.Session()
if cookie:
logging.info(f"[检查环境变量]检测到cookie将直接使用并保存到文件")
for cookie_item in cookie.split(';'):
key, value = cookie_item.split('=', 1)
session.cookies.set(key.strip(), value.strip())
self.write_cookie_file(cookie, email)
# 检查cookie是否有效
if self.check_cookie_valid(self.default_host, session):
logging.info(f"[Cookie]账号 {email} 的Cookie有效")
# 执行签到任务
sign_hash = self.get_sign_hash(self.default_host, session)
if sign_hash:
self.signin(self.default_host, session, sign_hash)
return session
else:
logging.warning(f"[Cookie]账号 {email} 的Cookie已失效")
continue
else:
logging.info(f"[检查环境变量]检测到邮箱密码,将进行登录")
formhash, seccodehash, loginhash = self.get_param(self.default_host, session)
if not all([formhash, seccodehash, loginhash]):
logging.error("获取参数失败,跳过当前账号")
continue
max_retries = 3
retry_count = 0
while retry_count < max_retries:
login_in_captcha = self.get_captcha_img(self.default_host, seccodehash, session)
login_in_captcha_text = self.get_captcha_text(login_in_captcha, ocr_url)
if self.check_captcha(self.default_host, login_in_captcha_text, session, seccodehash):
break
retry_count += 1
if retry_count < max_retries:
logging.warning(f"[验证码]验证失败,第{retry_count}次重试")
time.sleep(5)
else:
logging.error("[验证码]验证失败,已达到最大重试次数")
continue
if not self.login_in(self.default_host, email, password, formhash, login_in_captcha_text, session, loginhash, seccodehash):
logging.error("登录失败,跳过当前账号")
continue
# 登录成功后保存cookie到文件
cookies = self.get_session_cookies(session)
if cookies:
self.write_cookie_file(cookies, email)
# 登录成功后执行签到任务
sign_hash = self.get_sign_hash(self.default_host, session)
if sign_hash:
self.signin(self.default_host, session, sign_hash)
logging.info(f"------【账号{index}】执行任务完成------")
logging.info("")
return session
except Exception as e:
logging.error(f"{self.site_name}】执行过程中发生错误: {str(e)}\n{traceback.format_exc()}")
return None
if __name__ == "__main__":
site_name = "司机社"
ocr_url = DDDD_OCR_URL
auto_task = AutoTask(site_name, DEFAULT_HOST)
session = auto_task.run(ocr_url)

View File

@@ -0,0 +1,430 @@
# Source: https://github.com/LinYuanovo/AutoTaskScripts/blob/main/web/%E5%98%A4%E5%98%A4%E6%80%AA%E4%B9%8B%E5%AE%B6.py
# Raw: https://raw.githubusercontent.com/LinYuanovo/AutoTaskScripts/main/web/%E5%98%A4%E5%98%A4%E6%80%AA%E4%B9%8B%E5%AE%B6.py
# Repo: LinYuanovo/AutoTaskScripts
# Path: web/嘤嘤怪之家.py
# UploadedAt: 2025-08-27T15:31:08+08:00
# SHA256: 9e2e2ee0614b254534faf4e169de569e3d9bbc058a01ef97defe9b330fc9dd90
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
作者: 临渊
日期: 2025/6/8
name: 嘤嘤怪之家
入口: 网站 (https://yyg.app/)
功能: 登录、签到、评论每日上限30积分
变量: yyg='账号&密码' 多个账号用换行分割
DDDD_OCR_URL (dddd_ocr地址)
定时: 一天两次
cron: 10 9,10 * * *
------------更新日志------------
2025/6/8 V1.0 初始化,完成签到功能
2025/6/10 V1.1 添加评论功能
2025/6/11 V1.2 优化代码结构使用session管理cookie添加查询积分功能不一定成功
2025/7/23 V1.3 更新域名
2025/7/28 V1.4 修改头部注释,以便拉库
2025/8/27 V1.5 增加尝试获取最新域名
"""
import requests
import os
import re
import urllib.parse
import time
import random
import logging
import traceback
from datetime import datetime
from bs4 import BeautifulSoup
DDDD_OCR_URL = os.getenv("DDDD_OCR_URL") or "" # dddd_ocr地址
DEFAULT_GUIDE_URL = "https://yyg.autos/" # 默认发布地址
DEFAULT_HOST = "yyg.app" # 默认域名
class AutoTask:
def __init__(self, site_name):
"""
初始化自动任务类
:param site_name: 站点名称,用于日志显示
"""
self.site_name = site_name
self.setup_logging()
def setup_logging(self):
"""
配置日志系统
"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s\t- %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
handlers=[
# logging.FileHandler(f'{self.site_name}_{datetime.now().strftime("%Y%m%d")}.log', encoding='utf-8'), # 保存日志
logging.StreamHandler()
]
)
def check_cookie(self):
"""
检查cookie
:return: 用户名和密码
"""
try:
# 从环境变量获取cookie
cookie = os.getenv(f"yyg")
if not cookie:
logging.error(f"[检查cookie]没有找到环境变量yyg")
return
# 多个账号用换行分割
cookies = cookie.split('\n')
for cookie in cookies:
# 解析cookie字符串提取用户名和密码
username, password = cookie.split('&')
yield username, password
except Exception as e:
logging.error(f"[检查cookie]发生错误: {str(e)}\n{traceback.format_exc()}")
raise
def get_host(self):
"""
获取最新域名
:return: 域名
"""
try:
url = DEFAULT_GUIDE_URL
response = requests.get(url)
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
links = soup.find_all('a')
for link in links:
link_text = link.get_text(strip=True)
if re.search(r'访问最新域名', link_text):
href_value = link.get('href')
if href_value.startswith("http"):
host = href_value.split("//")[1]
logging.info(f"[获取最新域名]最新域名: {host}")
return host
else:
return href_value
return DEFAULT_HOST
except Exception as e:
logging.error(f"[获取最新域名]发生错误: {str(e)}\n{traceback.format_exc()}")
return DEFAULT_HOST
def get_captcha_img(self, host, session, type):
"""
获取验证码图片
:param host: 域名
:param session: 会话对象
:param type: 验证码类型
:return: 验证码base64
"""
max_retries = 3 # 最大重试次数
retry_count = 0
while retry_count < max_retries:
try:
url = f"https://{host}/wp-content/themes/zibll/action/captcha.php?type=image&id={type}"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
}
response = session.get(url, headers=headers).json()
if 'img' in response:
return response['img']
else:
retry_count += 1
logging.warning(f"[获取验证码]第{retry_count}次获取失败,正在重试...")
continue
except Exception as e:
retry_count += 1
if retry_count >= max_retries:
logging.error(f"[获取验证码]重试次数已达上限")
return None
continue
return None
def get_captcha_text(self, img):
"""
获取验证码文字
:param img: 验证码图片base64
:return: 验证码
"""
try:
url = DDDD_OCR_URL
payload = {
'image': img
}
response = requests.post(url, data=payload).json()
if response['code'] == 200:
return response['data']
else:
logging.error(f"[获取验证码]发生错误: {response['message']}")
return None
except Exception as e:
logging.error(f"[获取验证码]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def login_in(self, host, username, password, text, session):
"""
登录
:param host: 域名
:param username: 用户名
:param password: 密码
:param text: 验证码
:param session: 会话对象
:return: 是否成功
"""
max_retries = 3 # 最大重试次数
retry_count = 0
while retry_count < max_retries:
try:
url = f"https://{host}/wp-admin/admin-ajax.php"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
payload = f"username={username}&password={password}&canvas_yz={text}&remember=forever&action=user_signin"
response = session.post(url, headers=headers, data=payload)
response_json = response.json()
if response_json['error'] == 0:
logging.info(f"[登录]成功")
return True
else:
logging.error(f"[登录]失败: {response_json['msg']}")
if "重新获取" in response_json['msg'] or "请输入图形验证码" in response_json['msg']:
retry_count += 1
if retry_count >= max_retries:
logging.error(f"[登录]验证码重试次数已达上限")
return False
img = self.get_captcha_img(host, session, "img_yz_signin")
while not img:
img = self.get_captcha_img(host, session, "img_yz_signin")
text = self.get_captcha_text(img)
if not text:
logging.error(f"[登录]获取验证码文字失败")
return False
continue
return False
except requests.RequestException as e:
logging.error(f"[登录]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[登录]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
return False
def sign_in(self, host, session):
"""
执行签到
:param host: 域名
:param session: 会话对象
:return: 是否签到成功
"""
try:
url = f"https://{host}/wp-admin/admin-ajax.php"
headers = {
'Host': host,
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
}
payload = "action=user_checkin"
response = session.post(url, headers=headers, data=payload)
response_json = response.json()
# 处理响应
logging.info(f"[签到]{response_json['msg']}")
return response_json['msg']
except requests.RequestException as e:
logging.error(f"[签到]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[签到]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def get_post_id(self, host, session, retry_count=0):
"""
获取帖子id
:param host: 域名
:param session: 会话对象
:param retry_count: 重试次数
:return: 帖子id列表
"""
try:
url = f"https://{host}/category/pcgame?orderby=modified" # 最新排列
headers = {
'Host': host,
'Referer': f"https://{host}/category/pcgame",
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
}
response = session.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
post_ids = []
for i in range(3,7):
# 找到所有posts元素
links = soup.select(f'body > main > div > div > div:nth-child(2) > posts:nth-child({i}) > div.item-body.flex.xx.flex1.jsb > h2 > a')
if links: # 如果找到了链接
link = links[0] # 获取第一个链接
# 提取帖子ID
if link.get('href'):
# 从URL中提取ID (例如从 https://yyg.boats/14819.html 提取 14819)
post_id = link['href'].split('/')[-1].replace('.html', '')
post_ids.append(post_id)
# 如果没有获取到帖子ID且重试次数小于3次则重试
if not post_ids and retry_count < 3:
logging.info(f"[获取帖子ID]未获取到帖子ID{retry_count + 1}次重试")
time.sleep(random.randint(5, 10))
return self.get_post_id(host, session, retry_count + 1)
elif not post_ids and retry_count >= 3:
post_ids = ['14818', '14817', '14816', '14815']
logging.warning(f"[获取帖子ID]三次未获取到帖子ID使用默认帖子ID: {post_ids}")
logging.info(f"[获取帖子ID]成功获取到 {len(post_ids)} 个帖子ID: {post_ids}")
return post_ids
except requests.RequestException as e:
logging.error(f"[获取帖子ID]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return []
except Exception as e:
logging.error(f"[获取帖子ID]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return []
def submit_comment(self, host, session, captcha, post_id, retry_count=0):
"""
提交评论
:param host: 域名
:param session: 会话对象
:param captcha: 验证码
:param post_id: 帖子ID
:param retry_count: 重试次数
"""
try:
url = f"https://{host}/wp-admin/admin-ajax.php"
headers = {
'Host': host,
'Referer': f"https://{host}/{post_id}.html",
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
}
payload = f"comment=%E6%84%9F%E8%B0%A2%E5%88%86%E4%BA%AB&canvas_yz={captcha}&comment_post_ID={post_id}&comment_parent=0&action=submit_comment"
response = session.post(url, headers=headers, data=payload)
response_json = response.json()
logging.info(f"[评论帖子{post_id}]{response_json['msg']}")
if "图形验证码错误" in response_json['msg']:
if retry_count >= 3:
logging.warning(f"[评论{post_id}]验证码错误重试次数已达上限,跳过此评论")
return False
logging.info(f"[评论帖子{post_id}]验证码错误,第{retry_count + 1}次重试")
submit_comment_captcha = self.get_captcha_img(host, session, "submit_comment")
while not submit_comment_captcha:
submit_comment_captcha = self.get_captcha_img(host, session, "submit_comment")
submit_comment_text = self.get_captcha_text(submit_comment_captcha)
if not submit_comment_text:
logging.error(f"[评论帖子{post_id}]获取验证码文字失败")
return False
return self.submit_comment(host, session, submit_comment_text, post_id, retry_count + 1)
return response_json['msg']
except Exception as e:
logging.error(f"[评论帖子{post_id}]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def get_user_balance(self, host, session):
"""
获取用户积分
:param host: 域名
:param session: 会话对象
:return: 用户积分
"""
try:
url = f"https://{host}/user/balance"
headers = {
'Host': host,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
}
response = session.get(url, headers=headers)
# 正则匹配积分记录里第一个,即 积分: xxx
balance = re.search(r'积分: (\d+)', response.text)
if balance:
return balance.group(1)
else:
logging.error(f"[获取用户积分]未找到积分记录")
return 0
except Exception as e:
logging.error(f"[获取用户积分]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return 0
def do_task(self, host, session):
"""
执行任务
:param host: 域名
:param session: 会话对象
"""
# 执行签到
self.sign_in(host, session)
# 获取帖子id
post_ids = self.get_post_id(host, session)
# 获取评论验证码图片(四次)
for post_id in post_ids:
captcha = self.get_captcha_img(host, session, "submit_comment")
while not captcha:
captcha = self.get_captcha_img(host, session, "submit_comment")
text = self.get_captcha_text(captcha)
if not text:
logging.error(f"[评论{post_id}]获取验证码文字失败")
continue
# 提交评论
self.submit_comment(host, session, text, post_id)
time.sleep(random.randint(16, 30))
# 获取用户积分
balance = self.get_user_balance(host, session)
logging.info(f"[账号]当前积分: {balance}")
def run(self):
"""
运行任务
"""
try:
logging.info(f"{self.site_name}】开始执行任务")
host = self.get_host()
for index, (username, password) in enumerate(self.check_cookie(), 1):
logging.info("")
logging.info(f"------【账号{index}】开始执行任务------")
# 创建会话
session = requests.Session()
# 获取登录验证码图片
login_in_img = self.get_captcha_img(host, session, "img_yz_signin")
while not login_in_img:
login_in_img = self.get_captcha_img(host, session, "img_yz_signin")
# 获取登录验证码文字
login_in_text = self.get_captcha_text(login_in_img)
if not login_in_text:
logging.error(f"[{self.site_name}]获取登录验证码文字失败")
continue
# 登录
if self.login_in(host, username, password, login_in_text, session):
# 执行任务
self.do_task(host, session)
logging.info(f"------【账号{index}】执行任务完成------")
logging.info("")
except Exception as e:
logging.error(f"{self.site_name}】执行过程中发生错误: {str(e)}\n{traceback.format_exc()}")
if __name__ == "__main__":
auto_task = AutoTask("嘤嘤怪之家")
auto_task.run()

View File

@@ -0,0 +1,649 @@
# Source: https://github.com/LinYuanovo/AutoTaskScripts/blob/main/web/%E5%B0%9A%E9%A6%99%E4%B9%A6%E8%8B%91.py
# Raw: https://raw.githubusercontent.com/LinYuanovo/AutoTaskScripts/main/web/%E5%B0%9A%E9%A6%99%E4%B9%A6%E8%8B%91.py
# Repo: LinYuanovo/AutoTaskScripts
# Path: web/尚香书苑.py
# UploadedAt: 2025-08-27T15:31:08+08:00
# SHA256: d239178748199491eac1ccb8d3adeb971977e5caabe96f2f633de43739e492e2
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
作者: 临渊
日期: 2025/6/8
name: 尚香书苑
入口: 网站 (https://sxsy19.com/)
功能: 登录、签到
变量: sxsy='邮箱&密码' 或者 'cookie'
自动检测,多个账号用换行分割
使用邮箱密码将会进行登录必须有ocr服务地址
使用cookie将会直接使用
定时: 一天两次
cron: 10 9,10 * * *
------------更新日志------------
2025/6/8 V1.0 初始化,完成签到功能
2025/6/11 V1.1 变量增加邮箱密码支持
2025/6/17 V1.2 增加cookie存储功能
2025/7/28 V1.3 修改头部注释,以便拉库
2025/8/27 V1.4 修改默认域名
"""
DEFAULT_HOST = "sxsy21.com" # 默认域名
import requests
import os
import re
import urllib.parse
import logging
import traceback
import base64
import random
import time
import json
from datetime import datetime
DDDD_OCR_URL = os.getenv("DDDD_OCR_URL") or "" # dddd_ocr地址
class AutoTask:
def __init__(self, site_name):
"""
初始化自动任务类
:param site_name: 站点名称,用于日志显示
"""
self.site_name = site_name
self.cookie_file = f"{site_name}_cookie.json"
self.setup_logging()
def setup_logging(self):
"""
配置日志系统
"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s\t- %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
handlers=[
# logging.FileHandler(f'{self.site_name}_{datetime.now().strftime("%Y%m%d")}.log', encoding='utf-8'), # 保存日志
logging.StreamHandler()
]
)
def check_env(self):
"""
检查环境变量
:return: 邮箱和密码或者cookie
"""
try:
env = os.getenv("sxsy")
if not env:
logging.error("[检查环境变量]没有找到环境变量sxsy")
return
# 多个账号用换行分割
envs = env.split('\n')
for env in envs:
if '&' in env:
# 解析cookie字符串提取邮箱和密码
email, password = env.split('&')
yield email, password, None
else:
# 直接使用cookie
yield None, None, env
except Exception as e:
logging.error(f"[检查环境变量]发生错误: {str(e)}\n{traceback.format_exc()}")
raise
def get_host(self):
"""
获取host
:return: host
"""
try:
# 访问发布页
url = "https://sxsy.org/"
payload = {}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': 'sxsy.org'
}
response = requests.request("GET", url, headers=headers, data=payload)
response.raise_for_status() # 检查响应状态
# 使用正则表达式匹配host
pattern = r'href="https://(.*?)/'
match = re.search(pattern, response.text)
if match:
host = match.group(1)
logging.info(f"[获取host]{host}")
return host
logging.warning("[获取host]无法获取host使用默认域名")
return DEFAULT_HOST # 如果无法获取,返回默认域名
except requests.RequestException as e:
logging.warning(f"[获取host]发生网络错误,使用默认域名")
return DEFAULT_HOST
except Exception as e:
logging.error(f"[获取host]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return DEFAULT_HOST
def get_param(self, host, session):
"""
获取参数
:param host: 域名
:param session: 会话对象
:return: formhash, seccodehash, loginhash
"""
try:
# 访问首页
url = f"https://{host}/member.php?mod=logging&action=login&infloat=yes&frommessage&inajax=1&ajaxtarget=messagelogin"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
# 使用正则表达式匹配
# formhash 格式: name="formhash" value="5448b1bc"
pattern = r'name="formhash" value="([a-zA-Z0-9]{8})"'
match = re.search(pattern, response.text)
if match:
formhash = match.group(1)
else:
logging.error("[获取formhash]无法获取formhash")
return None, None, None
# seccodehash 格式: seccode_cSAbDg cSAbDg
pattern = r'seccode_([a-zA-Z0-9]{6})'
match = re.search(pattern, response.text)
if match:
seccodehash = match.group(1)
else:
logging.error("[获取seccodehash]无法获取seccodehash")
return None, None, None
# loginhash 格式: main_messaqge_LCpo4 LCpo4
pattern = r'main_messaqge_([a-zA-Z0-9]{5})'
match = re.search(pattern, response.text)
if match:
loginhash = match.group(1)
else:
logging.error("[获取loginhash]无法获取loginhash")
return None, None, None
return formhash, seccodehash, loginhash
except requests.RequestException as e:
logging.warning(f"[获取参数]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return None, None, None
except Exception as e:
logging.error(f"[获取参数]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return None, None, None
def get_captcha_img(self, host, seccodehash, session):
"""
获取验证码图片
:param host: 域名
:param seccodehash: seccodehash
:param session: 会话对象
:return: 验证码图片
"""
try:
url = f"https://{host}/misc.php?mod=seccode&update={random.randint(10000, 99999)}&idhash={seccodehash}"
headers = {
'referer': f'https://{host}/member.php?mod=logging&action=login',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
# 图片转为base64
img_base64 = base64.b64encode(response.content).decode('utf-8')
return img_base64
except Exception as e:
logging.error(f"[获取验证码图片]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return None
def get_captcha_text(self, img_base64):
"""
获取验证码文字
:param img_base64: 验证码base64
:return: 验证码文字
"""
try:
url = DDDD_OCR_URL
payload = {
'image': img_base64
}
response = requests.post(url, data=payload).json()
if response['code'] == 200:
return response['data']
else:
logging.error(f"[获取验证码]发生错误: {response['message']}")
return None
except Exception as e:
logging.error(f"[获取验证码]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def check_captcha(self, host, captcha, session, seccodehash):
"""
检查验证码
:param host: 域名
:param captcha: 验证码文字
:param session: 会话对象
:param seccodehash: seccodehash
:return: 是否正确
"""
try:
url = f"https://{host}/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash={seccodehash}&secverify={captcha}"
headers = {
'referer': f'https://{host}/member.php?mod=logging&action=login',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
pattern = r'<!\[CDATA\[(.*?)\]\]>'
match = re.search(pattern, response.text)
if match:
text = match.group(1)
if "succeed" in text:
return True
else:
return False
else:
logging.warning("[检查验证码]响应格式异常")
return False
except requests.RequestException as e:
logging.error(f"[检查验证码]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[检查验证码]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def login_in(self, host, username, password, formhash, captcha, session, loginhash, seccodehash):
"""
登录
:param host: 域名
:param username: 邮箱
:param password: 密码
:param formhash: formhash
:param captcha: 验证码文字
:param session: 会话对象
:param loginhash: loginhash
:param seccodehash: seccodehash
:return: 是否成功
"""
try:
url = f"https://{host}/member.php?mod=logging&action=login&loginsubmit=yes&loginhash={loginhash}&inajax=1"
payload = f"formhash={formhash}&referer=https://{host}/home.php?mod=spacecp&ac=credit&showcredit=1&loginfield=email&username={username}&password={password}&questionid=0&answer=&seccodehash={seccodehash}&seccodemodid=member::logging&seccodeverify={captcha}&cookietime=2592000"
headers = {
'Referer': f'https://{host}/home.php?mod=spacecp&ac=credit&showcredit=1',
'content-type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
# payload转为url编码/替换为%2F
payload = urllib.parse.quote(payload, safe='=&')
response = session.post(url, headers=headers, data=payload)
response.raise_for_status()
pattern = r'<!\[CDATA\[(.*?)\]\]>'
match = re.search(pattern, response.text)
if match:
text = match.group(1)
if "欢迎您回来" in text:
# 匹配
username_pattern = r'欢迎您回来,(.*?),现在将转入登录前页面'
username_match = re.search(username_pattern, text)
if username_match:
matched_username = username_match.group(1)
logging.info(f"[登录]成功,当前账号: {matched_username}")
return True
else:
logging.warning("[登录]登录失败")
return False
else:
logging.warning("[登录]响应格式异常")
return False
except requests.RequestException as e:
logging.error(f"[登录]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[登录]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def get_sign_hash(self, host, session):
"""
获取签到hash
:param host: 域名
:param session: 会话对象
:return: 签到hash
"""
try:
url = f"https://{host}/plugin.php?id=k_misign:sign"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
pattern = r'formhash=([a-zA-Z0-9]{8})'
match = re.search(pattern, response.text)
if match:
formhash = match.group(1)
return formhash
else:
logging.warning("[获取签到hash]无法获取签到hash")
return None
except requests.RequestException as e:
logging.error(f"[获取签到hash]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return None
def signin(self, host, session, sign_hash):
"""
签到
:param host: 域名
:param session: 会话对象
:param sign_hash: 签到hash
"""
try:
if not sign_hash:
logging.error("sign_hash为空无法进行签到")
return
url = f"https://{host}/plugin.php?id=k_misign:sign&operation=qiandao&format=global_usernav_extra&formhash={sign_hash}&inajax=1&ajaxtarget=k_misign_topb"
payload = {}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
# 使用正则表达式匹配CDATA中的内容
pattern = r'<!\[CDATA\[(.*?)\]\]>'
match = re.search(pattern, response.text)
if match:
text = match.group(1)
logging.info(f"[签到]{text}")
else:
logging.warning("[签到]响应格式异常")
except requests.RequestException as e:
logging.error(f"[签到]发生网络错误: {str(e)}\n{traceback.format_exc()}")
except Exception as e:
logging.error(f"[签到]发生未知错误: {str(e)}\n{traceback.format_exc()}")
def get_user_info(self, host, session, print_info=False):
"""
获取用户信息
:param host: 域名
:param session: 会话对象
:param print_info: 是否打印信息
:return: uid
"""
try:
url = f"https://{host}/home.php?mod=spacecp&ac=credit&showcredit=1"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
# 使用正则表达式匹配金钱数量
money_pattern = r'金钱: </em>(\d+)'
match = re.search(money_pattern, response.text)
uid_pattern = r'uid=(\d+)'
uid_match = re.search(uid_pattern, response.text)
if match:
money = match.group(1)
uid = uid_match.group(1)
if print_info:
logging.info(f"[用户{uid}]现有金钱 {money}")
return uid
logging.warning("[获取用户信息]无法获取用户金钱信息")
return None
except requests.RequestException as e:
logging.error(f"[获取用户信息]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return None
except Exception as e:
logging.error(f"[获取用户信息]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return None
def get_promotion_reward(self, host, uid):
"""
获取推广奖励
:param host: 域名
:param uid: uid
"""
try:
url = f"https://{host}/?fromuid={uid}"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host,
'Referer': f'https://{host}/fromuid={uid}'
}
# 不带cookie直接访问
response = requests.get(url, headers=headers)
response.raise_for_status()
except requests.RequestException as e:
logging.error(f"[获取推广奖励]发生网络错误: {str(e)}\n{traceback.format_exc()}")
except Exception as e:
logging.error(f"[获取推广奖励]发生未知错误: {str(e)}\n{traceback.format_exc()}")
def do_task(self, host, session):
"""
执行任务
:param host: 域名
:param session: 会话对象
"""
try:
sign_hash = self.get_sign_hash(host, session)
if sign_hash:
self.signin(host, session, sign_hash)
uid = self.get_user_info(host, session)
self.get_promotion_reward(host, uid)
self.get_user_info(host, session, print_info=True)
except Exception as e:
logging.error(f"[执行任务]发生未知错误: {str(e)}\n{traceback.format_exc()}")
def read_cookie_file(self):
"""
读取cookie文件
:return: cookie字符串或None
"""
try:
if os.path.exists(self.cookie_file):
with open(self.cookie_file, 'r', encoding='utf-8') as f:
cookie_data = json.load(f)
if cookie_data.get('accounts'):
logging.info(f"[读取Cookie文件]成功读取{self.cookie_file}")
return cookie_data['accounts']
return None
except Exception as e:
logging.error(f"[读取Cookie文件]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def write_cookie_file(self, cookies, email=None):
"""
写入cookie文件
:param cookies: cookie字符串
:param email: 账号邮箱,用于标识不同账号
"""
try:
# 读取现有cookie文件
existing_data = {}
if os.path.exists(self.cookie_file):
with open(self.cookie_file, 'r', encoding='utf-8') as f:
existing_data = json.load(f)
# 准备新的cookie数据
cookie_data = {
'site_name': self.site_name,
'host': DEFAULT_HOST,
'accounts': existing_data.get('accounts', {}),
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
# 更新或添加账号cookie
if email:
cookie_data['accounts'][email] = {
'cookies': cookies,
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
else:
# 如果没有提供email使用默认键
cookie_data['accounts']['default'] = {
'cookies': cookies,
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
with open(self.cookie_file, 'w', encoding='utf-8') as f:
json.dump(cookie_data, f, ensure_ascii=False, indent=2)
logging.info(f"[写入Cookie文件]成功写入{self.cookie_file}")
except Exception as e:
logging.error(f"[写入Cookie文件]发生错误: {str(e)}\n{traceback.format_exc()}")
def get_session_cookies(self, session):
"""
获取session的cookies字符串
:param session: 会话对象
:return: cookie字符串
"""
try:
cookies = []
for cookie in session.cookies:
cookies.append(f"{cookie.name}={cookie.value}")
return '; '.join(cookies)
except Exception as e:
logging.error(f"[获取Session Cookies]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def check_cookie_valid(self, host, session):
"""
检查cookie是否有效
:param host: 域名
:param session: 会话对象
:return: 是否有效
"""
try:
url = f"https://{host}/home.php?mod=space"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
if "请先登录" in response.text:
return False
return True
except Exception as e:
logging.error(f"[Cookie检测]发生错误: {str(e)}\n{traceback.format_exc()}")
return False
def run(self):
"""
执行签到任务的主函数
"""
try:
logging.info(f"{self.site_name}】开始执行签到任务")
# 首先尝试读取cookie文件
accounts = self.read_cookie_file()
if accounts:
logging.info("[Cookie文件]检测到cookie文件将尝试使用")
for email, account_data in accounts.items():
session = requests.Session()
for cookie_item in account_data['cookies'].split(';'):
key, value = cookie_item.split('=', 1)
session.cookies.set(key.strip(), value.strip())
# 检查cookie是否有效
if self.check_cookie_valid(DEFAULT_HOST, session):
logging.info("")
logging.info(f"[Cookie检测]账号 {email} 的Cookie有效")
# 执行签到任务
self.do_task(DEFAULT_HOST, session)
logging.info("")
# 如果是最后一个账号执行return
if email == list(accounts.keys())[-1]:
return
else:
logging.warning(f"[Cookie文件]账号 {email} 的Cookie已失效")
logging.info("[Cookie文件]所有账号的Cookie都已失效尝试使用邮箱密码登录")
# 检查环境变量中是否有邮箱密码
env = os.getenv("sxsy")
if not env or '&' not in env:
logging.error("[Cookie文件]所有Cookie已失效且环境变量中未找到邮箱密码无法继续")
return
# 删除失效的cookie文件
try:
os.remove(self.cookie_file)
logging.info(f"[Cookie文件]已删除失效的cookie文件: {self.cookie_file}")
except Exception as e:
logging.error(f"[Cookie文件]删除失效cookie文件失败: {str(e)}")
host = self.get_host()
for index, (email, password, cookie) in enumerate(self.check_env(), 1):
logging.info("")
logging.info(f"------【账号{index}】开始执行任务------")
# 创建会话
session = requests.Session()
if cookie:
# 直接使用cookie
logging.info(f"[检查环境变量]检测到cookie将直接使用并保存到文件")
for cookie_item in cookie.split(';'):
key, value = cookie_item.split('=', 1)
session.cookies.set(key.strip(), value.strip())
self.write_cookie_file(cookie, email)
# 检查cookie是否有效
if self.check_cookie_valid(host, session):
logging.info(f"[Cookie]账号 {email} 的Cookie有效")
# 执行签到任务
self.do_task(host, session)
return
else:
logging.warning(f"[Cookie]账号 {email} 的Cookie已失效")
continue
else:
logging.info(f"[检查环境变量]检测到邮箱密码,将进行登录")
# 获取参数
formhash, seccodehash, loginhash = self.get_param(host, session)
if not all([formhash, seccodehash, loginhash]):
logging.error("获取参数失败,跳过当前账号")
continue
# 验证码重试逻辑
max_retries = 3
retry_count = 0
while retry_count < max_retries:
login_in_captcha = self.get_captcha_img(host, seccodehash, session)
login_in_captcha_text = self.get_captcha_text(login_in_captcha)
if self.check_captcha(host, login_in_captcha_text, session, seccodehash):
break
retry_count += 1
if retry_count < max_retries:
logging.warning(f"[验证码]验证失败,第{retry_count}次重试")
time.sleep(5)
else:
logging.error("[验证码]验证失败,已达到最大重试次数")
continue
if not self.login_in(host, email, password, formhash, login_in_captcha_text, session, loginhash, seccodehash):
logging.error("登录失败,跳过当前账号")
continue
# 登录成功后保存cookie到文件
cookies = self.get_session_cookies(session)
if cookies:
self.write_cookie_file(cookies, email)
# 登录成功后执行签到任务
self.do_task(host, session)
logging.info(f"------【账号{index}】执行任务完成------")
logging.info("")
except Exception as e:
logging.error(f"{self.site_name}】执行过程中发生错误: {str(e)}\n{traceback.format_exc()}")
if __name__ == "__main__":
auto_task = AutoTask("尚香书苑")
auto_task.run()

View File

@@ -0,0 +1,568 @@
# Source: https://github.com/LinYuanovo/AutoTaskScripts/blob/main/web/%E5%BF%AB%E8%90%8C%E8%AE%BA%E5%9D%9B.py
# Raw: https://raw.githubusercontent.com/LinYuanovo/AutoTaskScripts/main/web/%E5%BF%AB%E8%90%8C%E8%AE%BA%E5%9D%9B.py
# Repo: LinYuanovo/AutoTaskScripts
# Path: web/快萌论坛.py
# UploadedAt: 2025-08-27T15:31:08+08:00
# SHA256: 27c922da7d88c924dc93984f676b53b226e5342f04bf8d1ec9710b312ff88d24
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
作者: 临渊
日期: 2025/6/8
name: 快萌论坛
入口: 网站 (https://kmacg20.com/)
功能: 登录、签到
变量: kmacg='邮箱&密码' 或者 'cookie'
自动检测,多个账号用换行分割
使用邮箱密码将会进行登录必须有ocr服务地址
使用cookie将会直接使用
定时: 一天两次
cron: 10 9,10 * * *
------------更新日志------------
2025/6/8 V1.0 初始化,完成签到功能
2025/7/28 V1.1 修改头部注释,以便拉库
"""
DEFAULT_HOST = "kmacg20.com" # 默认域名
from bs4 import BeautifulSoup
import requests
import os
import re
import urllib.parse
import logging
import traceback
import base64
import random
import time
import json
from datetime import datetime
DDDD_OCR_URL = os.getenv("DDDD_OCR_URL") or "" # dddd_ocr地址
class AutoTask:
def __init__(self, site_name):
"""
初始化自动任务类
:param site_name: 站点名称,用于日志显示
"""
self.site_name = site_name
self.cookie_file = f"{site_name}_cookie.json"
self.setup_logging()
def setup_logging(self):
"""
配置日志系统
"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s\t- %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
handlers=[
# logging.FileHandler(f'{self.site_name}_{datetime.now().strftime("%Y%m%d")}.log', encoding='utf-8'), # 保存日志
logging.StreamHandler()
]
)
def check_env(self):
"""
检查环境变量
:return: 邮箱和密码或者cookie
"""
try:
env = os.getenv("kmacg")
if not env:
logging.error("[检查环境变量]没有找到环境变量kmacg")
return
# 多个账号用换行分割
envs = env.split('\n')
for env in envs:
if '&' in env:
# 解析cookie字符串提取邮箱和密码
email, password = env.split('&')
yield email, password, None
else:
# 直接使用cookie
yield None, None, env
except Exception as e:
logging.error(f"[检查环境变量]发生错误: {str(e)}\n{traceback.format_exc()}")
raise
def get_param(self, host, session):
"""
获取参数
:param host: 域名
:param session: 会话对象
:return: formhash, seccodehash, loginhash
"""
try:
# 访问首页
url = f"https://{host}/member.php?mod=logging&action=login"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
# 使用正则表达式匹配
# formhash 格式: name="formhash" value="5448b1bc"
pattern = r'name="formhash" value="([a-zA-Z0-9]{8})"'
match = re.search(pattern, response.text)
if match:
formhash = match.group(1)
else:
logging.error("[获取formhash]无法获取formhash")
return None, None, None
# # seccodehash 格式: seccode_cSAbDg cSAbDg
# pattern = r'seccode_([a-zA-Z0-9]{6})'
# match = re.search(pattern, response.text)
# if match:
# seccodehash = match.group(1)
# else:
# logging.error("[获取seccodehash]无法获取seccodehash")
# return None, None, None
# loginhash 格式: main_messaqge_LCpo4 LCpo4
seccodehash = 'test'
pattern = r'main_messaqge_([a-zA-Z0-9]{5})'
match = re.search(pattern, response.text)
if match:
loginhash = match.group(1)
else:
logging.error("[获取loginhash]无法获取loginhash")
return None, None, None
return formhash, seccodehash, loginhash
except requests.RequestException as e:
logging.warning(f"[获取参数]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return None, None, None
except Exception as e:
logging.error(f"[获取参数]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return None, None, None
def get_captcha_img(self, host, seccodehash, session):
"""
获取验证码图片
:param host: 域名
:param seccodehash: seccodehash
:param session: 会话对象
:return: 验证码图片
"""
try:
url = f"https://{host}/misc.php?mod=seccode&update={random.randint(10000, 99999)}&idhash={seccodehash}"
headers = {
'referer': f'https://{host}/member.php?mod=logging&action=login',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
# 图片转为base64
img_base64 = base64.b64encode(response.content).decode('utf-8')
return img_base64
except Exception as e:
logging.error(f"[获取验证码图片]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return None
def get_captcha_text(self, img_base64):
"""
获取验证码文字
:param img_base64: 验证码base64
:return: 验证码文字
"""
try:
url = DDDD_OCR_URL
payload = {
'image': img_base64
}
response = requests.post(url, data=payload).json()
if response['code'] == 200:
return response['data']
else:
logging.error(f"[获取验证码]发生错误: {response['message']}")
return None
except Exception as e:
logging.error(f"[获取验证码]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def check_captcha(self, host, captcha, session, seccodehash):
"""
检查验证码
:param host: 域名
:param captcha: 验证码文字
:param session: 会话对象
:param seccodehash: seccodehash
:return: 是否正确
"""
try:
url = f"https://{host}/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash={seccodehash}&secverify={captcha}"
headers = {
'referer': f'https://{host}/member.php?mod=logging&action=login',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
pattern = r'<!\[CDATA\[(.*?)\]\]>'
match = re.search(pattern, response.text)
if match:
text = match.group(1)
if "succeed" in text:
return True
else:
return False
else:
logging.warning("[检查验证码]响应格式异常")
return False
except requests.RequestException as e:
logging.error(f"[检查验证码]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[检查验证码]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def login_in(self, host, username, password, formhash, captcha, session, loginhash, seccodehash):
"""
登录
:param host: 域名
:param username: 邮箱
:param password: 密码
:param formhash: formhash
:param captcha: 验证码文字
:param session: 会话对象
:param loginhash: loginhash
:param seccodehash: seccodehash
:return: 是否成功
"""
try:
url = f"https://{host}/member.php?mod=logging&action=login&loginsubmit=yes&loginhash={loginhash}&inajax=1"
payload = f"formhash={formhash}&referer=https://{host}/home.php?mod=spacecp&ac=credit&showcredit=1&loginfield=email&username={username}&password={password}&questionid=0&answer=&seccodehash={seccodehash}&seccodemodid=member::logging&seccodeverify={captcha}&cookietime=2592000"
headers = {
'Referer': f'https://{host}/home.php?mod=spacecp&ac=credit&showcredit=1',
'content-type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
# payload转为url编码/替换为%2F
payload = urllib.parse.quote(payload, safe='=&')
response = session.post(url, headers=headers, data=payload)
response.raise_for_status()
pattern = r'<!\[CDATA\[(.*?)\]\]>'
match = re.search(pattern, response.text)
if match:
text = match.group(1)
if "欢迎您回来" in text:
# 匹配
username_pattern = r'欢迎您回来,(.*?),现在将转入登录前页面'
username_match = re.search(username_pattern, text)
if username_match:
matched_username = username_match.group(1)
logging.info(f"[登录]成功,当前账号: {matched_username}")
return True
else:
logging.warning("[登录]登录失败")
return False
else:
logging.warning("[登录]响应格式异常")
return False
except requests.RequestException as e:
logging.error(f"[登录]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return False
except Exception as e:
logging.error(f"[登录]发生未知错误: {str(e)}\n{traceback.format_exc()}")
return False
def get_sign_hash(self, host, session):
"""
获取签到hash
:param host: 域名
:param session: 会话对象
:return: 签到hash
"""
try:
url = f"https://{host}/dsu_paulsign-sign.html"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
pattern = r'formhash=([a-zA-Z0-9]{8})'
match = re.search(pattern, response.text)
if match:
formhash = match.group(1)
return formhash
else:
logging.warning("[获取签到hash]无法获取签到hash")
return None
except requests.RequestException as e:
logging.error(f"[获取签到hash]发生网络错误: {str(e)}\n{traceback.format_exc()}")
return None
def get_sign_result(self, html):
"""
获取签到结果
:param html: 签到结果
:return: 签到结果
"""
# 提取CDATA中的HTML内容
start_cdata = html.find('<![CDATA[') + len('<![CDATA[')
end_cdata = html.find(']]>')
html_content = html[start_cdata:end_cdata]
soup = BeautifulSoup(html_content, 'html.parser')
sign_res = soup.find('div', class_='c')
if sign_res:
return sign_res.text.strip()
else:
return None
def signin(self, host, session, sign_hash):
"""
签到
:param host: 域名
:param session: 会话对象
:param sign_hash: 签到hash
"""
try:
if not sign_hash:
logging.error("sign_hash为空无法进行签到")
return
url = f"https://{host}/plugin.php?id=dsu_paulsign:sign&operation=qiandao&infloat=1&inajax=1"
payload = f"formhash={sign_hash}&qdxq=ym&qdmode=2&todaysay=&fastreply=0"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host,
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': f'https://{host}/dsu_paulsign-sign.html'
}
response = session.post(url, headers=headers, data=payload)
response.raise_for_status()
sign_result = self.get_sign_result(response.text)
logging.info(f"[签到]签到结果: {sign_result}")
except requests.RequestException as e:
logging.error(f"[签到]发生网络错误: {str(e)}\n{traceback.format_exc()}")
except Exception as e:
logging.error(f"[签到]发生未知错误: {str(e)}\n{traceback.format_exc()}")
def do_task(self, host, session):
"""
执行任务
:param host: 域名
:param session: 会话对象
"""
try:
sign_hash = self.get_sign_hash(host, session)
if sign_hash:
self.signin(host, session, sign_hash)
except Exception as e:
logging.error(f"[执行任务]发生未知错误: {str(e)}\n{traceback.format_exc()}")
def read_cookie_file(self):
"""
读取cookie文件
:return: cookie字符串或None
"""
try:
if os.path.exists(self.cookie_file):
with open(self.cookie_file, 'r', encoding='utf-8') as f:
cookie_data = json.load(f)
if cookie_data.get('accounts'):
logging.info(f"[读取Cookie文件]成功读取{self.cookie_file}")
return cookie_data['accounts']
return None
except Exception as e:
logging.error(f"[读取Cookie文件]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def write_cookie_file(self, cookies, email=None):
"""
写入cookie文件
:param cookies: cookie字符串
:param email: 账号邮箱,用于标识不同账号
"""
try:
# 读取现有cookie文件
existing_data = {}
if os.path.exists(self.cookie_file):
with open(self.cookie_file, 'r', encoding='utf-8') as f:
existing_data = json.load(f)
# 准备新的cookie数据
cookie_data = {
'site_name': self.site_name,
'host': DEFAULT_HOST,
'accounts': existing_data.get('accounts', {}),
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
# 更新或添加账号cookie
if email:
cookie_data['accounts'][email] = {
'cookies': cookies,
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
else:
# 如果没有提供email使用默认键
cookie_data['accounts']['default'] = {
'cookies': cookies,
'update_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
with open(self.cookie_file, 'w', encoding='utf-8') as f:
json.dump(cookie_data, f, ensure_ascii=False, indent=2)
logging.info(f"[写入Cookie文件]成功写入{self.cookie_file}")
except Exception as e:
logging.error(f"[写入Cookie文件]发生错误: {str(e)}\n{traceback.format_exc()}")
def get_session_cookies(self, session):
"""
获取session的cookies字符串
:param session: 会话对象
:return: cookie字符串
"""
try:
cookies = []
for cookie in session.cookies:
cookies.append(f"{cookie.name}={cookie.value}")
return '; '.join(cookies)
except Exception as e:
logging.error(f"[获取Session Cookies]发生错误: {str(e)}\n{traceback.format_exc()}")
return None
def check_cookie_valid(self, host, session):
"""
检查cookie是否有效
:param host: 域名
:param session: 会话对象
:return: 是否有效
"""
try:
url = f"https://{host}/home.php?mod=space"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
'Host': host
}
response = session.get(url, headers=headers)
response.raise_for_status()
if "请先登录" in response.text:
return False
return True
except Exception as e:
logging.error(f"[Cookie检测]发生错误: {str(e)}\n{traceback.format_exc()}")
return False
def run(self):
"""
执行签到任务的主函数
"""
try:
logging.info(f"{self.site_name}】开始执行签到任务")
# 首先尝试读取cookie文件
accounts = self.read_cookie_file()
if accounts:
logging.info("[Cookie文件]检测到cookie文件将尝试使用")
for email, account_data in accounts.items():
session = requests.Session()
for cookie_item in account_data['cookies'].split(';'):
key, value = cookie_item.split('=', 1)
session.cookies.set(key.strip(), value.strip())
# 检查cookie是否有效
if self.check_cookie_valid(DEFAULT_HOST, session):
logging.info("")
logging.info(f"[Cookie检测]账号 {email} 的Cookie有效")
# 执行签到任务
self.do_task(DEFAULT_HOST, session)
logging.info("")
# 如果是最后一个账号执行return
if email == list(accounts.keys())[-1]:
return
else:
logging.warning(f"[Cookie文件]账号 {email} 的Cookie已失效")
logging.info("[Cookie文件]所有账号的Cookie都已失效尝试使用邮箱密码登录")
# 检查环境变量中是否有邮箱密码
env = os.getenv("kmacg")
if not env or '&' not in env:
logging.error("[Cookie文件]所有Cookie已失效且环境变量中未找到邮箱密码无法继续")
return
# 删除失效的cookie文件
try:
os.remove(self.cookie_file)
logging.info(f"[Cookie文件]已删除失效的cookie文件: {self.cookie_file}")
except Exception as e:
logging.error(f"[Cookie文件]删除失效cookie文件失败: {str(e)}")
host = DEFAULT_HOST
for index, (email, password, cookie) in enumerate(self.check_env(), 1):
logging.info("")
logging.info(f"------【账号{index}】开始执行任务------")
# 创建会话
session = requests.Session()
if cookie:
# 直接使用cookie
logging.info(f"[检查环境变量]检测到cookie将直接使用并保存到文件")
for cookie_item in cookie.split(';'):
key, value = cookie_item.split('=', 1)
session.cookies.set(key.strip(), value.strip())
self.write_cookie_file(cookie, email)
# 检查cookie是否有效
if self.check_cookie_valid(host, session):
logging.info(f"[Cookie]账号 {email} 的Cookie有效")
# 执行签到任务
self.do_task(host, session)
return
else:
logging.warning(f"[Cookie]账号 {email} 的Cookie已失效")
continue
else:
logging.info(f"[检查环境变量]检测到邮箱密码,将进行登录")
# 获取参数
formhash, seccodehash, loginhash = self.get_param(host, session)
if not all([formhash, seccodehash, loginhash]):
logging.error("获取参数失败,跳过当前账号")
continue
# 验证码重试逻辑
max_retries = 3
retry_count = 0
while retry_count < max_retries:
login_in_captcha = self.get_captcha_img(host, seccodehash, session)
login_in_captcha_text = self.get_captcha_text(login_in_captcha)
if self.check_captcha(host, login_in_captcha_text, session, seccodehash):
break
retry_count += 1
if retry_count < max_retries:
logging.warning(f"[验证码]验证失败,第{retry_count}次重试")
time.sleep(5)
else:
logging.error("[验证码]验证失败,已达到最大重试次数")
continue
if not self.login_in(host, email, password, formhash, login_in_captcha_text, session, loginhash, seccodehash):
logging.error("登录失败,跳过当前账号")
continue
# 登录成功后保存cookie到文件
cookies = self.get_session_cookies(session)
if cookies:
self.write_cookie_file(cookies, email)
# 登录成功后执行签到任务
self.do_task(host, session)
logging.info(f"------【账号{index}】执行任务完成------")
logging.info("")
except Exception as e:
logging.error(f"{self.site_name}】执行过程中发生错误: {str(e)}\n{traceback.format_exc()}")
if __name__ == "__main__":
auto_task = AutoTask("快萌论坛")
auto_task.run()

View File

@@ -0,0 +1,512 @@
# Source: https://gitee.com/jdqlscript/yyt/blob/master/%E7%94%B5%E4%BF%A1/7%E6%9C%881%E6%97%A50%E7%82%B9%E6%9D%83%E7%9B%8A.py
# Raw: https://gitee.com/jdqlscript/yyt/raw/master/%E7%94%B5%E4%BF%A1/7%E6%9C%881%E6%97%A50%E7%82%B9%E6%9D%83%E7%9B%8A.py
# Repo: jdqlscript/yyt
# Path: 电信/7月1日0点权益.py
# UploadedAt: 2025-07-19T22:58:22+08:00
# SHA256: 836d9038a2cd640748364a75830ebfa3c3871d8b00292d32f96f4436a90e55f3
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
新电信抢话费
群里发的,未测试好,自测
修改内容如下“
1.删除内置的一个手机账号
2.修改环境变量名保持和拉菲电信金豆本环境变量一致
3.恢复瑞数通杀.js调用地址确实也不知道是啥。398、399行注释
环境变量chinaTelecomAccount值为账号#密码
cron: 57 9,13,23 * * *
const $ = new Env("新电信抢话费");
"""
#!/usr/bin/env python3
import os
import re
import sys
import ssl
import time
import json
import execjs
import base64
import random
import certifi
import aiohttp
import asyncio
import certifi
import datetime
import requests
import binascii
from lxml import etree
from http import cookiejar
from Crypto.Cipher import AES
from Crypto.Cipher import DES3
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Util.Padding import pad, unpad
from aiohttp import ClientSession, TCPConnector
from concurrent.futures import ThreadPoolExecutor
import subprocess
sys.stdout.reconfigure(encoding='utf-8')
import _locale
_locale._getdefaultlocale = (lambda *args: ['zh_CN', 'utf8'])
run_num=os.environ.get('reqNUM') or "1"
MAX_RETRIES = 3
RATE_LIMIT = 10 # 每秒请求数限制
class RateLimiter:
def __init__(self, rate_limit):
self.rate_limit = rate_limit
self.tokens = rate_limit
self.updated_at = time.monotonic()
async def acquire(self):
while self.tokens < 1:
self.add_new_tokens()
await asyncio.sleep(0.1)
self.tokens -= 1
def add_new_tokens(self):
now = time.monotonic()
time_since_update = now - self.updated_at
new_tokens = time_since_update * self.rate_limit
if new_tokens > 1:
self.tokens = min(self.tokens + new_tokens, self.rate_limit)
self.updated_at = now
class AsyncSessionManager:
def __init__(self):
self.session = None
self.connector = None
async def __aenter__(self):
ssl_context = ssl.create_default_context(cafile=certifi.where())
ssl_context.set_ciphers('DEFAULT@SECLEVEL=1')
self.connector = TCPConnector(ssl=ssl_context, limit=1000)
self.session = ClientSession(connector=self.connector)
return self.session
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.session.close()
await self.connector.close()
async def retry_request(session, method, url, **kwargs):
for attempt in range(MAX_RETRIES):
try:
await asyncio.sleep(1)
async with session.request(method, url, **kwargs) as response:
return await response.json()
# return await response.json()
except (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError) as e:
print(f"请求失败,第 {attempt + 1} 次重试: {e}")
if attempt == MAX_RETRIES - 1:
raise
await asyncio.sleep(2 ** attempt)
class BlockAll(cookiejar.CookiePolicy):
return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: False
netscape = True
rfc2965 = hide_cookie2 = False
def printn(m):
current_time = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
print(f'\n[{current_time}] {m}')
context = ssl.create_default_context()
context.set_ciphers('DEFAULT@SECLEVEL=1') # 低安全级别0/1
context.check_hostname = False # 禁用主机
context.verify_mode = ssl.CERT_NONE # 禁用证书
class DESAdapter(requests.adapters.HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
kwargs['ssl_context'] = context
return super().init_poolmanager(*args, **kwargs)
requests.packages.urllib3.disable_warnings()
# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
ss = requests.session()
ss.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","Referer":"https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"}
ss.mount('https://', DESAdapter())
ss.cookies.set_policy(BlockAll())
runTime = 0
key = b'1234567`90koiuyhgtfrdews'
iv = 8 * b'\0'
public_key_b64 = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBkLT15ThVgz6/NOl6s8GNPofdWzWbCkWnkaAm7O2LjkM1H7dMvzkiqdxU02jamGRHLX/ZNMCXHnPcW/sDhiFCBN18qFvy8g6VYb9QtroI09e176s+ZCtiv7hbin2cCTj99iUpnEloZm19lwHyo69u5UMiPMpq0/XKBO8lYhN/gwIDAQAB
-----END PUBLIC KEY-----'''
public_key_data = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+ugG5A8cZ3FqUKDwM57GM4io6JGcStivT8UdGt67PEOihLZTw3P7371+N47PrmsCpnTRzbTgcupKtUv8ImZalYk65dU8rjC/ridwhw9ffW2LBwvkEnDkkKKRi2liWIItDftJVBiWOh17o6gfbPoNrWORcAdcbpk2L+udld5kZNwIDAQAB
-----END PUBLIC KEY-----'''
def get_first_three(value):
# 处理数字情况
if isinstance(value, (int, float)):
return int(str(value)[:3])
elif isinstance(value, str):
return str(value)[:3]
else:
raise TypeError("error")
def run_Time(hour,miute,second):
date = datetime.datetime.now()
date_zero = datetime.datetime.now().replace(year=date.year, month=date.month, day=date.day, hour=hour, minute=miute, second=second)
date_zero_time = int(time.mktime(date_zero.timetuple()))
return date_zero_time
def encrypt(text):
cipher = DES3.new(key, DES3.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(text.encode(), DES3.block_size))
return ciphertext.hex()
def decrypt(text):
ciphertext = bytes.fromhex(text)
cipher = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), DES3.block_size)
return plaintext.decode()
def b64(plaintext):
public_key = RSA.import_key(public_key_b64)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return base64.b64encode(ciphertext).decode()
def encrypt_para(plaintext):
if not isinstance(plaintext, str):
plaintext = json.dumps(plaintext)
public_key = RSA.import_key(public_key_data)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return binascii.hexlify(ciphertext).decode()
def encrypt_paraNew(p):
k = RSA.import_key(public_key_data)
c = PKCS1_v1_5.new(k)
s = k.size_in_bytes() - 11
d = p.encode() if isinstance(p, str) else json.dumps(p).encode()
return binascii.hexlify(b''.join(c.encrypt(d[i:i+s]) for i in range(0, len(d), s))).decode()
def encode_phone(text):
encoded_chars = []
for char in text:
encoded_chars.append(chr(ord(char) + 2))
return ''.join(encoded_chars)
def getApiTime(api_url):
try:
with requests.get(api_url) as response:
if(not response or not response.text):
return time.time()
json_data = json.loads(response.text)
if (json_data.get("api")and json_data.get("api")not in("time") ):
timestamp_str = json_data.get('data', {}).get('t', '')
else:
timestamp_str = json_data.get('currentTime', {})
timestamp = int(timestamp_str) / 1000.0 # 将毫秒转为秒
difftime=time.time()-timestamp
return difftime;
except Exception as e:
print(f"获取时间失败: {e}")
return 0;
def userLoginNormal(phone,password):
alphabet = 'abcdef0123456789'
uuid = [''.join(random.sample(alphabet, 8)),''.join(random.sample(alphabet, 4)),'4'+''.join(random.sample(alphabet, 3)),''.join(random.sample(alphabet, 4)),''.join(random.sample(alphabet, 12))]
timestamp=datetime.datetime.now().strftime("%Y%m%d%H%M%S")
loginAuthCipherAsymmertric = 'iPhone 14 15.4.' + uuid[0] + uuid[1] + phone + timestamp + password[:6] + '0$$$0.'
#r = ss.post('https://appgologin.189.cn:9031/login/client/userLoginNormal',json={"headerInfos": {"code": "userLoginNormal", "timestamp": timestamp, "broadAccount": "", "broadToken": "", "clientType": "#9.6.1#channel50#iPhone 14 Pro Max#", "shopId": "20002", "source": "110003", "sourcePassword": "Sid98s", "token": "", "userLoginName": phone}, "content": {"attach": "test", "fieldData": {"loginType": "4", "accountType": "", "loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric), "deviceUid": uuid[0] + uuid[1] + uuid[2], "phoneNum": encode_phone(phone), "isChinatelecom": "0", "systemVersion": "15.4.0", "authentication": password}}},verify=certifi.where()).json()
r = ss.post('https://appgologin.189.cn:9031/login/client/userLoginNormal',json={"headerInfos": {"code": "userLoginNormal", "timestamp": timestamp, "broadAccount": "", "broadToken": "", "clientType": "#11.3.0#channel35#Xiaomi Redmi K30 Pro#", "shopId": "20002", "source": "110003", "sourcePassword": "Sid98s", "token": "", "userLoginName": encode_phone(phone)}, "content": {"attach": "test", "fieldData": {"loginType": "4", "accountType": "", "loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric), "deviceUid": uuid[0] + uuid[1] + uuid[2], "phoneNum": encode_phone(phone), "isChinatelecom": "0", "systemVersion": "12", "authentication": encode_phone(password)}}},verify=certifi.where()).json()
l = r['responseData']['data']['loginSuccessResult']
if l:
ticket = get_ticket(phone,l['userId'],l['token'])
return ticket
return False
async def exchangeForDay(phone, session, run_num, rid, stime, accId):
async def delayed_conversion(delay):
await asyncio.sleep(delay)
await conversionRights(phone, rid, session, accId)
tasks = [asyncio.create_task(delayed_conversion(i * stime)) for i in range(int(run_num))]
await asyncio.gather(*tasks)
def get_ticket(phone,userId,token):
r = ss.post('https://appgologin.189.cn:9031/map/clientXML',data='<Request><HeaderInfos><Code>getSingle</Code><Timestamp>'+datetime.datetime.now().strftime("%Y%m%d%H%M%S")+'</Timestamp><BroadAccount></BroadAccount><BroadToken></BroadToken><ClientType>#9.6.1#channel50#iPhone 14 Pro Max#</ClientType><ShopId>20002</ShopId><Source>110003</Source><SourcePassword>Sid98s</SourcePassword><Token>'+token+'</Token><UserLoginName>'+phone+'</UserLoginName></HeaderInfos><Content><Attach>test</Attach><FieldData><TargetId>'+encrypt(userId)+'</TargetId><Url>4a6862274835b451</Url></FieldData></Content></Request>',headers={'user-agent': 'CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1'},verify=certifi.where())
tk = re.findall('<Ticket>(.*?)</Ticket>',r.text)
if len(tk) == 0:
return False
return decrypt(tk[0])
async def exchange(s, phone, title, rid,jsexec, ckvalue):
try:
url="https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange"
get_url = await asyncio.to_thread(jsexec.call,"getUrl", "POST",url)
async with s.post(get_url, cookies=ckvalue, json={"activityId": rid}) as response:
pass
except Exception as e:
print(e)
async def check(s,item,ckvalue):
checkGoods = s.get('https://wapact.189.cn:9001/gateway/stand/detailNew/check?activityId=' + item, cookies=ckvalue).json()
return checkGoods
async def conversionRights(phone, rid, session, accId):
try:
# 获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print(f"{get_first_three(phone)}: 无法获取 Ruishu cookies")
return
value = {
"id": rid,
"accId": accId,
"showType": "9003",
"showEffect": "8",
"czValue": "0"
}
paraV = encrypt_paraNew(value)
printn(f"{get_first_three(phone)}:开始兑换")
# 使用 Ruishu cookies 发送请求
response = session.post(
'https://wappark.189.cn/jt-sign/paradise/receiverRights',
json={"para": paraV},
cookies=ruishu_cookies
)
login = response.json()
printn(f"{get_first_three(phone)}:{login}")
if '兑换成功' in response.text:
QLAPI.notify(get_first_three(phone), login['resoultMsg'])
exit(0)
except Exception as e:
printn(f"{get_first_three(phone)}: 兑换请求发生错误: {str(e)}")
# 可以选择是否在这里添加重试逻辑
async def getLevelRightsList(phone, session, accId):
try:
# 获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print("无法获取 Ruishu cookies")
return None
value = {
"type": "hg_qd_djqydh",
"accId": accId,
"shopId": "20001"
}
paraV = encrypt_paraNew(value)
# 使用 Ruishu cookies 发送请求
response = session.post(
'https://wappark.189.cn/jt-sign/paradise/queryLevelRightInfo',
json={"para": paraV},
cookies=ruishu_cookies
)
data = response.json()
if data.get('code') == 401:
print(f"获取失败:{data},原因大概是sign过期了")
return None
current_level = int(data['currentLevel'])
key_name = 'V' + str(current_level)
ids = [item['activityId'] for item in data.get(key_name, []) if '话费' in item.get('title',"")]
return ids
except Exception as e:
print(f"获取失败,重试一次: {str(e)}")
try:
# 重试时重新获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print("重试时无法获取 Ruishu cookies")
return None
paraV = encrypt_para(value)
response = session.post(
'https://wappark.189.cn/jt-sign/paradise/getLevelRightsList',
json={"para": paraV},
cookies=ruishu_cookies
)
data = response.json()
if data.get('code') == 401:
print(f"重试获取失败:{data},原因大概是sign过期了")
return None
current_level = int(data['currentLevel'])
key_name = 'V' + str(current_level)
ids = [item['activityId'] for item in data.get(key_name, []) if '话费' in item.get('title',"")]
return ids
except Exception as e:
print(f"重试也失败了: {str(e)}")
return None
def get_ruishu_cookies():
try:
# 获取当前文件所在目录
current_dir = os.path.dirname(os.path.abspath(__file__))
ruishu_path = os.path.join(current_dir, 'Ruishu.py')
# 执行 Ruishu.py 并获取输出
result = subprocess.run([sys.executable, ruishu_path],
capture_output=True,
text=True)
if result.returncode != 0:
print(f"Ruishu.py 执行错误: {result.stderr}")
return None
# 解析输出的 JSON
cookies = json.loads(result.stdout.strip())
return cookies
except Exception as e:
print(f"获取 Ruishu cookies 时发生错误: {str(e)}")
return None
async def getSign(ticket, session):
try:
# 获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print("无法获取 Ruishu cookies")
return None
# 合并现有的 cookies 和 Ruishu cookies
cookies = {**ruishu_cookies}
# 使用合并后的 cookies 发送请求
response = session.get(
'https://wappark.189.cn/jt-sign/ssoHomLogin?ticket=' + ticket,
cookies=cookies,headers = {'User-Agent': "Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36"}
).json()
if response.get('resoultCode') == '0':
sign = response.get('sign')
accId = response.get('accId')
return sign ,accId
else:
print(f"获取sign失败[{response.get('resoultCode')}]: {response}")
except Exception as e:
print(f"getSign 发生错误: {str(e)}")
return None
async def qgNight(phone, ticket, timeDiff,isTrue):
if isTrue:
runTime = run_Time(23,59,3)
else:
# runTime = run_Time(0,0,0) + 0.65
runTime = 0
if runTime >(time.time()+timeDiff):
difftime = runTime - time.time() - timeDiff
print(f"当前时间:{str(datetime.datetime.now())[11:23]},跟设定的时间不同,等待{difftime}秒开始兑换每天一次的")
await asyncio.sleep(difftime)
session = requests.Session()
session.mount('https://', DESAdapter())
session.verify = False # 禁用证书验证
signx =await getSign(ticket,session)
sign =signx[0]
accId =signx[1]
if sign:
# print(f"当前时间:{str(datetime.datetime.now())[11:23]}获取到了Sign:"+sign)
session.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","sign":sign}
else:
print("未获取sign。")
return
rightsId =await getLevelRightsList(phone,session,accId)
if rightsId:
print("获取到了rightsId:"+rightsId[0])
else:
print("未能获取rightsId。")
return
# await asyncio.sleep(10)直接延迟也行或者用下面的等待一段时间。之所以这样是要先获取sign省一些步骤。
if isTrue:
runTime2 = run_Time(23,59,59) + 0.3
difftime = runTime2 - time.time() - timeDiff
printn(f"等待{difftime}s")
await asyncio.sleep(difftime)
await exchangeForDay(phone,session,run_num,rightsId[0],0.1,accId)
async def qgDay(phone, ticket, timeDiff, isTrue):
async with AsyncSessionManager() as s:
pass
async def main(timeDiff,isTRUE,hour):
tasks = []
PHONES=os.environ.get('chinaTelecomAccount')
phone_list = PHONES.split('&')
for phoneV in phone_list:
value = phoneV.split('#')
phone, password = value[0], value[1]
printn(f'{get_first_three(phone)}开始登录')
# 添加重试逻辑
max_retries = 3
retry_count = 0
ticket = None
while retry_count < max_retries and not ticket:
ticket = userLoginNormal(phone,password)
if not ticket:
printn(f'{get_first_three(phone)}{retry_count+1}次登录失败,准备重试')
retry_count += 1
await asyncio.sleep(1) # 添加1秒延迟避免频繁请求
if ticket:
# hour=datetime.datetime.now().hour
# hour=23
if hour > 15:
tasks.append(qgNight(phone, ticket, timeDiff, isTRUE))
else: #十点//十四点场次
tasks.append(qgNight(phone, ticket, timeDiff, isTRUE))
else:
printn(f'{get_first_three(phone)} 登录失败,已达最大重试次数{max_retries}')
await asyncio.gather(*tasks)
if __name__ == "__main__":
h = datetime.datetime.now().hour
#h=20 #手动设置场次的时间
print("当前小时为: "+str(h))
if 10 >h >0:
print("当前小时为: "+str(h)+"已过0点但未到10点开始准备抢十点场次")
wttime= run_Time(9,59,8) #抢十点场次
elif 14 >= h >=10:
print("当前小时为: "+str(h) +"已过10点但未到14点开始准备抢十四点场次")
wttime= run_Time(13,59,8) #抢十四点场次
else:
print("当前小时为: "+str(h)+"已过14点开始准备抢凌晨")
wttime= run_Time(23,58,58) #抢凌晨
#isTRUE=False
isTRUE=True
#isTRUE等于False则表示忽略所有限制直接运行。这个参数一般用于测试。实际生产一定要设置为True。
if(wttime >time.time()) :
wTime=wttime-time.time()
print("未到时间,计算后差异:"+str(wTime)+"")
if isTRUE:
print("一定要先测试,根据自身 设定的重发和多号,不然会出问题,抢购过早或者过晚。")
print("开始等待:")
time.sleep(wTime)
# timeValue = getApiTime("https://f.m.suning.com/api/ct.do")
timeValue = 0
timeDiff = timeValue if timeValue > 0 else 0
asyncio.run(main(timeDiff, isTRUE,h))
print("所有任务都已执行完毕!")

View File

@@ -0,0 +1,149 @@
# Source: https://github.com/NaroisCool/naro-scripts/blob/master/%E6%9C%BA%E5%9C%BA%E7%AD%BE%E5%88%B0.py
# Raw: https://raw.githubusercontent.com/NaroisCool/naro-scripts/master/%E6%9C%BA%E5%9C%BA%E7%AD%BE%E5%88%B0.py
# Repo: NaroisCool/naro-scripts
# Path: 机场签到.py
# UploadedAt: 2025-10-28T05:54:28+08:00
# SHA256: 9f07b2418f8b79135f85915156e878e42ab114c82b05adae49df87fc6dbbf8f2
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
import json
import os
from urllib.parse import quote
import httpx
import requests
from bs4 import BeautifulSoup
import notify
"""
百变小樱机场自动签到领流量
机场注册地址☞ https://dash.bbxy.buzz/auth/register?code=G9we
脚本执行要求安装python依赖bs4和httpx;填入变量BBXY_EMAIL邮箱账号和BBXY_PASSWORD登录密码
感谢原作者Admsec
经NaroisCool改进将从百变小樱官方永久地址发布网站http://bbxy88.com/)上爬取最新的国内访问地址,以及其他方法内的逻辑改动。
"""
class BBXYSign:
def __init__(self):
self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0"}
self.session = httpx.Client()
self.originUrl = ""
self.loginUrl = ""
self.email = os.environ.get("BBXY_EMAIL")
self.password = os.environ.get("BBXY_PASSWORD")
self.params = {"email": self.email, "passwd": self.password, "remember-me": '0'}
self.signSuccessOrNot = False
self.signSuccessMsg = ""
def check_websites_sync(self, websites):
with httpx.Client(headers=self.headers) as client:
print(f"总共{len(websites)}个网站")
count = 1
for site in websites:
try:
response = client.get(site)
if response.status_code == 200 :
print(f"这个链接可以访问,暂定:{site}")
self.loginUrl = site + "/auth/login"
self.originUrl = site
#进行登录测试
flag = self.login()
if flag:
print(f"这个链接可以登录,锁定:{site}")
count = count +1
if count>len(websites):
notify.send('BBXY签到结果','所有网站登录测试失败,请重新运行一遍!')
return site
else :
print(f'登录失败,尝试下一个链接')
print('-----------------')
count = count +1
if count>len(websites):
notify.send('BBXY签到结果','所有网站登录测试失败,请重新运行一遍!')
continue
except httpx.RequestError as e:
print(f"这个链接不能用,避一避: {site} - {e}")
print('-----------------')
count = count +1
if count>len(websites):
notify.send('BBXY签到结果','所有网站登录测试失败,请重新运行一遍!')
continue
'''
登录
'''
def login(self):
print('开始登录测试...')
try:
r = self.session.post(url=self.loginUrl, params=self.params, headers=self.headers)
response = json.loads(r.text)
if response['ret'] != 1:
print(f"登录失败, 原因:{response['msg']}")
return False
else:
print("登录成功")
return True
except Exception as e:
print(e)
return False
"""
签到
"""
def sign(self):
try:
client = self.session.post(url=self.originUrl + "/user/checkin", params=self.params, headers=self.headers)
response = json.loads(client.text)
if response['ret'] != 1:
print(f"签到失败了,原因是{response['msg']}")
notify.send('BBXY签到结果',response['msg'])
return False
self.signSuccessMsg = response
self.signSuccessOrNot = True
#result = self.signSuccessMsg['msg'].decode('unicode_escape')
msg = (f"签到成功:{self.signSuccessMsg['msg']}\n总流量{self.signSuccessMsg['traffic']}\n"
f"今日已用{self.signSuccessMsg['trafficInfo'].get('todayUsedTraffic')}\n"
f"总共已用{self.signSuccessMsg['trafficInfo'].get('lastUsedTraffic')}\n"
f"剩余流量{self.signSuccessMsg['trafficInfo'].get('unUsedTraffic')}\n")
if self.signSuccessOrNot:
notify.send('BBXY签到结果',msg)
return True
else:
notify.send('BBXY签到结果',msg)
return False
return True
except Exception as e:
print(e)
return False
"""
消息模板,顺便发送消息到微信公众号
"""
if __name__ == '__main__':
"""
主程序
从http://bbxy88.com/上爬取最新国内的入口地址
"""
print("*****\n"
"百变小樱机场自动签到领流量\n"
"机场注册地址☞ https://bbxy.life/auth/register?code=G9we\n"
"脚本执行要求填入变量BBXY_EMAIL邮箱账号和BBXY_PASSWORD登录密码\n"
"感谢原作者Admsec\n"
"经NaroisCool改进将从百变小樱官方永久地址发布网站http://bbxy88.com/)上爬取最新的国内访问地址,以及其他方法内的逻辑改动。\n"
"*****")
url = 'http://bbxy88.com/'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
links = [link.get('href') for link in soup.find_all('a')]
additional_links = ['https://dash.bbxy.buzz/','https://baibianxiaoying.top/']
websites = links+additional_links
a = BBXYSign()
a.check_websites_sync(websites)
a.sign()

View File

@@ -0,0 +1,298 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/client/sudojia_jhcard.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/client/sudojia_jhcard.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/client/sudojia_jhcard.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: 2102df5ae5cc0c0d7fe510d4345f65068d692fcde84713647c8150124ec21af2
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* 江淮卡友APP
*
* 抓包 URLhttp://jacwxmp.starnetah.com:18280/v2driver/v2/login 获取该 URL 的请求体不要美化不要自动换行选择原始数据Raw
* export JHCARD_BODY = '{"phone":"18888888888","password":"539281948b12751a942459aacb4a9ec1","sendMessageKey":"1aorcomF5n2EVd7Tc6w","deviceType":"1","appType":"0","sign":"XXXXXX"}'
* 如需开启评论请在最后面加 true以 # 分割
* 示例:"sign":"XXXXXX"}#true
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2024/09/27
*
* const $ = new Env('江淮卡友')
* cron: 55 5 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('江淮卡友');
const moment = require("moment");
const jhCardList = process.env.JHCARD_BODY ? process.env.JHCARD_BODY.split(/[\n&]/) : [];
// 消息推送
let message = '';
// 接口地址
const baseUrl = 'http://jacwxmp.starnetah.com'
// 请求头
const headers = {
'User-Agent': sudojia.getRandomUserAgent('H5'),
'Accept-Encoding': 'gzip',
'Content-Type': 'application/json',
'appType': '0'
};
!(async () => {
await checkUpdate($.name, jhCardList);
console.log(`\n已随机分配 User-Agent\n\n${headers['user-agent'] || headers['User-Agent']}`);
for (let i = 0; i < jhCardList.length; i++) {
const index = i + 1;
const [jsonBody, comment] = jhCardList[i].split('#');
$.isLogin = true;
$.loginBody = JSON.parse(jsonBody);
$.isComment = comment || false;
console.log(`\n*****第[${index}]个${$.name}账号*****`);
await login();
if (!$.isLogin) {
continue;
}
message += `📣====${$.name}账号[${index}]====📣\n`;
await $.wait(sudojia.getRandomWait(800, 1200));
await main();
await $.wait(sudojia.getRandomWait(2000, 2500));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
async function main() {
await getUserInfo();
await $.wait(sudojia.getRandomWait(1000, 1500));
await signIn();
await $.wait(sudojia.getRandomWait(1000, 1500));
await querySignNumber();
await $.wait(sudojia.getRandomWait(1000, 1500));
await modifyUserInfo();
await $.wait(sudojia.getRandomWait(1000, 1500));
await getPoints();
if (!$.isComment) {
console.log('\n检测到你未开启评论任务本次将跳过评论任务');
return;
}
await $.wait(sudojia.getRandomWait(1000, 1500));
await getInvitationList();
}
/**
* 登录
*
* @returns {Promise<void>}
*/
async function login() {
try {
const data = await sudojia.sendRequest(`${baseUrl}:18280/v2driver/v2/login`, 'post', headers, $.loginBody);
if (200 !== data.resultCode) {
console.error(data.message);
$.isLogin = false;
return;
}
headers.token = data.data.token;
$.uid = data.data.userId;
} catch (e) {
console.error('登录时发生异常 ->', e.response.data);
$.isLogin = false;
}
}
/**
* 获取用户信息
*
* @returns {Promise<void>}
*/
async function getUserInfo() {
try {
const data = await sudojia.sendRequest(`${baseUrl}:18280/v2driver/getUserInfo`, 'post', headers, {
uc_id: $.uid
});
if (200 !== data.resultCode) {
return console.error(`获取用户信息失败:${data.message}`);
}
console.log(`${data.data.name}(${data.data.phone})`);
message += `${data.data.name}(${data.data.phone})\n`;
$.isSign = data.data.isSign;
} catch (e) {
console.error('获取用户信息时发生异常 ->', e.response.data);
}
}
/**
* 签到
*
* @returns {Promise<void>}
*/
async function signIn() {
try {
const data = await sudojia.sendRequest(`${baseUrl}:18280/v2driver/signIn`, 'post', headers, {
ucId: $.uid
});
if (200 !== data.resultCode) {
message += `${data.message}\n`;
return console.error(`签到失败:${data.message}`);
}
console.log(`签到成功!积分+${data.data.score}`);
message += `签到成功!积分+${data.data.score}\n`;
} catch (e) {
console.error('签到时发生异常 ->', e.response.data);
}
}
/**
* 查询签到天数
*
* @returns {Promise<void>}
*/
async function querySignNumber() {
try {
const data = await sudojia.sendRequest(`${baseUrl}:18280/v2driver/querySignNumber`, 'post', headers, {
year: moment().year(),
month: moment().month() + 1,
ucId: $.uid
});
if (200 !== data.resultCode) {
return console.error(`查询签到天数失败:${data.message}`);
}
console.log(`已连续签到${data.data.continueTime}`);
message += `已连续签到${data.data.continueTime}\n`;
} catch (e) {
console.error('查询签到天数时发生异常 ->', e.response.data);
}
}
/**
* 完善个人信息
*
* @returns {Promise<void>}
*/
async function modifyUserInfo() {
try {
const data = await sudojia.sendRequest(`${baseUrl}:18280/v2driver/modifyUserInfo`, 'post', headers, {
"ucId": $.uid,
"name": "菜狗联盟",
"signature": "这个人很帅,什么都没有留下",
"sex": "0",
"interest": "看书",
"birthday": "1949-10-01",
"drivingAge": 10,
"provinceDesc": "北京市",
"cityDesc": "北京直辖市",
"jianghuaiStaff": "0",
})
if (200 !== data.resultCode) {
return console.error(`完善个人信息失败:${data.message}`);
}
console.log(`完善个人信息成功`);
} catch (e) {
console.error('完善个人信息时发生异常 ->', e.response.data);
}
}
/**
* 获取积分
*
* @returns {Promise<void>}
*/
async function getPoints() {
try {
const data = await sudojia.sendRequest(`${baseUrl}:18280/v2driver/queryIntegral`, 'post', headers, {
uc_id: $.uid
});
if (200 !== data.resultCode) {
return console.error(`获取积分失败:${data.message}`);
}
console.log(`当前积分:${data.data.integralCounts}`);
message += `当前积分:${data.data.integralCounts}\n\n`;
} catch (e) {
console.error('获取积分时发生异常 ->', e.response.data);
}
}
/**
* 获取文案
*
* @returns {Promise<*|null>}
*/
async function getWenAn() {
try {
const data = await sudojia.sendRequest('https://api.vvhan.com/api/ian/wenxue?type=json', 'get', {
'User-Agent': sudojia.getRandomUserAgent('PC'),
'Accept-Encoding': 'gzip, deflate, br, zstd'
});
if (!data.success) {
console.error('获取文案失败 ->', data);
return null;
}
return data.data.content;
} catch (e) {
console.error('获取文案时发生异常 ->', e);
return null;
}
}
/**
* 获取帖子列表
*
* @returns {Promise<void>}
*/
async function getInvitationList() {
try {
console.log('你真勇,居然开启了评论任务');
console.log('❗❗❗❗❗❗');
console.log('准备开始评论任务,如账号被冻结,损失的一切都与作者(@sudojia)无关\n');
for (let i = 0; i < 5; i++) {
console.log(`${i + 1}次评论...`);
const data = await sudojia.sendRequest(`${baseUrl}:18180/jac/bbs/api/invitationInfo/getInvitationList`, 'post', headers, {
"bbsType": "image",
"forumId": "30",
"page": 1,
"size": 30
})
if (200 !== data.resultCode) {
return console.error(`获取帖子列表失败:${data.message}`);
}
// 获取帖子对象
const posts = data.data.records[Math.floor(Math.random() * 30) + 1];
// 获取帖子ID
const invitationId = posts.invitationCommentInfo.invitationId;
await $.wait(sudojia.getRandomWait(5000, 8000));
await postComment(invitationId);
await $.wait(sudojia.getRandomWait(1000, 2000));
}
} catch (e) {
console.error('获取帖子列表时发生异常 ->', e.response.data);
}
}
/**
* 评论
*
* @param invitationId
* @returns {Promise<void>}
*/
async function postComment(invitationId) {
try {
const content = await getWenAn();
if (!content) {
return console.error('获取文案失败,暂不发表评论!');
}
console.log(`获取到的文案 ->\n${content}`);
const data = await sudojia.sendRequest(`${baseUrl}:18180/jac/bbs/api/invitationComment/newInvitationComment`, 'post', headers, {
commentContent: content,
invitationId: invitationId,
});
if (200 !== data.resultCode) {
return console.error(`评论失败:${data.message}`);
}
console.log('评论成功\n');
} catch (e) {
console.error('评论时发生异常 ->', e.response.data);
}
}

View File

@@ -0,0 +1,488 @@
# Source: https://gitee.com/jdqlscript/yyt/blob/master/%E7%94%B5%E4%BF%A1old/%E7%94%B5%E4%BF%A12/%E7%94%B5%E4%BF%A1%E6%9D%83%E7%9B%8A.py
# Raw: https://gitee.com/jdqlscript/yyt/raw/master/%E7%94%B5%E4%BF%A1old/%E7%94%B5%E4%BF%A12/%E7%94%B5%E4%BF%A1%E6%9D%83%E7%9B%8A.py
# Repo: jdqlscript/yyt
# Path: 电信old/电信2/电信权益.py
# UploadedAt: 2025-07-19T22:58:22+08:00
# SHA256: 579e6e7f9f9fc531fc1c7cfd1778dd8e05800269395d45faaefd48fb9f5eddab
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
新电信抢话费
群里发的,未测试好,自测
修改内容如下“
1.删除内置的一个手机账号
2.修改环境变量名保持和拉菲电信金豆本环境变量一致
3.恢复瑞数通杀.js调用地址确实也不知道是啥。398、399行注释
环境变量dxqy值为账号#密码 多账号 123123#45456&123123#45456
cron: 30 59 23 * * *
const $ = new Env("电信权益");
"""
#!/usr/bin/env python3
import os
import re
import sys
import ssl
import time
import json
import execjs
import base64
import random
import certifi
import aiohttp
import asyncio
import certifi
import datetime
import requests
import binascii
from lxml import etree
from http import cookiejar
from Crypto.Cipher import AES
from Crypto.Cipher import DES3
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Util.Padding import pad, unpad
from aiohttp import ClientSession, TCPConnector
from concurrent.futures import ThreadPoolExecutor
import subprocess
run_num=os.environ.get('reqNUM') or "2"
MAX_RETRIES = 3
RATE_LIMIT = 10 # 每秒请求数限制
class RateLimiter:
def __init__(self, rate_limit):
self.rate_limit = rate_limit
self.tokens = rate_limit
self.updated_at = time.monotonic()
async def acquire(self):
while self.tokens < 1:
self.add_new_tokens()
await asyncio.sleep(0.1)
self.tokens -= 1
def add_new_tokens(self):
now = time.monotonic()
time_since_update = now - self.updated_at
new_tokens = time_since_update * self.rate_limit
if new_tokens > 1:
self.tokens = min(self.tokens + new_tokens, self.rate_limit)
self.updated_at = now
class AsyncSessionManager:
def __init__(self):
self.session = None
self.connector = None
async def __aenter__(self):
ssl_context = ssl.create_default_context(cafile=certifi.where())
ssl_context.set_ciphers('DEFAULT@SECLEVEL=1')
self.connector = TCPConnector(ssl=ssl_context, limit=1000)
self.session = ClientSession(connector=self.connector)
return self.session
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.session.close()
await self.connector.close()
async def retry_request(session, method, url, **kwargs):
for attempt in range(MAX_RETRIES):
try:
await asyncio.sleep(1)
async with session.request(method, url, **kwargs) as response:
return await response.json()
# return await response.json()
except (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError) as e:
print(f"请求失败,第 {attempt + 1} 次重试: {e}")
if attempt == MAX_RETRIES - 1:
raise
await asyncio.sleep(2 ** attempt)
class BlockAll(cookiejar.CookiePolicy):
return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: False
netscape = True
rfc2965 = hide_cookie2 = False
def printn(m):
current_time = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
print(f'\n[{current_time}] {m}')
context = ssl.create_default_context()
context.set_ciphers('DEFAULT@SECLEVEL=1') # 低安全级别0/1
context.check_hostname = False # 禁用主机
context.verify_mode = ssl.CERT_NONE # 禁用证书
class DESAdapter(requests.adapters.HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
kwargs['ssl_context'] = context
return super().init_poolmanager(*args, **kwargs)
requests.packages.urllib3.disable_warnings()
# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
ss = requests.session()
ss.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","Referer":"https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"}
ss.mount('https://', DESAdapter())
ss.cookies.set_policy(BlockAll())
runTime = 0
key = b'1234567`90koiuyhgtfrdews'
iv = 8 * b'\0'
public_key_b64 = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBkLT15ThVgz6/NOl6s8GNPofdWzWbCkWnkaAm7O2LjkM1H7dMvzkiqdxU02jamGRHLX/ZNMCXHnPcW/sDhiFCBN18qFvy8g6VYb9QtroI09e176s+ZCtiv7hbin2cCTj99iUpnEloZm19lwHyo69u5UMiPMpq0/XKBO8lYhN/gwIDAQAB
-----END PUBLIC KEY-----'''
public_key_data = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+ugG5A8cZ3FqUKDwM57GM4io6JGcStivT8UdGt67PEOihLZTw3P7371+N47PrmsCpnTRzbTgcupKtUv8ImZalYk65dU8rjC/ridwhw9ffW2LBwvkEnDkkKKRi2liWIItDftJVBiWOh17o6gfbPoNrWORcAdcbpk2L+udld5kZNwIDAQAB
-----END PUBLIC KEY-----'''
def get_first_three(value):
# 处理数字情况
if isinstance(value, (int, float)):
return int(str(value)[:11])
elif isinstance(value, str):
return str(value)[:11]
else:
raise TypeError("error")
def run_Time(hour,miute,second):
date = datetime.datetime.now()
date_zero = datetime.datetime.now().replace(year=date.year, month=date.month, day=date.day, hour=hour, minute=miute, second=second)
date_zero_time = int(time.mktime(date_zero.timetuple()))
return date_zero_time
def encrypt(text):
cipher = DES3.new(key, DES3.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(text.encode(), DES3.block_size))
return ciphertext.hex()
def decrypt(text):
ciphertext = bytes.fromhex(text)
cipher = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), DES3.block_size)
return plaintext.decode()
def b64(plaintext):
public_key = RSA.import_key(public_key_b64)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return base64.b64encode(ciphertext).decode()
def encrypt_para(plaintext):
if not isinstance(plaintext, str):
plaintext = json.dumps(plaintext)
public_key = RSA.import_key(public_key_data)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return binascii.hexlify(ciphertext).decode()
def encode_phone(text):
encoded_chars = []
for char in text:
encoded_chars.append(chr(ord(char) + 2))
return ''.join(encoded_chars)
def getApiTime(api_url):
try:
with requests.get(api_url) as response:
if(not response or not response.text):
return time.time()
json_data = json.loads(response.text)
if (json_data.get("api")and json_data.get("api")not in("time") ):
timestamp_str = json_data.get('data', {}).get('t', '')
else:
timestamp_str = json_data.get('currentTime', {})
timestamp = int(timestamp_str) / 1000.0 # 将毫秒转为秒
difftime=time.time()-timestamp
return difftime;
except Exception as e:
print(f"获取时间失败: {e}")
return 0;
def userLoginNormal(phone,password):
alphabet = 'abcdef0123456789'
uuid = [''.join(random.sample(alphabet, 8)),''.join(random.sample(alphabet, 4)),'4'+''.join(random.sample(alphabet, 3)),''.join(random.sample(alphabet, 4)),''.join(random.sample(alphabet, 12))]
timestamp=datetime.datetime.now().strftime("%Y%m%d%H%M%S")
loginAuthCipherAsymmertric = 'iPhone 14 15.4.' + uuid[0] + uuid[1] + phone + timestamp + password[:6] + '0$$$0.'
r = ss.post('https://appgologin.189.cn:9031/login/client/userLoginNormal',json={"headerInfos": {"code": "userLoginNormal", "timestamp": timestamp, "broadAccount": "", "broadToken": "", "clientType": "#9.6.1#channel50#iPhone 14 Pro Max#", "shopId": "20002", "source": "110003", "sourcePassword": "Sid98s", "token": "", "userLoginName": phone}, "content": {"attach": "test", "fieldData": {"loginType": "4", "accountType": "", "loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric), "deviceUid": uuid[0] + uuid[1] + uuid[2], "phoneNum": encode_phone(phone), "isChinatelecom": "0", "systemVersion": "15.4.0", "authentication": password}}},verify=certifi.where()).json()
l = r['responseData']['data']['loginSuccessResult']
if l:
ticket = get_ticket(phone,l['userId'],l['token'])
return ticket
return False
async def exchangeForDay(phone, session, run_num, rid, stime):
async def delayed_conversion(delay):
await asyncio.sleep(delay)
await conversionRights(phone, rid,session)
tasks = [asyncio.create_task(delayed_conversion(i * stime)) for i in range(int(run_num))]
await asyncio.gather(*tasks)
def get_ticket(phone,userId,token):
r = ss.post('https://appgologin.189.cn:9031/map/clientXML',data='<Request><HeaderInfos><Code>getSingle</Code><Timestamp>'+datetime.datetime.now().strftime("%Y%m%d%H%M%S")+'</Timestamp><BroadAccount></BroadAccount><BroadToken></BroadToken><ClientType>#9.6.1#channel50#iPhone 14 Pro Max#</ClientType><ShopId>20002</ShopId><Source>110003</Source><SourcePassword>Sid98s</SourcePassword><Token>'+token+'</Token><UserLoginName>'+phone+'</UserLoginName></HeaderInfos><Content><Attach>test</Attach><FieldData><TargetId>'+encrypt(userId)+'</TargetId><Url>4a6862274835b451</Url></FieldData></Content></Request>',headers={'user-agent': 'CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1'},verify=certifi.where())
tk = re.findall('<Ticket>(.*?)</Ticket>',r.text)
if len(tk) == 0:
return False
return decrypt(tk[0])
async def exchange(s, phone, title, aid,jsexec, ckvalue):
try:
url="https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange"
# getck = await asyncio.to_thread(jsexec.call, "getck") # 两种方式一种用ck一种用后缀
# getck = getck.split(';')[0].split('=')
# ckvalue[getck[0]] = getck[1]
# async with s.post(url, cookies=ckvalue, json={"activityId": aid}) as response:
# 通过 retry_request 实现重试机制
# response = await retry_request(s, 'POST', get_url, cookies=ckvalue, json={"activityId": aid})
get_url = await asyncio.to_thread(jsexec.call,"getUrl", "POST",url)
async with s.post(get_url, cookies=ckvalue, json={"activityId": aid}) as response:
pass
except Exception as e:
print(e)
async def check(s,item,ckvalue):
checkGoods = s.get('https://wapact.189.cn:9001/gateway/stand/detailNew/check?activityId=' + item, cookies=ckvalue).json()
return checkGoods
async def conversionRights(phone, aid, session):
try:
# 获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print(f"{get_first_three(phone)}: 无法获取 Ruishu cookies")
return
value = {
"phone": phone,
"rightsId": aid
}
paraV = encrypt_para(value)
printn(f"{get_first_three(phone)}:开始兑换")
# 使用 Ruishu cookies 发送请求
response = session.post(
'https://wappark.189.cn/jt-sign/paradise/conversionRights',
json={"para": paraV},
cookies=ruishu_cookies
)
login = response.json()
printn(f"{get_first_three(phone)}:{login}")
if '兑换成功' in response.text:
QLAPI.notify(get_first_three(phone), login['resoultMsg'])
exit(0)
except Exception as e:
printn(f"{get_first_three(phone)}: 兑换请求发生错误: {str(e)}")
# 可以选择是否在这里添加重试逻辑
async def getLevelRightsList(phone, session):
try:
# 获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print("无法获取 Ruishu cookies")
return None
value = {
"phone": phone
}
paraV = encrypt_para(value)
# 使用 Ruishu cookies 发送请求
response = session.post(
'https://wappark.189.cn/jt-sign/paradise/getLevelRightsList',
json={"para": paraV},
cookies=ruishu_cookies
)
data = response.json()
if data.get('code') == 401:
print(f"获取失败:{data},原因大概是sign过期了")
return None
current_level = int(data['currentLevel'])
key_name = 'V' + str(current_level)
ids = [item['id'] for item in data.get(key_name, []) if item.get('name') == '话费']
return ids
except Exception as e:
print(f"获取失败,重试一次: {str(e)}")
try:
# 重试时重新获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print("重试时无法获取 Ruishu cookies")
return None
paraV = encrypt_para(value)
response = session.post(
'https://wappark.189.cn/jt-sign/paradise/getLevelRightsList',
json={"para": paraV},
cookies=ruishu_cookies
)
data = response.json()
if data.get('code') == 401:
print(f"重试获取失败:{data},原因大概是sign过期了")
return None
current_level = int(data['currentLevel'])
key_name = 'V' + str(current_level)
ids = [item['id'] for item in data.get(key_name, []) if item.get('name') == '话费']
return ids
except Exception as e:
print(f"重试也失败了: {str(e)}")
return None
def get_ruishu_cookies():
try:
# 获取当前文件所在目录
current_dir = os.path.dirname(os.path.abspath(__file__))
ruishu_path = os.path.join(current_dir, 'Ruishu.py')
# 执行 Ruishu.py 并获取输出
result = subprocess.run([sys.executable, ruishu_path],
capture_output=True,
text=True)
if result.returncode != 0:
print(f"Ruishu.py 执行错误: {result.stderr}")
return None
# 解析输出的 JSON
cookies = json.loads(result.stdout.strip())
return cookies
except Exception as e:
print(f"获取 Ruishu cookies 时发生错误: {str(e)}")
return None
async def getSign(ticket, session):
try:
# 获取 Ruishu cookies
ruishu_cookies = get_ruishu_cookies()
if not ruishu_cookies:
print("无法获取 Ruishu cookies")
return None
# 合并现有的 cookies 和 Ruishu cookies
cookies = {**ruishu_cookies}
# 使用合并后的 cookies 发送请求
response = session.get(
'https://wappark.189.cn/jt-sign/ssoHomLogin?ticket=' + ticket,
cookies=cookies
).json()
if response.get('resoultCode') == '0':
sign = response.get('sign')
return sign
else:
print(f"获取sign失败[{response.get('resoultCode')}]: {response}")
except Exception as e:
print(f"getSign 发生错误: {str(e)}")
return None
async def qgNight(phone, ticket, timeDiff,isTrue):
if isTrue:
runTime = run_Time(23,59,3)
else:
# runTime = run_Time(0,0,0) + 0.65
runTime = 0
if runTime >(time.time()+timeDiff):
difftime = runTime - time.time() - timeDiff
print(f"当前时间:{str(datetime.datetime.now())[11:23]},跟设定的时间不同,等待{difftime}秒开始兑换每天一次的")
await asyncio.sleep(difftime)
session = requests.Session()
session.mount('https://', DESAdapter())
session.verify = False # 禁用证书验证
sign =await getSign(ticket,session)
if sign:
# print(f"当前时间:{str(datetime.datetime.now())[11:23]}获取到了Sign:"+sign)
session.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","sign":sign}
else:
print("未获取sign。")
return
rightsId =await getLevelRightsList(phone,session)
if rightsId:
print("获取到了rightsId:"+rightsId[0])
else:
print("未能获取rightsId。")
return
# await asyncio.sleep(10)直接延迟也行或者用下面的等待一段时间。之所以这样是要先获取sign省一些步骤。
if isTrue:
runTime2 = run_Time(23,59,59) + 0.7
difftime = runTime2 - time.time() - timeDiff
printn(f"等待{difftime}s")
await asyncio.sleep(difftime)
await exchangeForDay(phone,session,run_num,rightsId[0],0.1)
async def qgDay(phone, ticket, timeDiff, isTrue):
async with AsyncSessionManager() as s:
pass
async def main(timeDiff,isTRUE,hour):
tasks = []
PHONES=os.environ.get('dxqy')
phone_list = PHONES.split('&')
for phoneV in phone_list:
value = phoneV.split('#')
phone, password = value[0], value[1]
printn(f'{get_first_three(phone)}开始登录')
ticket = userLoginNormal(phone,password)
if ticket:
# hour=datetime.datetime.now().hour
# hour=23
if hour > 15:
tasks.append(qgNight(phone, ticket, timeDiff, isTRUE))
# await asyncio.sleep(0.1)
else:#十点//十四点场次
tasks.append(qgDay(phone, ticket, timeDiff, isTRUE))
# await asyncio.sleep(0.1)
else:
printn(f'{phone} 登录失败')
await asyncio.gather(*tasks)
if __name__ == "__main__":
h = datetime.datetime.now().hour
# h=15 #手动设置场次的时间
print("当前小时为: "+str(h))
if 10 >h >0:
print("当前小时为: "+str(h)+"已过0点但未到10点开始准备抢十点场次")
wttime= run_Time(9,59,8) #抢十点场次
elif 14 >= h >=10:
print("当前小时为: "+str(h) +"已过10点但未到14点开始准备抢十四点场次")
wttime= run_Time(13,59,8) #抢十四点场次
else:
print("当前小时为: "+str(h)+"已过14点开始准备抢凌晨")
wttime= run_Time(23,58,58) #抢凌晨
#isTRUE=False
isTRUE=True
#isTRUE等于False则表示忽略所有限制直接运行。这个参数一般用于测试。实际生产一定要设置为True。
if(wttime >time.time()) :
wTime=wttime-time.time()
print("未到时间,计算后差异:"+str(wTime)+"")
if isTRUE:
print("一定要先测试,根据自身 设定的重发和多号,不然会出问题,抢购过早或者过晚。")
print("开始等待:")
time.sleep(wTime)
# timeValue = getApiTime("https://f.m.suning.com/api/ct.do")
timeValue = 0
timeDiff = timeValue if timeValue > 0 else 0
asyncio.run(main(timeDiff, isTRUE,h))
print("所有任务都已执行完毕!")

View File

@@ -0,0 +1,731 @@
# Source: https://gitee.com/jdqlscript/yyt/blob/master/%E7%94%B5%E4%BF%A1/7%E6%9C%881%E6%97%A5%E9%87%91%E8%B1%86%E6%8D%A2%E8%AF%9D%E8%B4%B9.py
# Raw: https://gitee.com/jdqlscript/yyt/raw/master/%E7%94%B5%E4%BF%A1/7%E6%9C%881%E6%97%A5%E9%87%91%E8%B1%86%E6%8D%A2%E8%AF%9D%E8%B4%B9.py
# Repo: jdqlscript/yyt
# Path: 电信/7月1日金豆换话费.py
# UploadedAt: 2025-07-19T22:58:22+08:00
# SHA256: 6ac467d0a0bf44c28e3c9619647bad1e67686357d0fe8a19603ae6c45c35704f
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
cron: 0 59 9,13 * * *
new Env('电信金豆兑换话费');
"""
import subprocess
import sys
import asyncio
import aiohttp
import os
import execjs
import requests
import re
import time as time_module # 重命名导入以避免冲突
import json
import random
import datetime
import base64
import ssl
import certifi
import traceback
from bs4 import BeautifulSoup
from loguru import logger
from lxml import etree
import gjc
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad
from Crypto.Util.strxor import strxor
from Crypto.Cipher import AES
from http import cookiejar # Python 2: import cookielib as cookiejar
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
def get_network_time():
"""从淘宝接口获取网络时间"""
url = "https://acs.m.taobao.com/gw/mtop.common.getTimestamp/"
try:
response = requests.get(url)
if response.status_code == 200:
data = response.json()
if "data" in data and "t" in data["data"]:
timestamp = int(data["data"]["t"]) # 获取时间戳
return datetime.datetime.fromtimestamp(timestamp / 1000) # 转换为 datetime 对象
else:
raise ValueError("接口返回数据格式错误")
else:
raise Exception(f"获取网络时间失败,状态码: {response.status_code}")
except Exception as e:
print(f"{str(get_network_time())[11:22]} 获取网络时间失败: {e}")
return datetime.datetime.now() # 如果失败,使用本地时间作为备选
# 获取本地时间和网络时间
local_time = datetime.datetime.now()
network_time = get_network_time()
# 计算时间差
time_diff = network_time - local_time
# 输出时间差,精确到微秒
print(f"本地时间: {local_time.strftime('%Y-%m-%d %H:%M:%S.%f')}")
print(f"网络时间: {network_time.strftime('%Y-%m-%d %H:%M:%S.%f')}")
print(f"时间差: {time_diff.total_seconds():.6f}")
# 默认兑换策略
MEXZ = os.getenv("MEXZ")
# 定义时间段
morning_start = datetime.time(9, 30, 3)
morning_end = datetime.time(10, 0, 30)
afternoon_start = datetime.time(13, 30, 3)
afternoon_end = datetime.time(14, 0, 30)
# 获取当前时间
now = get_network_time().time()
# 判断当前时间是否在指定的时间段内
if (morning_start <= now <= morning_end) or (afternoon_start <= now <= afternoon_end):
# 在指定时间段内,使用环境变量中的 MEXZ 配置
if not MEXZ:
MEXZ = "0.5,5,6;1,10,3"
else:
# 不在指定时间段内,使用默认策略
MEXZ = "0.5,5,6;1,10,3"
# 解析 MEXZ 配置
morning_exchanges, afternoon_exchanges = MEXZ.split(';')
morning_exchanges = [f"{x}元话费" for x in morning_exchanges.split(',')]
afternoon_exchanges = [f"{x}元话费" for x in afternoon_exchanges.split(',')]
# 从环境变量中获取代理池地址
DY_PROXY = os.getenv("DY_PROXY123")
async def get_proxy_from_pool():
"""从代理池获取代理IP"""
if not DY_PROXY:
raise ValueError("DY_PROXY 环境变量未设置")
async with aiohttp.ClientSession() as session:
async with session.get(DY_PROXY) as response:
if response.status != 200:
raise Exception(f"从代理池获取代理IP失败状态码: {response.status}")
proxy_ip = await response.text()
return proxy_ip.strip() # 去除可能的空白字符
class BlockAll(cookiejar.CookiePolicy):
return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: False
netscape = True
rfc2965 = hide_cookie2 = False
def printn(m):
print(f'\n{m}')
def print_time_log(m):
print(f'{str(get_network_time())[11:22]} {m}')
ORIGIN_CIPHERS = ('DEFAULT@SECLEVEL=1')
class DESAdapter(HTTPAdapter):
def __init__(self, *args, **kwargs):
CIPHERS = ORIGIN_CIPHERS.split(':')
random.shuffle(CIPHERS)
CIPHERS = ':'.join(CIPHERS)
self.CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'
super().__init__(*args, **kwargs)
def init_poolmanager(self, *args, **kwargs):
context = create_urllib3_context(ciphers=self.CIPHERS)
context.check_hostname = False
kwargs['ssl_context'] = context
return super(DESAdapter, self).init_poolmanager(*args, **kwargs)
def proxy_manager_for(self, *args, **kwargs):
context = create_urllib3_context(ciphers=self.CIPHERS)
context.check_hostname = False
kwargs['ssl_context'] = context
return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)
requests.packages.urllib3.disable_warnings()
ssl_context = ssl.create_default_context()
ssl_context.set_ciphers("DEFAULT@SECLEVEL=1") # Set security level to allow smaller DH keys
ss = requests.session()
ss.verify = certifi.where()
ss.headers = {
"User-Agent": "Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36",
"Referer": "https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"
}
ss.mount('https://', DESAdapter())
ss.cookies.set_policy(BlockAll())
yc = 1
wt = 0
kswt = 0.1
yf = get_network_time().strftime("%Y%m")
ip_list = []
jp = {"9": {}, "13": {}}
try:
with open('电信金豆换话费.log') as fr:
dhjl = json.load(fr)
except:
dhjl = {}
if yf not in dhjl:
dhjl[yf] = {}
load_token_file = 'chinaTelecom_cache.json'
try:
with open(load_token_file, 'r') as f:
load_token = json.load(f)
except:
load_token = {}
errcode = {
"0": "兑换成功",
"412": "兑换次数已达上限",
"413": "商品已兑完",
"420": "未知错误",
"410": "该活动未开始",
"501": "服务器处理错误",
"Y0001": "当前等级不足,去升级兑当前话费",
"Y0002": "使用翼相连网络600分钟或连接并拓展网络500分钟可兑换此奖品",
"Y0003": "使用翼相连共享流量400M或共享WIFI2GB可兑换此奖品",
"Y0004": "使用翼相连共享流量2GB可兑换此奖品",
"Y0005": "当前等级不足,去升级兑当前话费",
"E0001": "您的网龄不足10年暂不能兑换"
}
key = b'1234567`90koiuyhgtfrdews'
iv = 8 * b'\0'
public_key_b64 = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBkLT15ThVgz6/NOl6s8GNPofdWzWbCkWnkaAm7O2LjkM1H7dMvzkiqdxU02jamGRHLX/ZNMCXHnPcW/sDhiFCBN18qFvy8g6VYb9QtroI09e176s+ZCtiv7hbin2cCTj99iUpnEloZm19lwHyo69u5UMiPMpq0/XKBO8lYhN/gwIDAQAB
-----END PUBLIC KEY-----'''
public_key_data = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+ugG5A8cZ3FqUKDwM57GM4io6JGcStivT8UdGt67PEOihLZTw3P7371+N47PrmsCpnTRzbTgcupKtUv8ImZalYk65dU8rjC/ridwhw9ffW2LBwvkEnDkkKKRi2liWIItDftJVBiWOh17o6gfbPoNrWORcAdcbpk2L+udld5kZNwIDAQAB
-----END PUBLIC KEY-----'''
def t(h):
date = get_network_time()
date_zero = date.replace(hour=h, minute=59, second=20)
date_zero_time = time_module.mktime(date_zero.timetuple()) # 使用 timetuple() 转换为 struct_time
return date_zero_time
def encrypt(text):
cipher = DES3.new(key, DES3.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(text.encode(), DES3.block_size))
return ciphertext.hex()
def decrypt(text):
ciphertext = bytes.fromhex(text)
cipher = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), DES3.block_size)
return plaintext.decode()
def b64(plaintext):
public_key = RSA.import_key(public_key_b64)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return base64.b64encode(ciphertext).decode()
def encrypt_para(plaintext):
public_key = RSA.import_key(public_key_data)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return ciphertext.hex()
def encode_phone(text):
encoded_chars = []
for char in text:
encoded_chars.append(chr(ord(char) + 2))
return ''.join(encoded_chars)
def ophone(t):
key = b'34d7cb0bcdf07523'
utf8_key = key.decode('utf-8')
utf8_t = t.encode('utf-8')
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = cipher.encrypt(pad(utf8_t, AES.block_size))
return ciphertext.hex()
def send(uid, content):
appToken = os.getenv("WXPUSHER_APP_TOKEN") # 从环境变量中获取 appToken
uid = os.getenv("WXPUSHER_UID") # 从环境变量中获取 uid
if not appToken or not uid:
raise ValueError("WXPUSHER_APP_TOKEN 或 WXPUSHER_UID 未设置")
r = requests.post('https://wxpusher.zjiecode.com/api/send/message', json={"appToken": appToken, "content": content, "contentType": 1, "uids": [uid]}).json()
return r
def userLoginNormal(phone, password):
alphabet = 'abcdef0123456789'
uuid = [''.join(random.sample(alphabet, 8)), ''.join(random.sample(alphabet, 4)), '4' + ''.join(random.sample(alphabet, 3)), ''.join(random.sample(alphabet, 4)), ''.join(random.sample(alphabet, 12))]
timestamp = get_network_time().strftime("%Y%m%d%H%M%S")
loginAuthCipherAsymmertric = 'iPhone 14 15.4.' + uuid[0] + uuid[1] + phone + timestamp + password[:6] + '0$$$0.'
try:
r = ss.post('https://appgologin.189.cn:9031/login/client/userLoginNormal',json={"headerInfos": {"code": "userLoginNormal", "timestamp": timestamp, "broadAccount": "", "broadToken": "", "clientType": "#11.3.0#channel35#Xiaomi Redmi K30 Pro#", "shopId": "20002", "source": "110003", "sourcePassword": "Sid98s", "token": "", "userLoginName": encode_phone(phone)}, "content": {"attach": "test", "fieldData": {"loginType": "4", "accountType": "", "loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric), "deviceUid": uuid[0] + uuid[1] + uuid[2], "phoneNum": encode_phone(phone), "isChinatelecom": "0", "systemVersion": "12", "authentication": encode_phone(password)}}},verify=certifi.where()).json()
#r = ss.post('https://appgologin.189.cn:9031/login/client/userLoginNormal', json={"headerInfos": {"code": "userLoginNormal", "timestamp": timestamp, "broadAccount": "", "broadToken": "", "clientType": "#9.6.1#channel50#iPhone 14 Pro Max#", "shopId": "20002", "source": "110003", "sourcePassword": "Sid98s", "token": "", "userLoginName": phone}, "content": {"attach": "test", "fieldData": {"loginType": "4", "accountType": "", "loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric), "deviceUid": uuid[0] + uuid[1] + uuid[2], "phoneNum": encode_phone(phone), "isChinatelecom": "0", "systemVersion": "15.4.0", "authentication": password}}}).json()
except Exception as e:
print(f"登录请求失败,错误信息: {e}")
return False
# 添加错误处理逻辑
if r is None:
print(f"登录请求失败,返回值为 None")
return False
if 'responseData' not in r or r['responseData'] is None:
print(f"登录请求失败responseData 不存在或为 None: {r}")
return False
if 'data' not in r['responseData'] or r['responseData']['data'] is None:
print(f"登录请求失败data 不存在或为 None: {r}")
return False
if 'loginSuccessResult' not in r['responseData']['data']:
print(f"登录请求失败loginSuccessResult 不存在: {r}")
return False
l = r['responseData']['data']['loginSuccessResult']
print(l)
if l:
load_token[phone] = l
with open(load_token_file, 'w') as f:
json.dump(load_token, f)
ticket = get_ticket(phone, l['userId'], l['token'])
return ticket
return False
def get_ticket(phone, userId, token):
r = ss.post('https://appgologin.189.cn:9031/map/clientXML', data='<Request><HeaderInfos><Code>getSingle</Code><Timestamp>' + get_network_time().strftime("%Y%m%d%H%M%S") + '</Timestamp><BroadAccount></BroadAccount><BroadToken></BroadToken><ClientType>#9.6.1#channel50#iPhone 14 Pro Max#</ClientType><ShopId>20002</ShopId><Source>110003</Source><SourcePassword>Sid98s</SourcePassword><Token>' + token + '</Token><UserLoginName>' + phone + '</UserLoginName></HeaderInfos><Content><Attach>test</Attach><FieldData><TargetId>' + encrypt(userId) + '</TargetId><Url>4a6862274835b451</Url></FieldData></Content></Request>', headers={'user-agent': 'CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1'})
tk = re.findall('<Ticket>(.*?)</Ticket>', r.text)
if len(tk) == 0:
return False
# print(tk)
return decrypt(tk[0])
async def exchange(phone, s, title, aid, uid, amount):
global h # 使用全局变量 h
masked_phone = phone[:3] + '****' + phone[-4:]
try:
# 第一次请求:获取 cookie
tt = time_module.time()
start_time = time_module.time() # 记录开始时间
cookies = await gjc.get_rs('https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange', s, md='post')
end_time = time_module.time() # 记录结束时间
print_time_log(f"{masked_phone} 获取到 {title} 的cookies 用时: {end_time - start_time:.3f}")
# 获取当前时间
now = get_network_time()
# 如果 h 没有赋值,则使用当前时间的小时数
if h is None:
h = now.hour
# 设置第一次等待的目标时间9:59:50 或 13:59:50
if h == 9:
first_target_time = now.replace(hour=h, minute=59, second=30, microsecond=0)
elif h == 13:
first_target_time = now.replace(hour=h, minute=59, second=30, microsecond=0)
# 计算第一次等待的时间差
first_time_diff = (first_target_time - now).total_seconds()
# 如果第一次等待的时间差在 0 到 300 秒之间,则等待到第一次目标时间
if 0 <= first_time_diff <= 300:
print_time_log(f"{masked_phone} 等待 {first_time_diff:.2f} 秒...")
await asyncio.sleep(first_time_diff)
# 判断当前时间是否在指定的时间段内
morning_start = datetime.time(9, 30, 50)
morning_end = datetime.time(10, 0, 5)
afternoon_start = datetime.time(13, 30, 40)
afternoon_end = datetime.time(14, 0, 5)
current_time = now.time()
if (morning_start <= current_time <= morning_end) or (afternoon_start <= current_time <= afternoon_end):
# 在指定时间段内,根据 DY_PROXY 是否设置来决定使用代理或本地 IP
if DY_PROXY:
try:
proxy_ip = await get_proxy_from_pool()
proxy = f"http://{proxy_ip}" # 根据代理池返回的格式调整
print_time_log(f"{masked_phone} 从代理池获取到代理IP: {proxy_ip}")
except ValueError as e:
print_time_log(f"{masked_phone} {e} 使用本地 IP ")
proxy = None # 设置为 None表示使用本地 IP
else:
print_time_log(f"{masked_phone} DY_PROXY 未设置,使用本地 IP")
proxy = None # 设置为 None表示使用本地 IP
else:
# 不在指定时间段内,直接使用本地 IP
print_time_log(f"{masked_phone} 不在指定时间段内,使用本地 IP")
proxy = None # 设置为 None表示使用本地 IP
# 设置第二次等待的目标时间9:59:59 或 13:59:59
if h == 9:
second_target_time = now.replace(hour=h, minute=59, second=55, microsecond=803600)
elif h == 13:
second_target_time = now.replace(hour=h, minute=59, second=55, microsecond=793600)
# 计算第二次等待的时间差
second_time_diff = (second_target_time - get_network_time()).total_seconds()
# 如果第二次等待的时间差在 0 到 300 秒之间,则等待到第二次目标时间
if 0 <= second_time_diff <= 300:
print_time_log(f"{masked_phone} 等待 {second_time_diff:.2f} 秒...")
await asyncio.sleep(second_time_diff)
# 打印是否使用了代理
if proxy:
print_time_log(f"{masked_phone} 正在使用代理IP: {proxy}")
else:
print_time_log(f"{masked_phone} 正在使用本地 IP")
# 第二次请求:发送兑换请求,使用代理 IP 或本地 IP
url = "https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange"
# 记录请求开始时间
request_start_time = datetime.datetime.now() # 获取当前时间,精确到微秒
# 发送请求
async with s.post(url, json={"activityId": aid}, cookies=cookies, proxy=proxy) as r:
# 记录请求结束时间
request_end_time = datetime.datetime.now() # 获取当前时间,精确到微秒
print(f'\n{str(get_network_time())[11:22]}')
print(f"{masked_phone} 发送兑换请求的时间: {request_start_time.strftime('%Y-%m-%d %H:%M:%S.%f')}")
# 打印请求耗时,精确到微秒
print(f"{masked_phone} 请求耗时: {(request_end_time - request_start_time).total_seconds():.6f}")
# 处理响应
if r.status == 412:
print(f"{masked_phone} 遇到连续 412 错误,已终止本次兑换!")
return
print(f"{masked_phone} 响应码: {r.status} {await r.text()}")
if r.status == 200:
r_json = await r.json()
if r_json["code"] == 0:
if r_json["biz"] != {} and r_json["biz"]["resultCode"] in errcode:
print(f'{masked_phone} ------ {str(get_network_time())[11:22]} ------ {title} {errcode[r_json["biz"]["resultCode"]]}')
if r_json["biz"]["resultCode"] in ["0", "412"]:
if r_json["biz"]["resultCode"] == "0":
msg = phone + ":" + title + "兑换成功"
send(uid, msg) # 发送推送通知
if phone not in dhjl[yf][title]:
dhjl[yf][title] += "#" + phone
with open('电信金豆换话费.log', 'w') as f:
json.dump(dhjl, f, ensure_ascii=False)
else:
print_time_log(f'{masked_phone} {r_json}')
else:
print_time_log(f"{masked_phone} 兑换请求失败: {await r.text()}")
except Exception as e:
print_time_log(f"{masked_phone} 发生错误: {e}")
# print(f"详细错误信息: {traceback.format_exc()}") # 打印详细的错误堆栈
async def dh(phone, s, title, aid, wt, uid):
global h # 使用全局变量 h
masked_phone = phone[:3] + '****' + phone[-4:]
print_time_log(f"{masked_phone} {title} 【开始兑换】")
cs = 0
tasks = []
creat_start_time = datetime.datetime.now() # 获取当前时间,精确到微秒
while cs < 1:
# 提取金额
amount = title.split('')[0]
if (h == 9 and title in morning_exchanges) or (h == 13 and title in afternoon_exchanges):
tasks.append(exchange(phone, s, title, aid, uid, amount))
else:
print_time_log(f"{masked_phone} 商品:{title} 不在兑换时间范围内,跳过兑换")
cs += 1
await asyncio.sleep(0.1)
creat_end_time = datetime.datetime.now() # 获取当前时间,精确到微秒
print_time_log(f"{masked_phone} 创建了【{cs}】次并发任务 耗时:{(creat_end_time - creat_start_time).total_seconds():.6f}")
while wt > get_network_time().timestamp():
await asyncio.sleep(1)
await asyncio.gather(*tasks)
def aes_ecb_encrypt(plaintext, key):
key = key.encode('utf-8')
if len(key) not in [16, 24, 32]:
raise ValueError("密钥长度必须为16/24/32字节")
# 对明文进行PKCS7填充
padded_data = pad(plaintext.encode('utf-8'), AES.block_size)
#padded_data = plaintext.encode('utf-8')
# 创建AES ECB加密器
cipher = AES.new(key, AES.MODE_ECB)
# 加密并返回Base64编码结果
ciphertext = cipher.encrypt(padded_data)
return base64.b64encode(ciphertext).decode('utf-8')
async def ks(phone, ticket, uid):
global h, wt # 使用全局变量 h 和 wt
masked_phone = phone[:3] + '****' + phone[-4:]
headers = {
"User-Agent": "Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36",
"Referer": "https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"
}
timeout = aiohttp.ClientTimeout(total=20) # 设置超时时间
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=ssl_context), headers=headers, timeout=timeout) as s:
try:
cookies = await gjc.get_rs('https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange', session=s)
s.cookie_jar.update_cookies(cookies)
login_data = {
"ticket": ticket,
"backUrl": "https%3A%2F%2Fwapact.189.cn%3A9001",
"platformCode": "P201010301",
"loginType": 2
}
encrypted_data = aes_ecb_encrypt(json.dumps(login_data), 'telecom_wap_2018')
# 登录请求
max_retries = 3 # 最大重试次数
retries = 0
while retries < max_retries:
try:
login_response = await s.post(
'https://wapact.189.cn:9001/unified/user/login',
data=encrypted_data,
headers={
"Content-Type": "application/json;charset=UTF-8",
"Accept": "application/json, text/javascript, */*; q=0.01"
}
)
# 处理登录响应
if login_response.status == 200:
login = await login_response.json()
break # 如果成功,跳出循环
elif login_response.status == 412:
print_time_log(f"{masked_phone} 登录请求失败HTTP状态码: {login_response.status}, 直接重新调用 ks 函数...")
return await ks(phone, ticket, uid) # 直接从头开始调用 ks 函数
else:
print_time_log(f"{masked_phone} 登录请求失败HTTP状态码: {login_response.status}")
print_time_log(f"响应内容: {await login_response.text()}")
except (aiohttp.ClientError, asyncio.TimeoutError) as e:
retries += 1
print_time_log(f"{masked_phone} 登录请求失败,重试 {retries}/{max_retries}... 错误信息: {e}")
await asyncio.sleep(2 ** retries) # 指数退避算法等待时间
if retries == max_retries:
print_time_log(f"{masked_phone} 登录失败,达到最大重试次数. 尝试重新调用 ks 函数...")
return await ks(phone, ticket, uid) # 递归调用 ks 函数
if 'login' in locals() and login['code'] == 0:
s.headers["Authorization"] = "Bearer " + login["biz"]["token"]
r = await s.get('https://wapact.189.cn:9001/gateway/golden/api/queryInfo')
r_json = await r.json()
amountTotal = r_json["biz"]["amountTotal"]
print_time_log(f'{masked_phone} 金豆余额:{amountTotal}')
queryBigDataAppGetOrInfo = await s.get('https://wapact.189.cn:9001/gateway/golden/goldGoods/getGoodsList?floorType=0&userType=1&page=1&order=3&tabOrder=')
queryBigDataAppGetOrInfo_json = await queryBigDataAppGetOrInfo.json()
# 检查列表是否为空
if "biz" in queryBigDataAppGetOrInfo_json and "ExchangeGoodslist" in queryBigDataAppGetOrInfo_json["biz"]:
for i in queryBigDataAppGetOrInfo_json["biz"]["ExchangeGoodslist"]:
if '话费' not in i["title"]:
continue
for j in morning_exchanges:
if j in i["title"]:
jp["9"][j] = i["id"]
for j in afternoon_exchanges:
if j in i["title"]:
jp["13"][j] = i["id"]
else:
print_time_log(f"{masked_phone} 获取兑换商品列表失败")
h = get_network_time().hour
if 11 > h:
h = 9
else:
h = 13
if len(sys.argv) == 2:
h = int(sys.argv[1])
d = jp[str(h)]
wt = t(h) + kswt
tasks = []
for di in sorted(d.keys(), key=lambda x: float(x.replace('元话费', '')), reverse=True):
if di not in dhjl[yf]:
dhjl[yf][di] = ""
if phone in dhjl[yf][di]:
print_time_log(f"{masked_phone} {di} 【已兑换】")
print_time_log(f"{masked_phone} {di} 【跳过兑换】")
else:
print_time_log(f"{masked_phone} {di} 【未兑换】")
if wt - time_module.time() > 30 * 60:
print_time_log(f"等待时间超过30分钟退出运行")
return
tasks.append(dh(phone, s, di, d[di], wt, uid))
print_time_log(f"{masked_phone} 共计【{len(tasks)}】个兑换任务 正在进行中~")
await asyncio.gather(*tasks)
else:
print_time_log(f"{masked_phone} 获取token失败, 错误信息: {login['message']}")
except Exception as e:
print_time_log(f"{masked_phone} 发生错误: {e}")
return # 跳过当前账户,继续处理其他账户
async def main():
global wt, rs, h # 使用全局变量 wt, rs, h
headers = {
"User-Agent": "Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36",
"Referer": "https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"
}
timeout = aiohttp.ClientTimeout(total=20) # 设置超时时间
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=ssl_context), headers=headers, timeout=timeout) as ss:
r = await ss.get('https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange')
if '$_ts=window' in await r.text():
rs = 1
# first_request()
else:
rs = 0
# 获取账号列表
chinaTelecomAccount = os.environ.get('chinaTelecomAccount')
if not chinaTelecomAccount:
print("未检测到账号")
return
accounts = chinaTelecomAccount.split('&')
account_count = len(accounts)
print_time_log(f"检测到 【{account_count}】 个账号")
# 分批次处理账号每批次20个账号
batch_size = 20
for i in range(0, account_count, batch_size):
batch_accounts = accounts[i:i + batch_size]
tasks = []
for account in batch_accounts:
account_info = account.split('#')
phone = account_info[0]
password = account_info[1]
uid = account_info[-1]
ticket = False
masked_phone = phone[:3] + '****' + phone[-4:]
if phone in load_token:
print_time_log(f'{masked_phone} 使用缓存登录')
ticket = get_ticket(phone, load_token[phone]['userId'], load_token[phone]['token'])
if not ticket:
print_time_log(f'{masked_phone} 使用密码登录')
ticket = userLoginNormal(phone, password)
if ticket:
tasks.append(ks(phone, ticket, uid))
else:
print_time_log(f'{masked_phone} ️登录失败')
continue # 跳过登录失败的账号
# 等待到设定时间
while wt > datetime.datetime.now().timestamp():
await asyncio.sleep(1)
await asyncio.gather(*tasks)
print_time_log(f"完成批次 {i // batch_size + 1} 的账号处理")
# 等待一段时间再处理下一个批次
await asyncio.sleep(2) # 等待2秒
START_LOG = rf'''
+--------------------------------------------------------------------+
话费兑换本,有几个需要根据自己机器配置来调整的地方:
1.打开脚本找到第二次等待时间大概381和383行根据情况调整secone秒数一般58秒。
2.次数改一下找到cs < 1,那一行1就是次数可以修改5次看看。
+--------------------------------------------------------------------+
'''
if __name__ == "__main__":
print(START_LOG)
print(f" 提醒:程序将提前【{kswt} 秒】启动兑换流程")
if len(sys.argv) > 1:
h = int(sys.argv[1])
else:
h = None # 默认值为 None
asyncio.run(main())
# 获取当前月份
current_month = get_network_time().strftime("%Y%m")
# 读取原始日志文件
try:
with open('电信金豆换话费.log', 'r') as fr:
dhjl = json.load(fr)
except FileNotFoundError:
dhjl = {}
# 初始化新的日志结构
dhjl2 = {}
# 只处理当前月份的数据
if current_month in dhjl:
records = dhjl[current_month]
for fee, phones in records.items():
phone_list = phones.strip('#').split('#')
for phone in phone_list:
if phone not in dhjl2:
dhjl2[phone] = {}
if current_month not in dhjl2[phone]:
dhjl2[phone][current_month] = []
dhjl2[phone][current_month].append(fee)
# 写入新的日志文件
with open('电信金豆换话费2.log', 'w') as fw:
json.dump(dhjl2, fw, ensure_ascii=False, indent=4)
# 检查当前时间是否在10:05:10到11:00:00或14:05:10到15:00:00之间
current_time = get_network_time()
start_time_1 = current_time.replace(hour=10, minute=0, second=00)
end_time_1 = current_time.replace(hour=10, minute=20, second=0)
start_time_2 = current_time.replace(hour=14, minute=0, second=00)
end_time_2 = current_time.replace(hour=14, minute=20, second=0)
if (start_time_1 <= current_time < end_time_1) or (start_time_2 <= current_time < end_time_2):
# 运行汇总推送脚本
subprocess.run(["python", "汇总推送.py"])
else:
print("当前不在推送时间,不运行汇总推送脚本。")

View File

@@ -0,0 +1,540 @@
# Source: https://gitee.com/jdqlscript/yyt/blob/master/%E7%94%B5%E4%BF%A1old/%E7%94%B5%E4%BF%A12/%E7%94%B5%E4%BF%A1%E9%87%91%E8%B1%86%E6%8D%A2%E8%AF%9D%E8%B4%B9.py
# Raw: https://gitee.com/jdqlscript/yyt/raw/master/%E7%94%B5%E4%BF%A1old/%E7%94%B5%E4%BF%A12/%E7%94%B5%E4%BF%A1%E9%87%91%E8%B1%86%E6%8D%A2%E8%AF%9D%E8%B4%B9.py
# Repo: jdqlscript/yyt
# Path: 电信old/电信2/电信金豆换话费.py
# UploadedAt: 2025-07-19T22:58:22+08:00
# SHA256: 57a582c067ad187f7c88e0eb8f1fe18b927452b258ac0e935e0ed8ac61699429
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
'''
变量chinaTelecomAccount
变量格式: 手机号#服务密码
多号创建多个变量&隔开
'''
import requests
import re
import time
import json
import random
import datetime
import base64
import threading
import ssl
import execjs
import os
import sys
import certifi
from bs4 import BeautifulSoup
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad
from Crypto.Util.strxor import strxor
from Crypto.Cipher import AES
from http import cookiejar # Python 2: import cookielib as cookiejar
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
class BlockAll(cookiejar.CookiePolicy):
return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: False
netscape = True
rfc2965 = hide_cookie2 = False
def printn(m):
print(f'\n{m}')
ORIGIN_CIPHERS = ('DEFAULT@SECLEVEL=1')
ip_list = []
class DESAdapter(HTTPAdapter):
def __init__(self, *args, **kwargs):
"""
A TransportAdapter that re-enables 3DES support in Requests.
"""
CIPHERS = ORIGIN_CIPHERS.split(':')
random.shuffle(CIPHERS)
CIPHERS = ':'.join(CIPHERS)
self.CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'
super().__init__(*args, **kwargs)
def init_poolmanager(self, *args, **kwargs):
context = create_urllib3_context(ciphers=self.CIPHERS)
kwargs['ssl_context'] = context
return super(DESAdapter, self).init_poolmanager(*args, **kwargs)
def proxy_manager_for(self, *args, **kwargs):
context = create_urllib3_context(ciphers=self.CIPHERS)
kwargs['ssl_context'] = context
return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)
requests.packages.urllib3.disable_warnings()
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
ssl_context.set_ciphers('DEFAULT@SECLEVEL=0')
ss = requests.session()
ss.verify = certifi.where()
ss.ssl=ssl_context
ss.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","Referer":"https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"}
ss.mount('https://', DESAdapter())
yc = 0.1
wt = 0
kswt = -3
yf = datetime.datetime.now().strftime("%Y%m")
jp = {"9":{},"12":{},"13":{},"23":{}}
try:
with open('电信金豆换话费.log') as fr:
dhjl = json.load(fr)
except:
dhjl = {}
if yf not in dhjl:
dhjl[yf] = {}
wxp={}
errcode = {
"0":"兑换成功",
"412":"兑换次数已达上限",
"413":"商品已兑完",
"420":"未知错误",
"410":"该活动已失效~",
"Y0001":"当前等级不足,去升级兑当前话费",
"Y0002":"使用翼相连网络600分钟或连接并拓展网络500分钟可兑换此奖品",
"Y0003":"使用翼相连共享流量400M或共享WIFI2GB可兑换此奖品",
"Y0004":"使用翼相连共享流量2GB可兑换此奖品",
"Y0005":"当前等级不足,去升级兑当前话费",
"E0001":"您的网龄不足10年暂不能兑换"
}
#加密参数
key = b'1234567`90koiuyhgtfrdews'
iv = 8 * b'\0'
public_key_b64 = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBkLT15ThVgz6/NOl6s8GNPofdWzWbCkWnkaAm7O2LjkM1H7dMvzkiqdxU02jamGRHLX/ZNMCXHnPcW/sDhiFCBN18qFvy8g6VYb9QtroI09e176s+ZCtiv7hbin2cCTj99iUpnEloZm19lwHyo69u5UMiPMpq0/XKBO8lYhN/gwIDAQAB
-----END PUBLIC KEY-----'''
public_key_data = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+ugG5A8cZ3FqUKDwM57GM4io6JGcStivT8UdGt67PEOihLZTw3P7371+N47PrmsCpnTRzbTgcupKtUv8ImZalYk65dU8rjC/ridwhw9ffW2LBwvkEnDkkKKRi2liWIItDftJVBiWOh17o6gfbPoNrWORcAdcbpk2L+udld5kZNwIDAQAB
-----END PUBLIC KEY-----'''
def t(h):
date = datetime.datetime.now()
date_zero = datetime.datetime.now().replace(year=date.year, month=date.month, day=date.day, hour=h, minute=59, second=59)
date_zero_time = int(time.mktime(date_zero.timetuple()))
return date_zero_time
def encrypt(text):
cipher = DES3.new(key, DES3.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(text.encode(), DES3.block_size))
return ciphertext.hex()
def decrypt(text):
ciphertext = bytes.fromhex(text)
cipher = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), DES3.block_size)
return plaintext.decode()
def b64(plaintext):
public_key = RSA.import_key(public_key_b64)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return base64.b64encode(ciphertext).decode()
def encrypt_para(plaintext):
public_key = RSA.import_key(public_key_data)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return ciphertext.hex()
def encode_phone(text):
encoded_chars = []
for char in text:
encoded_chars.append(chr(ord(char) + 2))
return ''.join(encoded_chars)
def ophone(t):
key = b'34d7cb0bcdf07523'
utf8_key = key.decode('utf-8')
utf8_t = t.encode('utf-8')
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = cipher.encrypt(pad(utf8_t, AES.block_size))
return ciphertext.hex()
def send(uid,content):
r = requests.post('https://wxpusher.zjiecode.com/api/send/message',json={"appToken":appToken,"content":content,"contentType":1,"uids":[uid]}).json()
return r
def userLoginNormal(phone,password):
alphabet = 'abcdef0123456789'
uuid = [''.join(random.sample(alphabet, 8)),''.join(random.sample(alphabet, 4)),'4'+''.join(random.sample(alphabet, 3)),''.join(random.sample(alphabet, 4)),''.join(random.sample(alphabet, 12))]
timestamp=datetime.datetime.now().strftime("%Y%m%d%H%M%S")
loginAuthCipherAsymmertric = 'iPhone 14 15.4.' + uuid[0] + uuid[1] + phone + timestamp + password[:6] + '0$$$0.'
login_date = {
"headerInfos": {
"code": "userLoginNormal",
"timestamp": timestamp,
"broadAccount": "",
"broadToken": "",
"clientType": "#10.5.0#channel50#iPhone 14 Pro Max#",
"shopId": "20002",
"source": "110003",
"sourcePassword": "Sid98s",
"token": "",
"userLoginName": encode_phone(phone)
},
"content": {
"attach": "test",
"fieldData": {
"loginType": "4",
"accountType": "",
"loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric),
"deviceUid": uuid[0] + uuid[1] + uuid[2],
"phoneNum": encode_phone(phone),
"isChinatelecom": "0",
"systemVersion": "15.4.0",
"authentication": encode_phone(password)
}
}
}
r = ss.post('https://appgologin.189.cn:9031/login/client/userLoginNormal', json=login_date).json()
l = r['responseData']['data']['loginSuccessResult']
if l:
load_token[phone] = l
with open(load_token_file, 'w') as f:
json.dump(load_token, f)
ticket = get_ticket(phone,l['userId'],l['token'])
return ticket
return False
def get_ticket(phone,userId,token):
r = ss.post('https://appgologin.189.cn:9031/map/clientXML',data='<Request><HeaderInfos><Code>getSingle</Code><Timestamp>'+datetime.datetime.now().strftime("%Y%m%d%H%M%S")+'</Timestamp><BroadAccount></BroadAccount><BroadToken></BroadToken><ClientType>#9.6.1#channel50#iPhone 14 Pro Max#</ClientType><ShopId>20002</ShopId><Source>110003</Source><SourcePassword>Sid98s</SourcePassword><Token>'+token+'</Token><UserLoginName>'+phone+'</UserLoginName></HeaderInfos><Content><Attach>test</Attach><FieldData><TargetId>'+encrypt(userId)+'</TargetId><Url>4a6862274835b451</Url></FieldData></Content></Request>',headers={'user-agent': 'CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1'})
#printn(phone, '获取ticket', re.findall('<Reason>(.*?)</Reason>',r.text)[0])
tk = re.findall('<Ticket>(.*?)</Ticket>',r.text)
if len(tk) == 0:
return False
return decrypt(tk[0])
def queryInfo(phone,s):
global rs
a = 1
while a < 2:
if rs:
bd = js.call('main').split('=')
ck[bd[0]] = bd[1]
r = s.get('https://wapact.189.cn:9001/gateway/golden/api/queryInfo',cookies=ck).json()
try:
printn(f'{phone} 金豆余额 {r["biz"]["amountTotal"]}')
amountTotal= r["biz"]["amountTotal"]
except:
amountTotal = 0
if amountTotal< 3000:
if rs == 1:
bd = js.call('main').split('=')
ck [bd[0]] = bd[1]
res = s.post('http://wapact.189.cn:9000/gateway/stand/detail/exchange',json={"activityId":jdaid},cookies=ck).text
printn(res)
if '$_ts=window' in res:
first_request()
rs = 1
time.sleep(3)
else:
return r
a += 1
return r
def exchange(phone,s,title,aid, uid):
try:
bd = js.call('main').split('=')
ck [bd[0]] = bd[1]
r = s.post('https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange',json={"activityId":aid},cookies=ck)
printn(f"响应码: {r.status_code}")
if '$_ts=window' in r.text:
first_request(r.text)
return
r = r.json()
if r["code"] == 0:
if r["biz"] != {} and r["biz"]["resultCode"] in errcode:
#printn(str(datetime.datetime.now())[11:22], phone, title,errcode[r["biz"]["resultCode"]])
printn(f'{str(datetime.datetime.now())[11:22]} {phone} {title} {errcode[r["biz"]["resultCode"]]}')
if r["biz"]["resultCode"] in ["0","412"]:
if r["biz"]["resultCode"] == "0":
msg = phone+":"+title+"兑换成功"
send(uid, msg)
if phone not in dhjl[yf][title]:
dhjl[yf][title] += "#"+phone
with open('电信金豆换话费.log', 'w') as f:
json.dump(dhjl, f, ensure_ascii=False)
else:
#printn(str(datetime.datetime.now())[11:22], phone, r["message"])
printn(f'{str(datetime.datetime.now())[11:22]} {phone} {r}')
except Exception as e:
#print(e)
pass
def dh(phone,s,title,aid,wt, uid):
while wt > time.time():
pass
printn(f"{str(datetime.datetime.now())[11:22]} {phone} {title} 开始兑换")
if rs:
bd = js.call('main').split('=')
ck [bd[0]] = bd[1]
for cs in range(cfcs):
threading.Thread(target=exchange,args=(phone,s,title,aid, uid)).start()
#time.sleep(5)
def lottery(s):
for cishu in range(3):
try:
if rs:
bd = js.call('main').split('=')
ck [bd[0]] = bd[1]
else:
cookie = {}
r = s.post('https://wapact.189.cn:9001/gateway/golden/api/lottery',json={"activityId":"6384b49b1e44396da4f1e4a3"},cookies=ck)
except:
pass
time.sleep(3)
def aes_ecb_encrypt(plaintext, key):
key = key.encode('utf-8')
if len(key) not in [16, 24, 32]:
raise ValueError("密钥长度必须为16/24/32字节")
# 对明文进行PKCS7填充
padded_data = pad(plaintext.encode('utf-8'), AES.block_size)
#padded_data = plaintext.encode('utf-8')
# 创建AES ECB加密器
cipher = AES.new(key, AES.MODE_ECB)
# 加密并返回Base64编码结果
ciphertext = cipher.encrypt(padded_data)
return base64.b64encode(ciphertext).decode('utf-8')
def ks(phone, ticket, uid):
global wt
wxp[phone] = uid
s = requests.session()
s.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","Referer":"https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"}
s.cookies.set_policy(BlockAll())
s.mount('https://', DESAdapter())
s.timeout = 30
if rs:
bd = js.call('main').split('=')
ck [bd[0]] = bd[1]
data = aes_ecb_encrypt(json.dumps({"ticket":ticket,"backUrl":"https%3A%2F%2Fwapact.189.cn%3A9001","platformCode":"P201010301","loginType":2}), 'telecom_wap_2018')
login = ss.post('https://wapact.189.cn:9001/unified/user/login',data=data, headers={"Content-Type":"application/json;charset=UTF-8","Accept":"application/json, text/javascript, */*; q=0.01"}, cookies=ck).json()
# login = s.post('https://wapact.189.cn:9001/unified/user/login',json={"ticket":ticket,"backUrl":"https%3A%2F%2Fwapact.189.cn%3A9001","platformCode":"P201010301","loginType":2}, cookies=ck).json()
if login['code'] == 0:
printn(phone+" 获取token成功")
s.headers["Authorization"] = "Bearer " + login["biz"]["token"]
queryInfo(phone,s)
if rs:
bd = js.call('main').split('=')
ck [bd[0]] = bd[1]
queryBigDataAppGetOrInfo = s.get('https://waphub.189.cn/gateway/golden/goldGoods/getGoodsList??floorType=0&userType=1&page&1&order=3&tabOrder=',cookies=ck).json()
for i in queryBigDataAppGetOrInfo["biz"]["ExchangeGoodslist"]:
if '话费' not in i["title"]:continue
if '0.5元' in i["title"] or '5元' in i["title"]:
jp["9"][i["title"]] = i["id"]
elif '1元' in i["title"] or '10元' in i["title"]:
jp["13"][i["title"]] = i["id"]
else:
jp["12"][i["title"]] = i["id"]
h = datetime.datetime.now().hour
if 11 > h > 1:
h = 9
elif 23 > h > 1:
h = 13
else:
h = 23
if len(sys.argv) ==2:
h = int(sys.argv[1])
#h=23
d = jp[str(h)]
wt = t(h) + kswt
if jp["12"] != {}:
d.update(jp["12"])
wt = 0
for di in d:
#if '5' in di:
if di not in dhjl[yf]:
dhjl[yf][di] = ""
if phone in dhjl[yf][di] :
printn(f"{phone} {di} 已兑换")
else:
printn(f"{phone} {di}")
if wt - time.time() > 20 * 60:
print("等待时间超过20分钟")
return
threading.Thread(target=dh,args=(phone,s,di,d[di],wt, uid)).start()
else:
printn(f"{phone} 获取token {login['message']}")
def first_request(res=''):
global js, fw
url = 'https://wapact.189.cn:9001/gateway/stand/detail/exchange'
if res == '':
response = ss.get(url)
res = response.text
soup = BeautifulSoup(res, 'html.parser')
scripts = soup.find_all('script')
for script in scripts:
if 'src' in str(script):
rsurl = re.findall('src="([^"]+)"', str(script))[0]
if '$_ts=window' in script.get_text():
ts_code = script.get_text()
urls = url.split('/')
rsurl = urls[0] + '//' + urls[2] + rsurl
#print(rsurl)
ts_code += ss.get(rsurl).text
content_code = soup.find_all('meta')[1].get('content')
with open("瑞数通杀.js") as f:
js_code_ym = f.read()
js_code = js_code_ym.replace('content_code', content_code).replace("'ts_code'", ts_code)
js = execjs.compile(js_code)
for cookie in ss.cookies:
ck[cookie.name] = cookie.value
return content_code, ts_code, ck
def main():
print()
global wt,rs
r = ss.get('https://wapact.189.cn:9001/gateway/stand/detailNew/exchange')
if '$_ts=window' in r.text:
rs = 1
print("瑞数加密已开启")
first_request()
else:
print("瑞数加密已关闭")
rs = 0
if os.environ.get('chinaTelecomAccount')!= None:
chinaTelecomAccount = os.environ.get('chinaTelecomAccount')
else:
chinaTelecomAccount = jdhf
for i in chinaTelecomAccount.split('&'):
i = i.split('#')
phone = i[0]
password = i[1]
uid = i[-1]
ticket = False
if phone in load_token:
printn(f'{phone} 使用缓存登录')
ticket = get_ticket(phone,load_token[phone]['userId'],load_token[phone]['token'])
if ticket == False:
printn(f'{phone} 使用密码登录')
ticket = userLoginNormal(phone,password)
if ticket:
threading.Thread(target=ks,args=(phone, ticket, uid)).start()
time.sleep(1)
else:
printn(f'{phone} 登录失败')
#手机号@密码@wxpusheruid
jdhf = ""
#重发次数
cfcs = 15
#wxpusher推送appToken
appToken = ""
jdaid = '60dd79533dc03d3c76bdde30'
ck = {}
load_token_file = 'chinaTelecom_cache.json'
try:
with open(load_token_file, 'r') as f:
load_token = json.load(f)
except:
load_token = {}
main()

View File

@@ -0,0 +1,164 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/web/sudojia_juejin.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/web/sudojia_juejin.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/web/sudojia_juejin.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: 7251342054b8f13aaaca34394af2829506de2ae87455cf13251f68775d831fef
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* 稀土掘金 https://juejin.cn/
*
* 仅每日签到(不维护了)
* 获取 Cookie、只要 sessionid 的值和手动签到之后抓取 https://api.juejin.cn/growth_api/v1/check_in 的 url 拼接的 uuid=123456&spider=0&msToken=xxxxxx&a_bogus=xxxxxx 用 # 分开
* 填写示例:
* export JUEJIN_COOKIE = 'sessionid#uuid=123456&spider=0&msToken=xxxxxx&a_bogus=xxxxxx'
* 多账号用换行,不要用 &
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2022/01/19
* @lastModify 2024/08/16
*
* const $ = new Env('稀土掘金')
* cron: 5 10 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('稀土掘金');
const jueJinList = process.env.JUEJIN_COOKIE ? process.env.JUEJIN_COOKIE.split(/\n/) : [];
let message = '';
// 接口地址
const baseUrl = 'https://api.juejin.cn';
// 请求头
const headers = {
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br, zstd',
"Content-type": "application/json",
'Referer': 'https://juejin.cn/',
'Origin': 'https://juejin.cn',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
};
!(async () => {
await checkUpdate($.name, jueJinList);
// console.log(`\n已随机分配 User-Agent\n\n${headers['user-agent'] || headers['User-Agent']}`);
for (let i = 0; i < jueJinList.length; i++) {
const [juejinCookie, urlList] = jueJinList[i].split('#');
headers.Cookie = `sid_tt=${juejinCookie}; sessionid=${juejinCookie}; sessionid_ss=${juejinCookie}`;
const index = i + 1;
console.log(`\n*****第[${index}]个${$.name}账号*****`);
if (await checkStatus()) {
console.error('Cookie 已失效');
await notify.sendNotify(`「Cookie失效通知」`, `${$.name}账号[${index}] Cookie 已失效,请重新登录获取 Cookie\n\n`);
continue;
}
message += `📣====${$.name}账号[${index}]====📣\n`;
await $.wait(sudojia.getRandomWait(800, 1200));
await main(urlList);
await $.wait(sudojia.getRandomWait(2000, 2500));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
/**
* 主函数
*
* @returns {Promise<void>}
*/
async function main(urlList) {
await getUserName();
await $.wait(sudojia.getRandomWait(2300, 2700));
await checkIn(urlList);
await $.wait(sudojia.getRandomWait(3000, 3500));
await getOreNum(urlList);
await $.wait(sudojia.getRandomWait(3000, 3500));
await getCount();
}
/**
* 获取用户信息
*/
async function getUserName() {
try {
const data = await sudojia.sendRequest(baseUrl + '/user_api/v1/user/get_info_pack?aid=2608', 'post', headers, {
"pack_req": {
"user_counter": true,
"user_growth_info": true,
"user": true
}
});
// 用户昵称
const userName = data.data.user_basic.user_name;
message += `【账号昵称】${userName}\n`;
console.log(`【账号昵称】${userName}`);
} catch (e) {
console.error(`获取用户信息发生异常: ${e.response.data}`);
}
}
/**
* 检查状态
*
* @return {Promise<*>}
*/
async function checkStatus() {
const data = await sudojia.sendRequest(baseUrl + '/growth_api/v1/get_today_status', 'get', headers);
return 403 === data.err_no;
}
/**
* 签到函数
*
* @returns {*}
*/
async function checkIn(urlList) {
try {
// uuid=7402961076386793000&spider=0&msToken=6N7P3ETmcpkVBSBdIEAoOvIE5TlEhnAmt382dbZpa1tNLnKhYR8QkGIKTJINouJxXGwc-JkvcwmUPhinCBGBtXg7ZsNn5LZzJtOpR4PSuRejD4spLQYUJ3tJdEurDng%3D&a_bogus=mX-QkcZ8Msm1Zhvtkhkz9GWEeOm0YWRkgZENqN9HUUo7
const data = await sudojia.sendRequest(baseUrl + `/growth_api/v1/check_in?aid=2608&${urlList}`, 'post', headers);
if (15001 === data.err_no) {
console.log(data.err_msg);
message += `【签到信息】${data.err_msg}\n`
return;
}
console.log(`签到成功,获得 ${data.data.incr_point} 矿石`);
message += `【签到信息】签到成功, 获得 ${data.data.incr_point} 矿石\n`
} catch (e) {
console.error(`签到时发生异常: ${e.response.data}`);
}
}
/**
* 获取总账号矿石数
*/
async function getOreNum(urlList) {
const data = await sudojia.sendRequest(baseUrl + `/growth_api/v1/get_cur_point?aid=2608&${urlList}`, 'get', headers);
console.log(`当前矿石数:${data.data}`);
message += `【总矿石数】${data.data} 矿石\n`
}
/**
* 查询免费抽奖次数
*/
async function queryFreeLuckyDrawCount(urlList) {
try {
const data = await sudojia.sendRequest(baseUrl + `/growth_api/v1/lottery_config/get?aid=2608&${urlList}`, 'get', headers);
// 获取免费抽奖次数
return data.data.free_count;
} catch (e) {
console.error(`查询免费抽奖次数时发生异常: ${e.response.data}`);
return 0;
}
}
/**
* 统计签到天数, 没什么用~
*/
async function getCount() {
const data = await sudojia.sendRequest(baseUrl + '/growth_api/v1/get_counts?aid=2608', 'get', headers);
console.log(`已连续签到${data.data.cont_count}天、累计签到${data.data.sum_count}`);
message += `【签到统计】已连续签到${data.data.cont_count}天、累计签到${data.data.sum_count}\n`
}

View File

@@ -0,0 +1,85 @@
# Source: https://gitee.com/yangro/ql/blob/main/jylt.py
# Raw: https://gitee.com/yangro/ql/raw/main/jylt.py
# Repo: yangro/ql
# Path: jylt.py
# UploadedAt: 2023-10-25T14:45:53+08:00
# SHA256: 48cbf2c964d538f8d9d2cb09d9cd35ee691e4d7dad7e962c8f18e2c2ae7d7bf4
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
# coding=utf-8
"""
每日7:25
cron: 0 25 7 * * ?
new Env("精易论坛")
"""
import urllib
from urllib import parse
import requests
import notify
import time
import re
import random
import utils.tool as TOOL
import utils.getCookie as getCookie
global msg
msg = """
名称|累计|本月|总获得|总精币|状态
:--:|:--:|:--:|:--:|:--:|:--:
"""
def main():
users = getCookie.GetQlEnvs().getCookies('JYLT_COOKIE')
print("🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉\n")
print("获取到: " + str(len(users)) + " 个用户")
print("-------------------------------------------")
for user in users:
signIn(user)
# 签到
def signIn(user):
global msg
url = "https://bbs.125.la/plugin.php?id=dsu_paulsign:sign"
data = 'formhash=926371b6&submit=1&operation=qiandao&qdxq=kx&ajax=1&infloat=0'
headers = {
"Host": "bbs.125.la",
"accept": "*/*",
"origin": "//bbs.125.la",
"x-requested-with": "XMLHttpRequest",
"user-agent": "Mozilla/5.0 (Linux; U; Android 11; zh-cn; M2011K2C Build/RKQ1.200826.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/79.0.3945.147 Mobile Safari/537.36 XiaoMi/MiuiBrowser/14.3.21",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"sec-fetch-site": "same-origin",
"accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
"cookie": "lDlk_ecc9_saltkey=gypyB1q2;lDlk_ecc9_lastvisit=1671591615;lDlk_ecc9_con_request_uri=http%3A%2F%2Fbbs.125.la%2Fconnect.php%3Fmod%3Dlogin%26op%3Dcallback%26referer%3Dindex.php;lDlk_ecc9_client_token=AB463AA7680A8BC46D64C58FC637960E;lDlk_ecc9_connect_is_bind=1;lDlk_ecc9_connect_uin=AB463AA7680A8BC46D64C58FC637960E;lDlk_ecc9_nofavfid=1;lDlk_ecc9_lastcheckfeed=662770%7C1672326032;__ancc_token=eDy0p0n5DsQMBJ8B4yxj2Q==;lDlk_ecc9_seccode=507.0542e4feff0318d6c5;lDlk_ecc9_client_created=1673829175;lDlk_ecc9_auth=ef18YFNYII0asASPE2u3U3ONRNbDuqTWo7sjRti9VkzdZlSFHETzOce8M877vlXg;lDlk_ecc9_connect_login=1;lDlk_ecc9_st_p=662770%7C1673829595%7Cdaec851af652b5d3c0199aabc791c7b5;lDlk_ecc9_visitedfid=202D81D168D147D51D206D178D98D27D100;lDlk_ecc9_viewid=tid_13957193;lDlk_ecc9_sid=CkKWXF;lDlk_ecc9_lip=117.163.248.13%2C1673870449;lDlk_ecc9_ulastactivity=d7e0Jr%2B9TDmtxrJE2j8MVjtkAPIeX18rnTbBp4ZnRjSeb8U5qjDz;lDlk_ecc9_home_diymode=1;lDlk_ecc9_lastact=1673948276%09plugin.php%09"
}
res = requests.post(url=url, data=data, headers=headers)
try:
json = res.json()
if (json['status'] == 1):
# seccess
print(user['name'] + " ---> " + "签到成功" + "\n")
msg += user['name'] + "|" + str(json['data']['days']) + "|" + str(json['data']['modays']) + "|" + str(
json['data']['reward']) + "|5000|" + "seccess" + "\n\n"
else:
# err
print(user['name'] + " ---> " + str(json['msg']) + "\n")
msg += user['name'] + "|||||" + str(json['msg']) + "\n\n"
except Exception as e:
print(user['name'] + " ---> " + "json err" + "\n")
msg += user['name'] + "|||||" + "json err" + "\n\n"
print("-------------------------------------------\n")
main()
print("🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉")
notify.send("精易论坛", msg)

View File

@@ -0,0 +1,87 @@
# Source: https://github.com/xfmeng970526/ql/blob/main/alypqd.py
# Raw: https://raw.githubusercontent.com/xfmeng970526/ql/main/alypqd.py
# Repo: xfmeng970526/ql
# Path: alypqd.py
# UploadedAt: 2023-09-20T12:13:28+08:00
# SHA256: cc872d595fe25f177c8ab54389fe8fd68d4405340c15dd0557e07914985d486c
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
#!/usr/bin/python3
# -- coding: utf-8 --
# @Time : 2023/4/8 10:23
# -------------------------------
# cron "30 5 * * *" script-path=xxx.py,tag=匹配cron用
# const $ = new Env('阿里云盘签到');
# cron: 25 2,21 * * *
# new Env('126-阿里云盘签到');
import json
import requests
import os
##变量export ali_refresh_token=''
ali_refresh_token=os.getenv("ali_refresh_token").split('&')
#refresh_token是一成不变的呢我们使用它来更新签到需要的access_token
# ali_refresh_token = os.getenv("ali_refresh_token")
# 推送加
plustoken = os.getenv("plustoken")
#推送函数
def Push(contents):
# 推送加
headers = {'Content-Type': 'application/json'}
json = {"token": plustoken, 'title': 'aliyun签到', 'content': contents.replace('\n', '<br>'), "template": "json"}
resp = requests.post(f'http://www.pushplus.plus/send', json=json, headers=headers).json()
print('push+推送成功' if resp['code'] == 200 else 'push+推送失败')
#签到函数
for i in range(len(ali_refresh_token)):
print(f'开始帐号{i+1}签到')
def daily_check(access_token):
url = 'https://member.aliyundrive.com/v1/activity/sign_in_list'
headers = {
'Authorization': access_token
}
response = requests.post(url=url, headers=headers, json={}).text
result = json.loads(response)
if 'success' in result:
print('签到成功')
for i, j in enumerate(result['result']['signInLogs']):
if j['status'] == 'miss':
day_json = result['result']['signInLogs'][i-1]
# print(day_json)
if not day_json['isReward']:
contents = '签到成功,今日未获得奖励'
else:
contents = '本月累计签到{}天,今日签到获得{}{}'.format(result['result']['signInCount'],
day_json['reward']['name'],
day_json['reward']['description'])
print(contents)
return contents
# 使用refresh_token更新access_token
def update_token(refresh_token):
url = 'https://auth.aliyundrive.com/v2/account/token'
data = {
'grant_type': 'refresh_token',
'refresh_token': ali_refresh_token[i]
}
response = requests.post(url=url, json=data).json()
access_token = response['access_token']
# print('获取的access_token为{}'.format(access_token))
return access_token
def mian():
# print('更新access_token')
access_token = update_token(ali_refresh_token)
# print('更新成功,开始进行签到')
content = daily_check(access_token)
if plustoken != '':
Push(content)
if __name__ == '__main__':
mian()

View File

@@ -0,0 +1,195 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/web/sudojia_fnnas.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/web/sudojia_fnnas.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/web/sudojia_fnnas.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: 5d80925231190e241d959facb5f7ae099c4bb2122c415e04975ba821f3c30271
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* 飞牛私有云
*
* 官网https://club.fnnas.com
* 获取 Cookie格式pvRK_2132_auth=46exxxxxxxx; pvRK_2132_saltkey=F3xxxxx
* export FN_NAS_COOKIE = 'pvRK_2132_auth=46exxxxxxxx; pvRK_2132_saltkey=F3xxxxx'
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2024/09/20
*
* const $ = new Env('飞牛私有云')
* cron: 10 0 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('飞牛私有云');
const cheerio = require("cheerio");
const fnNasList = process.env.FN_NAS_COOKIE ? process.env.FN_NAS_COOKIE.split(/[\n&]/) : [];
// 消息推送
let message = '';
// 获取配置信息
let formHash, signLink, uid;
// 接口地址
const baseUrl = 'https://club.fnnas.com'
// 请求头
const headers = {
'User-Agent': sudojia.getRandomUserAgent('PC'),
'Accept-Encoding': 'gzip, deflate, br, zstd',
};
!(async () => {
await checkUpdate($.name, fnNasList);
console.log(`\n已随机分配 User-Agent\n\n${headers['user-agent'] || headers['User-Agent']}`);
for (let i = 0; i < fnNasList.length; i++) {
const index = i + 1;
headers.Cookie = fnNasList[i];
console.log(`\n*****第[${index}]个${$.name}账号*****`);
message += `📣====${$.name}账号[${index}]====📣\n`;
await main();
await $.wait(sudojia.getRandomWait(2000, 2500));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
async function main() {
await getUidAndUserName();
await $.wait(sudojia.getRandomWait(800, 1200));
await follow();
await $.wait(sudojia.getRandomWait(1200, 1800));
await checkIn();
await $.wait(sudojia.getRandomWait(1200, 1800));
await getCount();
await $.wait(sudojia.getRandomWait(1200, 1800));
await getPoints();
}
/**
* 获取重要信息
*
* @returns {Promise<void>}
*/
async function getUidAndUserName() {
try {
const data = await sudojia.sendRequest(`${baseUrl}`, 'get', headers);
const $ = cheerio.load(data);
uid = $('a', '.icon_msg').attr('href').match(/uid=(\d+)/)[1];
const userName = $('.quater_phone_nav .z').text().trim();
console.log(`${userName}(${uid})`);
// 拿到 formhash 和签到地址
const logoutLink = $('li.l4 a').attr('href');
formHash = logoutLink.split('formhash=')[1];
signLink = $('a[href*="plugin.php?id=zqlj_sign"]').attr('href');
message += `${userName}(${uid})\n`;
} catch (e) {
console.error('获取重要信息时发生异常:', e);
}
}
/**
* 签到
*
* @returns {Promise<void>}
*/
async function checkIn() {
try {
let data = await sudojia.sendRequest(`${baseUrl}/${signLink}`, 'get', headers);
if (!data.includes('点击打卡')) {
console.log('今日已打卡');
return;
}
await $.wait(sudojia.getRandomWait(800, 1200));
data = await sudojia.sendRequest(`${baseUrl}/${signLink}&sign=${formHash}`, 'get', headers);
console.log('打卡成功!');
message += `打卡成功\n`;
} catch (e) {
console.error('签到时发生异常:', e);
}
}
/**
* 统计信息
*
* @returns {Promise<void>}
*/
async function getCount() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/${signLink}`, 'get', headers);
const $ = cheerio.load(data);
const items = {};
// 使用选择器提取信息
$('.xl li').each((index, element) => {
const text = $(element).text().trim();
switch (text.substring(0, 4)) {
case '最近打卡':
items['zjdk'] = text.substring(5).trim();
break;
case '本月打卡':
items['bydk'] = text.substring(5).trim();
break;
case '连续打卡':
items['lxdk'] = text.substring(5).trim();
break;
case '累计打卡':
items['ljdk'] = text.substring(5).trim();
break;
case '累计奖励':
items['ljjl'] = text.substring(5).trim();
break;
case '最近奖励':
items['zjjl'] = text.substring(5).trim();
break;
case '当前打卡':
items['currenDkLevel'] = text.substring(7).trim();
break;
}
});
console.log(`最近打卡:${items.zjdk}\n本月打卡:${items.bydk}\n连续打卡:${items.lxdk}\n累计打卡:${items.ljdk}\n累计奖励:${items.ljjl}\n最近奖励:${items.zjjl}\n当前打卡等级:${items.currenDkLevel}`);
message += `最近打卡:${items.zjdk}\n本月打卡:${items.bydk}\n连续打卡:${items.lxdk}\n累计打卡:${items.ljdk}\n累计奖励:${items.ljjl}\n最近奖励:${items.zjjl}\n当前打卡等级:${items.currenDkLevel}\n`;
} catch (e) {
console.error('获取统计信息时发生异常:', e);
}
}
/**
* 获取个人信息
*
* @returns {Promise<void>}
*/
async function getPoints() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/home.php?mod=space&uid=${uid}&do=profile&from=space`, 'get', headers);
const $ = cheerio.load(data);
const ulElement = $('.pf_l');
const item = {};
ulElement.find('li').each((index, element) => {
const label = $(element).find('em').text().trim();
const value = $(element).text().replace(label, '').trim();
switch (label) {
case '积分':
item.points = parseInt(value);
break;
case '牛值':
item.bullValue = parseInt(value);
break;
case '飞牛币':
item.flyingBullCoins = parseInt(value);
break;
case '登陆天数':
item.loginDays = parseInt(value);
break;
}
});
console.log(`当前积分:${item.points}\n当前牛值:${item.bullValue}\n当前飞牛币:${item.flyingBullCoins}\n当前登录天数:${item.loginDays}`);
message += `当前积分:${item.points}\n当前牛值:${item.bullValue}\n当前飞牛币:${item.flyingBullCoins}\n当前登录天数:${item.loginDays}\n\n`;
} catch (e) {
console.error('获取个人信息时发生异常:', e);
}
}
async function follow() {
const data = await sudojia.sendRequest(`${baseUrl}/home.php?mod=spacecp&ac=follow&op=add&hash=${formHash}&fuid=6441&infloat=yes&handlekey=followmod&inajax=1&ajaxtarget=fwin_content_followmod`, 'get', headers);
}

View File

@@ -0,0 +1,361 @@
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/client/sudojia_bananaVideo.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/client/sudojia_bananaVideo.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/client/sudojia_bananaVideo.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: 1a8fb3222c27ae2783be5e0562b3110bdb4f4d984f503c7f8b3c48d7ef588dfc
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/**
* 香蕉视频 APP
*
* 扫码下载https://pic.rmb.bdstatic.com/bjh/240914/dc8411e749492d270032b5278c5abd321993.png
* 开发不易,走个邀请码呗,感谢!!!
* 邀请码IOWDUC
* 每日签到及任务获得金币, 金币可提现或在棋牌处单车变摩托, 10 金币 = 1元, 保底每日 6 金币
* 手机号#密码
* export BANANA_ACCOUNT = '18888888888#123456'
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2024/09/14
*
* const $ = new Env('香蕉视频')
* cron: 10 1 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('香蕉视频');
const bananaList = process.env.BANANA_ACCOUNT ? process.env.BANANA_ACCOUNT.split(/[\n&]/) : [];
// 消息推送
let message = '';
// 接口地址
const baseUrl = 'https://mgcrjh.ipajx0.cc'
// 收藏列表数组
let favoriteList = [];
// 请求头
const headers = {
"x-system": "Android",
"x-channel": "xj1",
"x-version": "5.0.5",
'User-Agent': sudojia.getRandomUserAgent('H5'),
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
};
!(async () => {
await checkUpdate($.name, bananaList);
console.log(`\n已随机分配 User-Agent\n\n${headers['user-agent'] || headers['User-Agent']}`);
for (let i = 0; i < bananaList.length; i++) {
const index = i + 1;
const [phone, pwd] = bananaList[i].split('#');
console.log(`\n*****第[${index}]个${$.name}账号*****`);
message += `📣====${$.name}账号[${index}]====📣\n`;
await main(phone, pwd);
await $.wait(sudojia.getRandomWait(2000, 2500));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
async function main(phone, pwd) {
// 登录
await login(phone, pwd);
await $.wait(sudojia.getRandomWait(1500, 2000));
// 获取用户信息
await getUserInfo();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 签到
await sign();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 添加收藏
await addFavorite();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 获取收藏列表并删除收藏
await getFavoriteList();
await $.wait(sudojia.getRandomWait(800, 1200));
await removeFavorite();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 点击广告任务
await adViewClick();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 下载长视频任务
await downLoadVideoTask();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 观看影片任务
await watchVideo();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 保存二维码任务
await qrcodeSave();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 发布评论任务
await postComment();
await $.wait(sudojia.getRandomWait(1500, 2000));
// 获取金币
await getPoints();
}
/**
* 登录
*
* @return {Promise<void>}
*/
async function login(phone, pwd) {
try {
const data = await sudojia.sendRequest(`${baseUrl}/login`, 'post', headers, `logintype=0&mobiprefix=86&mobi=${phone}&password=${pwd}`);
if (0 !== data.retcode) {
return console.error(data.errmsg);
}
headers['X-Cookie-Auth'] = data.data.xxx_api_auth;
console.log(`登录成功~`);
} catch (e) {
console.error(`获取用户信息时发生异常:${e}`);
}
}
/**
* 获取用户信息
*
* @returns {Promise<void>}
*/
async function getUserInfo() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/ucp/index`, 'get', headers);
if (0 !== data.retcode) {
return console.error(data.errmsg);
}
console.log(`昵称:${data.data.user.username}`);
message += `昵称:${data.data.user.username}\n`;
} catch (e) {
console.error(`获取用户信息时发生异常:${e}`);
}
}
/**
* 签到
*
* @returns {Promise<void>}
*/
async function sign() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/ucp/task/sign`, 'post', headers);
if (0 !== data.retcode) {
message += `${data.errmsg}\n`;
return console.error(data.errmsg);
}
console.log(`签到成功,金币+${data.data.taskdone}`);
message += `签到成功\n`;
} catch (e) {
console.error(`签到时发生异常:${e}`);
}
}
/**
* 视频收藏
*
* @returns {Promise<void>}
*/
async function addFavorite() {
// 每次收藏的最大尝试次数
const maxAttempts = 5;
for (let i = 0; i < 5; i++) {
let attempt = 0;
while (attempt < maxAttempts) {
try {
const data = await sudojia.sendRequest(`${baseUrl}/favorite/add`, 'post', headers, `vodid=${sudojia.getRandomWait(1, 66000)}`);
if (data.retcode === 0) {
console.log(`${i + 1} 次收藏视频成功!`);
await $.wait(sudojia.getRandomWait(1500, 2300));
break;
} else if (data.retcode === -1) {
console.log(`${i + 1} 次收藏视频失败(已收藏),重新尝试...`);
attempt++;
await $.wait(sudojia.getRandomWait(1500, 2300));
} else {
console.error(`${i + 1} 次收藏视频失败,错误代码:${data.retcode},错误信息:${data.errmsg}`);
return;
}
} catch (e) {
console.error(`收藏视频时发生异常:${e}`);
}
}
if (attempt === maxAttempts) {
console.error(`收藏视频达到最大尝试次数,收藏任务未成功`);
return;
}
}
}
/**
* 获取收藏列表
*
* @returns {Promise<void>}
*/
async function getFavoriteList() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/favorite/listing`, 'get', headers);
if (0 !== data.retcode) {
return console.error(`获取收藏列表失败:${data.errmsg}`);
}
for (const item of data.data.rows) {
favoriteList.push(item.vodid);
}
console.log(`已获取收藏列表,开始删除收藏...`);
} catch (e) {
console.error(`获取收藏列表时发生异常:${e}`);
}
}
/**
* 删除收藏列表
*
* @returns {Promise<void>}
*/
async function removeFavorite() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/favorite/remove`, 'post', headers, `vodids=${favoriteList}`);
if (0 !== data.retcode) {
return console.error(`删除收藏视频失败:${data.errmsg}`);
}
console.log(`${data.errmsg}`);
} catch (e) {
console.error(`删除收藏视频时发生异常:${e}`);
}
}
/**
* 点击广告任务
*
* @returns {Promise<void>}
*/
async function adViewClick() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/ucp/task/adviewClick`, 'get', headers);
if (0 !== data.retcode) {
return console.error(`点击广告失败:${data.errmsg}`);
}
console.log(`点击广告成功,金币+${data.data.taskdone}`);
} catch (e) {
console.error(`点击广告时发生异常:${e}`);
}
}
/**
* 长视频下载任务
*
* @returns {Promise<void>}
*/
async function downLoadVideoTask() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/vod/reqdown/${sudojia.getRandomWait(1, 66000)}`, 'get', headers);
if (0 !== data.retcode) {
if (3 === data.retcode) {
await $.wait(sudojia.getRandomWait(800, 1200));
return await downLoadVideoTask();
}
console.error(`下载长视频失败:${data.errmsg}`);
return;
}
if (!data.data.taskdone) {
return console.error(`下载长视频任务已完成`);
}
console.log(`下载长视频任务成功,金币+${data.data.taskdone}`);
} catch (e) {
console.error(`下载长视频任务时发生异常:${e}`);
}
}
/**
* 观看影片任务
*
* @returns {Promise<void>}
*/
async function watchVideo() {
try {
let watched = 0;
while (watched < 10) {
const data = await sudojia.sendRequest(`${baseUrl}/v2/vod/reqplay/${sudojia.getRandomWait(1, 66000)}`, 'get', headers);
if (0 !== data.retcode) {
console.error(`观看影片任务失败:${data.errmsg}`);
await $.wait(sudojia.getRandomWait(800, 1200));
continue;
}
watched++;
console.log(`已观看影片数量:${watched}`);
await $.wait(sudojia.getRandomWait(1500, 2300));
}
} catch (e) {
console.error(`观看影片时发生异常:${e}`);
}
}
/**
* 保存二维码任务
*
* @returns {Promise<void>}
*/
async function qrcodeSave() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/ucp/task/qrcodeSave`, 'get', headers);
if (0 !== data.retcode) {
return console.error(`保存二维码任务失败:${data.errmsg}`);
}
console.log(`保存二维码任务成功,金币+${data.data.taskdone}`);
} catch (e) {
console.error(`保存二维码任务时发生异常:${e}`);
}
}
/**
* 发布评论任务
*
* @returns {Promise<*|undefined>}
*/
async function postComment() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/comment/post`, 'post', headers, `vodid=${sudojia.getRandomWait(1, 66000)}&content=好`);
if (0 !== data.retcode) {
if (3 === data.retcode) {
await $.wait(sudojia.getRandomWait(800, 1200));
return await postComment();
}
console.error(`发布评论失败:${data.errmsg}`);
return
}
console.log(data.errmsg);
} catch (e) {
console.error(`发布评论时发生异常:${e}`);
}
}
/**
* 获取金币
*
* @returns {Promise<void>}
*/
async function getPoints() {
try {
const data = await sudojia.sendRequest(`${baseUrl}/ucp/index`, 'get', headers);
if (0 !== data.retcode) {
return console.error(data.errmsg);
}
console.log(`当前金币:${data.data.user.goldcoin}`);
message += `当前金币:${data.data.user.goldcoin}`;
} catch (e) {
console.error(`获取金币时发生异常:${e}`);
}
}