mirror of
https://github.com/wq-h/qinglong.git
synced 2025-12-18 15:55:03 +08:00
优化脚本
This commit is contained in:
38
Ruishu.py
38
Ruishu.py
@@ -14,6 +14,7 @@ from Crypto.Cipher import DES3
|
||||
from Crypto.Util.Padding import pad, unpad
|
||||
from aiohttp import ClientSession, TCPConnector
|
||||
import httpx
|
||||
import logging
|
||||
|
||||
diffValue = 2
|
||||
filename='Cache.js'
|
||||
@@ -77,35 +78,50 @@ custom_client = httpx.Client(
|
||||
)
|
||||
)
|
||||
|
||||
# 添加日志记录
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def initCookie(getUrl='https://wapact.189.cn:9001/gateway/standQuery/detailNew/exchange'):
|
||||
try:
|
||||
global js_code_ym, fileContent
|
||||
cookie = ''
|
||||
response = custom_client.post(getUrl)
|
||||
response.raise_for_status()
|
||||
|
||||
# 解析响应内容
|
||||
content = response.text.split(' content="')[2].split('" r=')[0]
|
||||
code1 = response.text.split('$_ts=window')[1].split('</script><script type="text/javascript"')[0]
|
||||
code1Content = '$_ts=window' + code1
|
||||
Url = response.text.split('$_ts.lcd();</script><script type="text/javascript" charset="utf-8" src="')[1].split('" r=')[0]
|
||||
urls = getUrl.split('/')
|
||||
rsurl = urls[0] + '//' + urls[2] + Url
|
||||
filename = 'Cache.js'
|
||||
if fileContent == '':
|
||||
if not os.path.exists(filename):
|
||||
fileRes = custom_client.get(rsurl)
|
||||
fileContent = fileRes.text
|
||||
|
||||
# 处理文件缓存
|
||||
if not fileContent:
|
||||
fileRes = custom_client.get(Url)
|
||||
if fileRes.status_code == 200:
|
||||
fileContent = fileRes.text
|
||||
with open(filename, 'w', encoding='utf-8') as file:
|
||||
file.write(fileRes.text)
|
||||
else:
|
||||
print(f"Failed to download {rsurl}. Status code: {fileRes.status_code}")
|
||||
if response.headers['Set-Cookie']:
|
||||
cookie = response.headers['Set-Cookie'].split(';')[0].split('=')[1]
|
||||
logger.error(f"Failed to download {Url}. Status code: {fileRes.status_code}")
|
||||
return None
|
||||
|
||||
# 处理cookies
|
||||
cookie = response.headers.get('Set-Cookie', '').split(';')[0].split('=')[1]
|
||||
runJs = js_code_ym.replace('content_code', content).replace("'ts_code'", code1Content + fileContent)
|
||||
execjsRun = RefererCookie(runJs)
|
||||
|
||||
return {
|
||||
'cookie': cookie,
|
||||
'execjsRun': execjsRun
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"初始化cookies失败: {str(e)}")
|
||||
return None
|
||||
|
||||
def RefererCookie(runJs):
|
||||
try:
|
||||
execjsRun = execjs.compile(runJs)
|
||||
|
||||
106
chinatelecom.py
106
chinatelecom.py
@@ -2,14 +2,14 @@
|
||||
新电信抢话费
|
||||
|
||||
群里发的,未测试好,自测
|
||||
修改内容如下“
|
||||
修改内容如下"
|
||||
1.删除内置的一个手机账号
|
||||
2.修改环境变量名保持和拉菲电信金豆本环境变量一致
|
||||
3.恢复瑞数通杀.js调用地址,确实也不知道是啥。398、399行注释
|
||||
|
||||
环境变量chinaTelecomAccount,值为:账号#密码
|
||||
|
||||
cron: 57 9,13,23 * * *
|
||||
cron: 56 59 09,13 * * *
|
||||
const $ = new Env("新电信抢话费");
|
||||
|
||||
"""
|
||||
@@ -40,11 +40,27 @@ from Crypto.Util.Padding import pad, unpad
|
||||
from aiohttp import ClientSession, TCPConnector
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import subprocess
|
||||
import logging
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler('chinatelecom.log'),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
run_num=os.environ.get('reqNUM') or "2"
|
||||
|
||||
# 添加配置类
|
||||
class Config:
|
||||
MAX_RETRIES = 3
|
||||
RATE_LIMIT = 10 # 每秒请求数限制
|
||||
RATE_LIMIT = 10
|
||||
REQUEST_TIMEOUT = 30
|
||||
BASE_URL = "https://wapact.189.cn:9001"
|
||||
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"
|
||||
|
||||
class RateLimiter:
|
||||
def __init__(self, rate_limit):
|
||||
@@ -427,27 +443,89 @@ async def qgNight(phone, ticket, timeDiff,isTrue):
|
||||
async def qgDay(phone, ticket, timeDiff, isTrue):
|
||||
async with AsyncSessionManager() as s:
|
||||
pass
|
||||
|
||||
# 修改 RequestUtil 类
|
||||
class RequestUtil:
|
||||
def __init__(self):
|
||||
# 在创建 ClientSession 时通过 headers 参数设置请求头
|
||||
self.session = aiohttp.ClientSession(headers={"User-Agent": Config.USER_AGENT})
|
||||
self.rate_limiter = RateLimiter(Config.RATE_LIMIT)
|
||||
|
||||
async def safe_request(self, method, url, **kwargs):
|
||||
for attempt in range(Config.MAX_RETRIES):
|
||||
try:
|
||||
await self.rate_limiter.acquire()
|
||||
async with self.session.request(method, url, timeout=Config.REQUEST_TIMEOUT, **kwargs) as response:
|
||||
response.raise_for_status()
|
||||
return await response.json()
|
||||
except Exception as e:
|
||||
if attempt == Config.MAX_RETRIES - 1:
|
||||
raise
|
||||
await asyncio.sleep(2 ** attempt)
|
||||
|
||||
async def close(self):
|
||||
if self.session and not self.session.closed:
|
||||
await self.session.close()
|
||||
|
||||
# 修改 main 函数,增加日志记录
|
||||
async def main(timeDiff, isTRUE, hour):
|
||||
tasks = []
|
||||
config = Config()
|
||||
request_util = RequestUtil()
|
||||
|
||||
try:
|
||||
PHONES = os.environ.get('chinaTelecomAccount')
|
||||
if not PHONES:
|
||||
logger.error("未找到环境变量 chinaTelecomAccount")
|
||||
raise ValueError("未找到环境变量 chinaTelecomAccount")
|
||||
|
||||
phone_list = PHONES.split('\n')
|
||||
tasks = []
|
||||
logger.info(f"开始处理 {len(phone_list)} 个账号")
|
||||
|
||||
for phoneV in phone_list:
|
||||
try:
|
||||
value = phoneV.split('#')
|
||||
if len(value) != 2:
|
||||
logger.warning(f"账号格式错误: {phoneV}")
|
||||
continue
|
||||
|
||||
phone, password = value[0], value[1]
|
||||
printn(f'{get_first_three(phone)}开始登录')
|
||||
logger.info(f'{get_first_three(phone)} 开始登录')
|
||||
|
||||
ticket = userLoginNormal(phone, password)
|
||||
if ticket:
|
||||
# hour=datetime.datetime.now().hour
|
||||
# hour=23
|
||||
if not ticket:
|
||||
logger.error(f'{get_first_three(phone)} 登录失败')
|
||||
continue
|
||||
|
||||
logger.info(f'{get_first_three(phone)} 登录成功')
|
||||
|
||||
if hour > 15:
|
||||
logger.info(f'{get_first_three(phone)} 加入夜间任务队列')
|
||||
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)
|
||||
logger.info(f'{get_first_three(phone)} 加入日间任务队列')
|
||||
tasks.append(qgDay(phone, ticket, timeDiff, isTRUE))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'{get_first_three(phone)} 处理失败: {str(e)}')
|
||||
continue
|
||||
|
||||
logger.info(f"开始执行 {len(tasks)} 个任务")
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
# 记录任务执行结果
|
||||
for i, result in enumerate(results, start=1): # 从1开始计数
|
||||
if isinstance(result, Exception):
|
||||
logger.error(f"任务 {i} 执行失败: {str(result)}")
|
||||
else:
|
||||
logger.info(f"任务 {i} 执行成功")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'主程序运行失败: {str(e)}', exc_info=True)
|
||||
finally:
|
||||
logger.info("正在关闭请求会话")
|
||||
await request_util.close()
|
||||
logger.info("程序执行完毕")
|
||||
|
||||
if __name__ == "__main__":
|
||||
h = datetime.datetime.now().hour
|
||||
|
||||
@@ -8,17 +8,43 @@ export Ikuuu_HOST="ikuuu.one"
|
||||
cron: 33 08 * * *
|
||||
const $ = new Env("ikuuu 机场签到");
|
||||
*/
|
||||
const { sendNotify } = require("./sendNotify"); // 引入 sendNotify.js 模块
|
||||
const { sendNotify } = require("./sendNotify");
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const host = process.env.Ikuuu_HOST || "ikuuu.one";
|
||||
// 配置类
|
||||
class Config {
|
||||
static get HOST() {
|
||||
return process.env.Ikuuu_HOST || "ikuuu.one";
|
||||
}
|
||||
|
||||
const protocolPrefix = "https://";
|
||||
const logInUrl = `${protocolPrefix}${host}/auth/login`;
|
||||
const checkInUrl = `${protocolPrefix}${host}/user/checkin`;
|
||||
static get PROTOCOL_PREFIX() {
|
||||
return "https://";
|
||||
}
|
||||
|
||||
function parseCookie(rawCookie) {
|
||||
static get LOGIN_URL() {
|
||||
return `${Config.PROTOCOL_PREFIX}${Config.HOST}/auth/login`;
|
||||
}
|
||||
|
||||
static get CHECKIN_URL() {
|
||||
return `${Config.PROTOCOL_PREFIX}${Config.HOST}/user/checkin`;
|
||||
}
|
||||
}
|
||||
|
||||
// 日志配置
|
||||
const logStream = fs.createWriteStream(path.join(__dirname, 'ikuuu.log'), { flags: 'a' });
|
||||
|
||||
function log(level, message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
const logMessage = `[${timestamp}] [${level}] ${message}\n`;
|
||||
logStream.write(logMessage);
|
||||
console.log(logMessage);
|
||||
}
|
||||
|
||||
// Cookie 工具类
|
||||
class CookieUtil {
|
||||
static parseCookie(rawCookie) {
|
||||
let cookieSets = rawCookie.split("path=/,");
|
||||
|
||||
const cookies = {};
|
||||
|
||||
cookieSets.forEach((cookie) => {
|
||||
@@ -26,7 +52,6 @@ function parseCookie(rawCookie) {
|
||||
if (match) {
|
||||
const fieldName = match[1].trim();
|
||||
let fieldValue = match[2].trim();
|
||||
|
||||
fieldValue = decodeURIComponent(fieldValue);
|
||||
|
||||
if (!cookies[fieldName]) {
|
||||
@@ -38,51 +63,68 @@ function parseCookie(rawCookie) {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
function generateCookieStr(cookieObject) {
|
||||
static generateCookieStr(cookieObject) {
|
||||
return Object.entries(cookieObject)
|
||||
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
||||
.join("; ");
|
||||
}
|
||||
}
|
||||
|
||||
async function logIn(email, passwd) {
|
||||
console.log(`Logging in with email: ${email}...`);
|
||||
// Ikuuu 客户端类
|
||||
class IkuuuClient {
|
||||
constructor(email, password) {
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
async login() {
|
||||
log('INFO', `Logging in with email: ${this.email}...`);
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append("host", host);
|
||||
formData.append("email", email);
|
||||
formData.append("passwd", passwd);
|
||||
formData.append("host", Config.HOST);
|
||||
formData.append("email", this.email);
|
||||
formData.append("passwd", this.password);
|
||||
formData.append("code", "");
|
||||
formData.append("remember_me", "off");
|
||||
|
||||
let response = await fetch(logInUrl, {
|
||||
try {
|
||||
let response = await fetch(Config.LOGIN_URL, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
let rawCookie = response.headers.get("set-cookie");
|
||||
|
||||
let responseJson = await response.json();
|
||||
|
||||
if (responseJson) {
|
||||
console.log(responseJson.msg);
|
||||
log('INFO', responseJson.msg);
|
||||
}
|
||||
|
||||
return parseCookie(rawCookie);
|
||||
return CookieUtil.parseCookie(rawCookie);
|
||||
} catch (error) {
|
||||
log('ERROR', `Login failed for ${this.email}: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function checkIn(cookie) {
|
||||
return fetch(checkInUrl, {
|
||||
async checkIn(cookie) {
|
||||
try {
|
||||
let response = await fetch(Config.CHECKIN_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Cookie: generateCookieStr(cookie),
|
||||
Cookie: CookieUtil.generateCookieStr(cookie),
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((resJson) => {
|
||||
if (resJson) {
|
||||
console.log(resJson.msg);
|
||||
}
|
||||
});
|
||||
|
||||
let responseJson = await response.json();
|
||||
if (responseJson) {
|
||||
log('INFO', responseJson.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
log('ERROR', `Check-in failed for ${this.email}: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 延迟函数,单位为毫秒
|
||||
@@ -95,7 +137,7 @@ async function main() {
|
||||
let passwords = process.env.Ikuuu_PASSWD;
|
||||
|
||||
if (!emails || !passwords) {
|
||||
console.log("ENV ERROR: Please set both Ikuuu_EMAIL and Ikuuu_PASSWD.");
|
||||
log('ERROR', "ENV ERROR: Please set both Ikuuu_EMAIL and Ikuuu_PASSWD.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -103,32 +145,40 @@ async function main() {
|
||||
let passwdList = passwords.split(";");
|
||||
|
||||
if (emailList.length !== passwdList.length) {
|
||||
console.log("Error: The number of emails does not match the number of passwords.");
|
||||
log('ERROR', "Error: The number of emails does not match the number of passwords.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 创建一个通知数组,避免多次发送相同的消息
|
||||
let notifications = [];
|
||||
|
||||
// 遍历每个账号执行登录并签到
|
||||
for (let i = 0; i < emailList.length; i++) {
|
||||
let email = emailList[i];
|
||||
let passwd = passwdList[i];
|
||||
let cookie = await logIn(email, passwd);
|
||||
await checkIn(cookie);
|
||||
let client = new IkuuuClient(email, passwd);
|
||||
|
||||
// 每个账号的操作只添加一条通知
|
||||
try {
|
||||
let cookie = await client.login();
|
||||
await client.checkIn(cookie);
|
||||
notifications.push(`账号 ${email} 登录成功,签到完成`);
|
||||
} catch (error) {
|
||||
notifications.push(`账号 ${email} 操作失败: ${error.message}`);
|
||||
}
|
||||
|
||||
// 每次登录后延迟 2 秒
|
||||
await delay(2000); // 延迟 2 秒
|
||||
}
|
||||
|
||||
// 合并所有通知为一条消息,避免多次发送
|
||||
const notificationMessage = notifications.join("\n");
|
||||
// 过滤掉 undefined 值
|
||||
const notificationMessage = notifications
|
||||
.filter(msg => msg !== undefined)
|
||||
.join("\n");
|
||||
|
||||
// 调试:打印通知数组
|
||||
console.log("通知数组内容:", notifications);
|
||||
|
||||
// 发送合并后的消息通知
|
||||
sendNotify(`多个账号操作完成:\n${notificationMessage}`);
|
||||
}
|
||||
|
||||
main();
|
||||
main().catch(error => {
|
||||
log('ERROR', `Main function failed: ${error.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
44
tieba.py
44
tieba.py
@@ -7,6 +7,7 @@ import os
|
||||
import time
|
||||
from requests import session
|
||||
from hashlib import md5
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
try:
|
||||
from sendNotify import send
|
||||
@@ -14,6 +15,11 @@ except ImportError:
|
||||
print("加载通知服务失败")
|
||||
|
||||
class Tieba():
|
||||
# 将配置项提取为类变量
|
||||
MAX_RETRY = 10 # 最大重试次数
|
||||
REQUEST_TIMEOUT = 30 # 请求超时时间
|
||||
SLEEP_TIME = 10 # 退出前等待时间
|
||||
|
||||
Tieba_BDUSS = os.getenv("Tieba_BDUSS")
|
||||
|
||||
def __init__(self, STOKEN):
|
||||
@@ -40,13 +46,17 @@ class Tieba():
|
||||
self.session.cookies.update({'BDUSS': self.BDUSS, 'STOKEN': self.STOKEN})
|
||||
|
||||
def fetch_tbs(self):
|
||||
try:
|
||||
r = self.session.get('http://tieba.baidu.com/dc/common/tbs').json()
|
||||
if r['is_login'] == 1:
|
||||
self.tbs = r['tbs']
|
||||
else:
|
||||
raise Exception('获取tbs错误!以下为返回数据:' + str(r))
|
||||
except Exception as e:
|
||||
raise Exception(f'获取tbs时发生异常:{str(e)}')
|
||||
|
||||
def fetch_likes(self):
|
||||
try:
|
||||
self.rest = set()
|
||||
self.already = set()
|
||||
r = self.session.get('https://tieba.baidu.com/mo/q/newmoindex?').json()
|
||||
@@ -58,14 +68,17 @@ class Tieba():
|
||||
self.rest.add(forum['forum_name'])
|
||||
else:
|
||||
raise Exception('获取关注贴吧错误!以下为返回数据:' + str(r))
|
||||
except Exception as e:
|
||||
raise Exception(f'获取关注贴吧时发生异常:{str(e)}')
|
||||
|
||||
def sign(self, forum_name):
|
||||
try:
|
||||
data = {
|
||||
'kw': forum_name,
|
||||
'tbs': self.tbs,
|
||||
'sign': md5(f'kw={forum_name}tbs={self.tbs}tiebaclient!!!'.encode('utf8')).hexdigest()
|
||||
}
|
||||
r = self.session.post('http://c.tieba.baidu.com/c/c/forum/sign', data).json()
|
||||
r = self.session.post('http://c.tieba.baidu.com/c/c/forum/sign', data, timeout=self.REQUEST_TIMEOUT).json()
|
||||
if r['error_code'] == '160002':
|
||||
print(f'"{forum_name}"已签到')
|
||||
self.sign_list.append(forum_name)
|
||||
@@ -79,17 +92,28 @@ class Tieba():
|
||||
print(f'"{forum_name}"签到失败!以下为返回数据:{str(r)}')
|
||||
self.fail_list.append(forum_name)
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f'"{forum_name}"签到时发生异常:{str(e)}')
|
||||
self.fail_list.append(forum_name)
|
||||
return False
|
||||
|
||||
def loop(self, n):
|
||||
print(f'* 开始第{n}轮签到 *')
|
||||
rest = set()
|
||||
self.fetch_tbs()
|
||||
for forum_name in self.rest:
|
||||
flag = self.sign(forum_name)
|
||||
if not flag:
|
||||
# 使用线程池并发签到
|
||||
with ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = {executor.submit(self.sign, forum_name): forum_name for forum_name in self.rest}
|
||||
for future in as_completed(futures):
|
||||
forum_name = futures[future]
|
||||
try:
|
||||
if not future.result():
|
||||
rest.add(forum_name)
|
||||
except Exception as e:
|
||||
print(f'"{forum_name}"签到异常:{str(e)}')
|
||||
rest.add(forum_name)
|
||||
self.rest = rest
|
||||
if n >= 10: # 最大重试次数
|
||||
if n >= self.MAX_RETRY: # 使用类变量
|
||||
self.rest = set()
|
||||
|
||||
def main(self, max):
|
||||
@@ -114,6 +138,7 @@ class Tieba():
|
||||
self.send_notification_message()
|
||||
|
||||
def send_notification_message(self):
|
||||
try:
|
||||
msg = "贴吧签到结果:\n"
|
||||
|
||||
if self.success_list:
|
||||
@@ -124,8 +149,9 @@ class Tieba():
|
||||
|
||||
if self.sign_list:
|
||||
msg += "- **已经签到的贴吧**:\n"
|
||||
msg += " " + "\n ".join(self.sign_list) + "\n"
|
||||
msg += " " + ", ".join(self.sign_list) # 去掉末尾的换行符
|
||||
|
||||
# 直接拼接统计信息,去掉前面的空行
|
||||
msg += f"\n共关注了{len(self.already) + len(self.success_list)}个贴吧,"
|
||||
msg += f"本次成功签到了{len(self.success_list)}个,"
|
||||
msg += f"失败了{len(self.fail_list)}个,"
|
||||
@@ -134,8 +160,10 @@ class Tieba():
|
||||
# 发送通知
|
||||
send('Tieba_Sign', msg)
|
||||
|
||||
# Add a 10-second delay before exiting
|
||||
time.sleep(10)
|
||||
# 使用类变量
|
||||
time.sleep(self.SLEEP_TIME)
|
||||
except Exception as e:
|
||||
print(f'发送通知时发生异常:{str(e)}')
|
||||
|
||||
if __name__ == "__main__":
|
||||
BDUSS_values = os.getenv("Tieba_BDUSS")
|
||||
|
||||
Reference in New Issue
Block a user