优化脚本

This commit is contained in:
weiqun
2025-02-13 16:25:44 +08:00
parent d008f0b2f6
commit e0eb4e7f6b
4 changed files with 368 additions and 196 deletions

View File

@@ -14,6 +14,7 @@ from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad from Crypto.Util.Padding import pad, unpad
from aiohttp import ClientSession, TCPConnector from aiohttp import ClientSession, TCPConnector
import httpx import httpx
import logging
diffValue = 2 diffValue = 2
filename='Cache.js' 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'): def initCookie(getUrl='https://wapact.189.cn:9001/gateway/standQuery/detailNew/exchange'):
try:
global js_code_ym, fileContent global js_code_ym, fileContent
cookie = ''
response = custom_client.post(getUrl) response = custom_client.post(getUrl)
response.raise_for_status()
# 解析响应内容
content = response.text.split(' content="')[2].split('" r=')[0] content = response.text.split(' content="')[2].split('" r=')[0]
code1 = response.text.split('$_ts=window')[1].split('</script><script type="text/javascript"')[0] code1 = response.text.split('$_ts=window')[1].split('</script><script type="text/javascript"')[0]
code1Content = '$_ts=window' + code1 code1Content = '$_ts=window' + code1
Url = response.text.split('$_ts.lcd();</script><script type="text/javascript" charset="utf-8" src="')[1].split('" r=')[0] 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 not fileContent:
if fileContent == '': fileRes = custom_client.get(Url)
if not os.path.exists(filename):
fileRes = custom_client.get(rsurl)
fileContent = fileRes.text
if fileRes.status_code == 200: if fileRes.status_code == 200:
fileContent = fileRes.text
with open(filename, 'w', encoding='utf-8') as file: with open(filename, 'w', encoding='utf-8') as file:
file.write(fileRes.text) file.write(fileRes.text)
else: else:
print(f"Failed to download {rsurl}. Status code: {fileRes.status_code}") logger.error(f"Failed to download {Url}. Status code: {fileRes.status_code}")
if response.headers['Set-Cookie']: return None
cookie = response.headers['Set-Cookie'].split(';')[0].split('=')[1]
# 处理cookies
cookie = response.headers.get('Set-Cookie', '').split(';')[0].split('=')[1]
runJs = js_code_ym.replace('content_code', content).replace("'ts_code'", code1Content + fileContent) runJs = js_code_ym.replace('content_code', content).replace("'ts_code'", code1Content + fileContent)
execjsRun = RefererCookie(runJs) execjsRun = RefererCookie(runJs)
return { return {
'cookie': cookie, 'cookie': cookie,
'execjsRun': execjsRun 'execjsRun': execjsRun
} }
except Exception as e:
logger.error(f"初始化cookies失败: {str(e)}")
return None
def RefererCookie(runJs): def RefererCookie(runJs):
try: try:
execjsRun = execjs.compile(runJs) execjsRun = execjs.compile(runJs)

View File

@@ -2,14 +2,14 @@
新电信抢话费 新电信抢话费
群里发的,未测试好,自测 群里发的,未测试好,自测
修改内容如下 修改内容如下"
1.删除内置的一个手机账号 1.删除内置的一个手机账号
2.修改环境变量名保持和拉菲电信金豆本环境变量一致 2.修改环境变量名保持和拉菲电信金豆本环境变量一致
3.恢复瑞数通杀.js调用地址确实也不知道是啥。398、399行注释 3.恢复瑞数通杀.js调用地址确实也不知道是啥。398、399行注释
环境变量chinaTelecomAccount值为账号#密码 环境变量chinaTelecomAccount值为账号#密码
cron: 57 9,13,23 * * * cron: 56 59 09,13 * * *
const $ = new Env("新电信抢话费"); const $ = new Env("新电信抢话费");
""" """
@@ -40,11 +40,27 @@ from Crypto.Util.Padding import pad, unpad
from aiohttp import ClientSession, TCPConnector from aiohttp import ClientSession, TCPConnector
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
import subprocess 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" run_num=os.environ.get('reqNUM') or "2"
# 添加配置类
class Config:
MAX_RETRIES = 3 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: class RateLimiter:
def __init__(self, rate_limit): def __init__(self, rate_limit):
@@ -427,27 +443,89 @@ async def qgNight(phone, ticket, timeDiff,isTrue):
async def qgDay(phone, ticket, timeDiff, isTrue): async def qgDay(phone, ticket, timeDiff, isTrue):
async with AsyncSessionManager() as s: async with AsyncSessionManager() as s:
pass 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): async def main(timeDiff, isTRUE, hour):
tasks = [] config = Config()
request_util = RequestUtil()
try:
PHONES = os.environ.get('chinaTelecomAccount') PHONES = os.environ.get('chinaTelecomAccount')
if not PHONES:
logger.error("未找到环境变量 chinaTelecomAccount")
raise ValueError("未找到环境变量 chinaTelecomAccount")
phone_list = PHONES.split('\n') phone_list = PHONES.split('\n')
tasks = []
logger.info(f"开始处理 {len(phone_list)} 个账号")
for phoneV in phone_list: for phoneV in phone_list:
try:
value = phoneV.split('#') value = phoneV.split('#')
if len(value) != 2:
logger.warning(f"账号格式错误: {phoneV}")
continue
phone, password = value[0], value[1] phone, password = value[0], value[1]
printn(f'{get_first_three(phone)}开始登录') logger.info(f'{get_first_three(phone)} 开始登录')
ticket = userLoginNormal(phone, password) ticket = userLoginNormal(phone, password)
if ticket: if not ticket:
# hour=datetime.datetime.now().hour logger.error(f'{get_first_three(phone)} 登录失败')
# hour=23 continue
logger.info(f'{get_first_three(phone)} 登录成功')
if hour > 15: if hour > 15:
logger.info(f'{get_first_three(phone)} 加入夜间任务队列')
tasks.append(qgNight(phone, ticket, timeDiff, isTRUE)) 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: else:
printn(f'{phone} 登录失败') logger.info(f'{get_first_three(phone)} 加入日间任务队列')
await asyncio.gather(*tasks) 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__": if __name__ == "__main__":
h = datetime.datetime.now().hour h = datetime.datetime.now().hour

View File

@@ -8,17 +8,43 @@ export Ikuuu_HOST="ikuuu.one"
cron: 33 08 * * * cron: 33 08 * * *
const $ = new Env("ikuuu 机场签到"); 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://"; static get PROTOCOL_PREFIX() {
const logInUrl = `${protocolPrefix}${host}/auth/login`; return "https://";
const checkInUrl = `${protocolPrefix}${host}/user/checkin`; }
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=/,"); let cookieSets = rawCookie.split("path=/,");
const cookies = {}; const cookies = {};
cookieSets.forEach((cookie) => { cookieSets.forEach((cookie) => {
@@ -26,7 +52,6 @@ function parseCookie(rawCookie) {
if (match) { if (match) {
const fieldName = match[1].trim(); const fieldName = match[1].trim();
let fieldValue = match[2].trim(); let fieldValue = match[2].trim();
fieldValue = decodeURIComponent(fieldValue); fieldValue = decodeURIComponent(fieldValue);
if (!cookies[fieldName]) { if (!cookies[fieldName]) {
@@ -38,51 +63,68 @@ function parseCookie(rawCookie) {
return cookies; return cookies;
} }
function generateCookieStr(cookieObject) { static generateCookieStr(cookieObject) {
return Object.entries(cookieObject) return Object.entries(cookieObject)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`) .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join("; "); .join("; ");
} }
}
async function logIn(email, passwd) { // Ikuuu 客户端类
console.log(`Logging in with email: ${email}...`); 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(); let formData = new FormData();
formData.append("host", host); formData.append("host", Config.HOST);
formData.append("email", email); formData.append("email", this.email);
formData.append("passwd", passwd); formData.append("passwd", this.password);
formData.append("code", ""); formData.append("code", "");
formData.append("remember_me", "off"); formData.append("remember_me", "off");
let response = await fetch(logInUrl, { try {
let response = await fetch(Config.LOGIN_URL, {
method: "POST", method: "POST",
body: formData, body: formData,
}); });
let rawCookie = response.headers.get("set-cookie"); let rawCookie = response.headers.get("set-cookie");
let responseJson = await response.json(); let responseJson = await response.json();
if (responseJson) { 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) { async checkIn(cookie) {
return fetch(checkInUrl, { try {
let response = await fetch(Config.CHECKIN_URL, {
method: "POST", method: "POST",
headers: { 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; let passwords = process.env.Ikuuu_PASSWD;
if (!emails || !passwords) { 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); process.exit(1);
} }
@@ -103,32 +145,40 @@ async function main() {
let passwdList = passwords.split(";"); let passwdList = passwords.split(";");
if (emailList.length !== passwdList.length) { 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); process.exit(1);
} }
// 创建一个通知数组,避免多次发送相同的消息
let notifications = []; let notifications = [];
// 遍历每个账号执行登录并签到
for (let i = 0; i < emailList.length; i++) { for (let i = 0; i < emailList.length; i++) {
let email = emailList[i]; let email = emailList[i];
let passwd = passwdList[i]; let passwd = passwdList[i];
let cookie = await logIn(email, passwd); let client = new IkuuuClient(email, passwd);
await checkIn(cookie);
// 每个账号的操作只添加一条通知 try {
let cookie = await client.login();
await client.checkIn(cookie);
notifications.push(`账号 ${email} 登录成功,签到完成`); notifications.push(`账号 ${email} 登录成功,签到完成`);
} catch (error) {
notifications.push(`账号 ${email} 操作失败: ${error.message}`);
}
// 每次登录后延迟 2 秒
await delay(2000); // 延迟 2 秒 await delay(2000); // 延迟 2 秒
} }
// 合并所有通知为一条消息,避免多次发送 // 过滤掉 undefined 值
const notificationMessage = notifications.join("\n"); const notificationMessage = notifications
.filter(msg => msg !== undefined)
.join("\n");
// 调试:打印通知数组
console.log("通知数组内容:", notifications);
// 发送合并后的消息通知
sendNotify(`多个账号操作完成:\n${notificationMessage}`); sendNotify(`多个账号操作完成:\n${notificationMessage}`);
} }
main(); main().catch(error => {
log('ERROR', `Main function failed: ${error.message}`);
process.exit(1);
});

View File

@@ -7,6 +7,7 @@ import os
import time import time
from requests import session from requests import session
from hashlib import md5 from hashlib import md5
from concurrent.futures import ThreadPoolExecutor, as_completed
try: try:
from sendNotify import send from sendNotify import send
@@ -14,6 +15,11 @@ except ImportError:
print("加载通知服务失败") print("加载通知服务失败")
class Tieba(): class Tieba():
# 将配置项提取为类变量
MAX_RETRY = 10 # 最大重试次数
REQUEST_TIMEOUT = 30 # 请求超时时间
SLEEP_TIME = 10 # 退出前等待时间
Tieba_BDUSS = os.getenv("Tieba_BDUSS") Tieba_BDUSS = os.getenv("Tieba_BDUSS")
def __init__(self, STOKEN): def __init__(self, STOKEN):
@@ -40,13 +46,17 @@ class Tieba():
self.session.cookies.update({'BDUSS': self.BDUSS, 'STOKEN': self.STOKEN}) self.session.cookies.update({'BDUSS': self.BDUSS, 'STOKEN': self.STOKEN})
def fetch_tbs(self): def fetch_tbs(self):
try:
r = self.session.get('http://tieba.baidu.com/dc/common/tbs').json() r = self.session.get('http://tieba.baidu.com/dc/common/tbs').json()
if r['is_login'] == 1: if r['is_login'] == 1:
self.tbs = r['tbs'] self.tbs = r['tbs']
else: else:
raise Exception('获取tbs错误以下为返回数据' + str(r)) raise Exception('获取tbs错误以下为返回数据' + str(r))
except Exception as e:
raise Exception(f'获取tbs时发生异常{str(e)}')
def fetch_likes(self): def fetch_likes(self):
try:
self.rest = set() self.rest = set()
self.already = set() self.already = set()
r = self.session.get('https://tieba.baidu.com/mo/q/newmoindex?').json() r = self.session.get('https://tieba.baidu.com/mo/q/newmoindex?').json()
@@ -58,14 +68,17 @@ class Tieba():
self.rest.add(forum['forum_name']) self.rest.add(forum['forum_name'])
else: else:
raise Exception('获取关注贴吧错误!以下为返回数据:' + str(r)) raise Exception('获取关注贴吧错误!以下为返回数据:' + str(r))
except Exception as e:
raise Exception(f'获取关注贴吧时发生异常:{str(e)}')
def sign(self, forum_name): def sign(self, forum_name):
try:
data = { data = {
'kw': forum_name, 'kw': forum_name,
'tbs': self.tbs, 'tbs': self.tbs,
'sign': md5(f'kw={forum_name}tbs={self.tbs}tiebaclient!!!'.encode('utf8')).hexdigest() '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': if r['error_code'] == '160002':
print(f'"{forum_name}"已签到') print(f'"{forum_name}"已签到')
self.sign_list.append(forum_name) self.sign_list.append(forum_name)
@@ -79,17 +92,28 @@ class Tieba():
print(f'"{forum_name}"签到失败!以下为返回数据:{str(r)}') print(f'"{forum_name}"签到失败!以下为返回数据:{str(r)}')
self.fail_list.append(forum_name) self.fail_list.append(forum_name)
return False return False
except Exception as e:
print(f'"{forum_name}"签到时发生异常:{str(e)}')
self.fail_list.append(forum_name)
return False
def loop(self, n): def loop(self, n):
print(f'* 开始第{n}轮签到 *') print(f'* 开始第{n}轮签到 *')
rest = set() rest = set()
self.fetch_tbs() self.fetch_tbs()
for forum_name in self.rest: # 使用线程池并发签到
flag = self.sign(forum_name) with ThreadPoolExecutor(max_workers=5) as executor:
if not flag: 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) rest.add(forum_name)
self.rest = rest self.rest = rest
if n >= 10: # 最大重试次数 if n >= self.MAX_RETRY: # 使用类变量
self.rest = set() self.rest = set()
def main(self, max): def main(self, max):
@@ -114,6 +138,7 @@ class Tieba():
self.send_notification_message() self.send_notification_message()
def send_notification_message(self): def send_notification_message(self):
try:
msg = "贴吧签到结果:\n" msg = "贴吧签到结果:\n"
if self.success_list: if self.success_list:
@@ -124,8 +149,9 @@ class Tieba():
if self.sign_list: if self.sign_list:
msg += "- **已经签到的贴吧**\n" 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"\n共关注了{len(self.already) + len(self.success_list)}个贴吧,"
msg += f"本次成功签到了{len(self.success_list)}个," msg += f"本次成功签到了{len(self.success_list)}个,"
msg += f"失败了{len(self.fail_list)}个," msg += f"失败了{len(self.fail_list)}个,"
@@ -134,8 +160,10 @@ class Tieba():
# 发送通知 # 发送通知
send('Tieba_Sign', msg) 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__": if __name__ == "__main__":
BDUSS_values = os.getenv("Tieba_BDUSS") BDUSS_values = os.getenv("Tieba_BDUSS")