mirror of
https://github.com/KingJin-web/zy.git
synced 2025-12-17 15:34:37 +08:00
初始化
This commit is contained in:
525
电信/0点权益.py
Normal file
525
电信/0点权益.py
Normal file
@@ -0,0 +1,525 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import ssl
|
||||
import time
|
||||
import json
|
||||
import base64
|
||||
import random
|
||||
import certifi
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import datetime
|
||||
import requests
|
||||
import binascii
|
||||
from http import cookiejar
|
||||
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
|
||||
|
||||
# 在全局变量区域添加停止事件
|
||||
stop_all_event = asyncio.Event() # 控制所有任务停止
|
||||
|
||||
# 🌸 标题 🌸
|
||||
LOGO = f'''
|
||||
✧・゚: *✧・゚:* 电信金豆换话费脚本 ✧・゚: *✧・゚:*
|
||||
'''
|
||||
|
||||
run_num = os.environ.get('reqNUM') or "50"
|
||||
MAX_RETRIES = 3
|
||||
RATE_LIMIT = 15 # 每秒请求数限制
|
||||
|
||||
# 🌸 日志相关设置 🌸
|
||||
yf = datetime.datetime.now().strftime("%Y%m")
|
||||
try:
|
||||
with open('电信金豆换话费.log') as fr:
|
||||
dhjl = json.load(fr)
|
||||
except:
|
||||
dhjl = {}
|
||||
if yf not in dhjl:
|
||||
dhjl[yf] = {}
|
||||
|
||||
|
||||
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()
|
||||
|
||||
except (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError) as e:
|
||||
print(f"{Color.LIGHT_PINK}💔 请求失败,第 {attempt + 1} 次重试: {e}{Color.ENDC}")
|
||||
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()
|
||||
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 f"{str(value)[:3]}****{str(value)[-4:]}"
|
||||
elif isinstance(value, str):
|
||||
return f"{value[:3]}****{value[-4:]}"
|
||||
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)
|
||||
key_size = public_key.size_in_bytes()
|
||||
max_chunk_size = key_size - 11
|
||||
plaintext_bytes = plaintext.encode()
|
||||
ciphertext = b''
|
||||
for i in range(0, len(plaintext_bytes), max_chunk_size):
|
||||
chunk = plaintext_bytes[i:i + max_chunk_size]
|
||||
encrypted_chunk = cipher.encrypt(chunk)
|
||||
ciphertext += encrypted_chunk
|
||||
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.'
|
||||
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)}}}).json()
|
||||
l = r['responseData']['data']['loginSuccessResult']
|
||||
if l:
|
||||
ticket = get_ticket(phone, l['userId'], l['token'])
|
||||
return ticket
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"💔 登录失败: {e}")
|
||||
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):
|
||||
try:
|
||||
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])
|
||||
except Exception as e:
|
||||
print(f"💔 获取ticket失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def exchange(s, phone, title, aid, 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": aid}) as response:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f"💔 兑换出错: {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, accId):
|
||||
try:
|
||||
value = {
|
||||
"id": aid,
|
||||
"accId": accId,
|
||||
"showType": "9003",
|
||||
"showEffect": "8",
|
||||
"czValue": "0"
|
||||
}
|
||||
paraV = encrypt_para(value)
|
||||
|
||||
printn(f"{get_first_three(phone)}: 开始兑换啦~ ✨")
|
||||
|
||||
response = await asyncio.to_thread(
|
||||
session.post,
|
||||
'https://wappark.189.cn/jt-sign/paradise/receiverRights',
|
||||
json={"para": paraV}
|
||||
)
|
||||
|
||||
login = response.json()
|
||||
printn(f"💔 {get_first_three(phone)}: 结果是 {login} 💬")
|
||||
if '兑换成功' in response.text:
|
||||
printn(f"{Color.MINT}🎉 恭喜呀!{get_first_three(phone)} 兑换成功啦!🎉")
|
||||
dhjl[yf]['等级话费'] += "#" + phone
|
||||
with open('电信金豆换话费.log', 'w') as f:
|
||||
json.dump(dhjl, f, ensure_ascii=False)
|
||||
return
|
||||
elif '已兑换' in response.text:
|
||||
printn(f"💖 {get_first_three(phone)} 已经兑换过咯~")
|
||||
dhjl[yf]['等级话费'] += "#" + phone
|
||||
with open('电信金豆换话费.log', 'w') as f:
|
||||
json.dump(dhjl, f, ensure_ascii=False)
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
printn(f"💔 {get_first_three(phone)} 兑换时出错了: {str(e)}")
|
||||
|
||||
|
||||
async def getLevelRightsList(phone, session, accId):
|
||||
try:
|
||||
value = {
|
||||
"type": "hg_qd_djqydh",
|
||||
"accId": accId,
|
||||
"shopId": "20001"
|
||||
}
|
||||
paraV = encrypt_para(value)
|
||||
|
||||
response = session.post(
|
||||
'https://wappark.189.cn/jt-sign/paradise/queryLevelRightInfo',
|
||||
json={"para": paraV}
|
||||
)
|
||||
|
||||
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:
|
||||
paraV = encrypt_para(value)
|
||||
response = session.post(
|
||||
'https://wappark.189.cn/jt-sign/paradise/queryLevelRightInfo',
|
||||
json={"para": paraV}
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
|
||||
async def getSign(ticket, session):
|
||||
try:
|
||||
response = session.get(
|
||||
'https://wappark.189.cn/jt-sign/ssoHomLogin?ticket=' + ticket,
|
||||
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, None
|
||||
|
||||
|
||||
async def qgNight(phone, ticket, timeDiff, isTrue):
|
||||
if isTrue:
|
||||
runTime = run_Time(23, 58, 30)
|
||||
else:
|
||||
runTime = 0
|
||||
|
||||
if runTime > (time.time() + timeDiff):
|
||||
difftime = runTime - time.time() - timeDiff
|
||||
print(f"⏰ 当前时间: {str(datetime.datetime.now())[11:23]}, 要等一会儿哦~ 还要等 {difftime:.2f} 秒")
|
||||
await asyncio.sleep(difftime)
|
||||
|
||||
session = requests.Session()
|
||||
session.mount('https://', DESAdapter())
|
||||
session.verify = False # 禁用证书验证
|
||||
sign, accId = await getSign(ticket, session)
|
||||
|
||||
if 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}
|
||||
printn(f"{get_first_three(phone)} 获取到sign啦~ 太好了!😊")
|
||||
else:
|
||||
print(f"{get_first_three(phone)} 💔 没有获取到sign呢...")
|
||||
return
|
||||
|
||||
rightsId = await getLevelRightsList(phone, session, accId)
|
||||
if rightsId:
|
||||
printn(f"{get_first_three(phone)} 找到rightsId了: {rightsId[0]} 🌟")
|
||||
else:
|
||||
print(f"{get_first_three(phone)} 💔 没找到rightsId呢...")
|
||||
return
|
||||
|
||||
if isTrue:
|
||||
runTime2 = run_Time(23, 59, 59) + 0.5
|
||||
difftime = runTime2 - time.time() - timeDiff
|
||||
printn(f"再等 {difftime:.2f} 秒就开始啦~ ⏳")
|
||||
await asyncio.sleep(difftime)
|
||||
else:
|
||||
# 测试模式:不等待,直接执行
|
||||
printn(f"测试模式,执行兑换测试~ 🧪")
|
||||
|
||||
await exchangeForDay(phone, session, run_num, rightsId[0], 0.05, accId)
|
||||
|
||||
|
||||
async def qgDay(phone, ticket, timeDiff, isTrue):
|
||||
async with AsyncSessionManager() as s:
|
||||
pass
|
||||
|
||||
|
||||
async def main(timeDiff, isTRUE, hour):
|
||||
print(LOGO)
|
||||
print(f"✨ 脚本启动中~ 准备开始兑换话费啦!✨\n")
|
||||
|
||||
tasks = []
|
||||
accounts = []
|
||||
for key, value in os.environ.items():
|
||||
if key == 'chinaTelecomAccount':
|
||||
accounts.extend(re.split(r'@|&',value))
|
||||
if not accounts:
|
||||
print(f"💔 错误: 没有设置 chinaTelecomAccount 环境变量哦~ 要写成 账号#密码 的格式呀 多账号用@分开~")
|
||||
return
|
||||
account_count = len(accounts)
|
||||
print(f"💖 发现 {len(accounts)} 个账号呢,准备开始处理啦~")
|
||||
|
||||
for phoneV in accounts:
|
||||
value = phoneV.split('#')
|
||||
if len(value) != 2:
|
||||
print(f"💔 跳过无效格式: {phoneV},要写成 账号#密码 哦 多账号用@分开~")
|
||||
continue
|
||||
|
||||
phone, password = value[0], value[1]
|
||||
if '等级话费' not in dhjl[yf]:
|
||||
dhjl[yf]['等级话费'] = ""
|
||||
if phone in dhjl[yf]['等级话费']:
|
||||
printn(f"{get_first_three(phone)} 的等级话费已经兑换过啦~ 不用再弄咯~ 💖")
|
||||
continue
|
||||
|
||||
printn(f'{get_first_three(phone)} 开始登录啦~ 🌸')
|
||||
ticket = userLoginNormal(phone, password)
|
||||
if ticket:
|
||||
printn(f'{get_first_three(phone)} 登录成功!太棒啦!🎉')
|
||||
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)} 登录失败了... 有点小伤心呢 💔')
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
h = datetime.datetime.now().hour
|
||||
print(f"⏰ 当前时间是 {h} 点哦~")
|
||||
|
||||
if 10 > h > 0:
|
||||
print(f"☀️ 现在是 {h} 点,准备抢十点场次的话费啦~")
|
||||
wttime = run_Time(9, 59, 8) # 抢十点场次
|
||||
elif 14 >= h >= 10:
|
||||
print(f"☀️ 现在是 {h} 点,准备抢十四点场次的话费啦~")
|
||||
wttime = run_Time(13, 59, 8) # 抢十四点场次
|
||||
else:
|
||||
print(f"🌙 现在是 {h} 点,准备抢凌晨场次的话费啦~")
|
||||
wttime = run_Time(23, 57, 57) # 抢凌晨场次
|
||||
|
||||
isTRUE = True # 实际用的时候设为True,测试的时候可以设为False哦
|
||||
|
||||
if wttime > time.time():
|
||||
wTime = wttime - time.time()
|
||||
print(f"⏳ 还要等 {wTime:.2f} 秒才到时间呢~ 耐心等一下下哦~")
|
||||
if isTRUE:
|
||||
print(f"💡 小贴士: 记得先测试一下哦~ 要根据自己的网络调整参数呢~")
|
||||
print(f"💤 开始等待啦... 不要关掉窗口哦~")
|
||||
time.sleep(wTime)
|
||||
|
||||
timeValue = 0 # 时间获取
|
||||
timeDiff = timeValue if timeValue > 0 else 0
|
||||
|
||||
try:
|
||||
asyncio.run(main(timeDiff, isTRUE, h))
|
||||
except Exception as e:
|
||||
print(f"💔 脚本运行的时候出错了: {str(e)}")
|
||||
finally:
|
||||
print(f"\n💖 所有任务都完成啦~ 💖")
|
||||
255
电信/Ruishu.py
Normal file
255
电信/Ruishu.py
Normal file
@@ -0,0 +1,255 @@
|
||||
import os
|
||||
import ssl
|
||||
import time
|
||||
import json
|
||||
import execjs
|
||||
import base64
|
||||
import random
|
||||
import certifi
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import requests
|
||||
from http import cookiejar
|
||||
from Crypto.Cipher import DES3
|
||||
from Crypto.Util.Padding import pad, unpad
|
||||
from aiohttp import ClientSession, TCPConnector
|
||||
import httpx
|
||||
httpx._config.DEFAULT_CIPHERS += ":ALL:@SECLEVEL=1"
|
||||
diffValue = 2
|
||||
filename='Cache.js'
|
||||
if os.path.exists(filename):
|
||||
with open(filename, 'r', encoding='utf-8') as file:
|
||||
fileContent = file.read()
|
||||
else:
|
||||
fileContent=''
|
||||
|
||||
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}')
|
||||
|
||||
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.DEFAULT_RETRIES = 0
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
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
|
||||
sleepTime = 1
|
||||
key = b'1234567`90koiuyhgtfrdews'
|
||||
iv = 8 * b'\0'
|
||||
|
||||
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 initCookie(getUrl='https://wapact.189.cn:9001/gateway/standQuery/detailNew/exchange'):
|
||||
global js_code_ym, fileContent
|
||||
cookie = ''
|
||||
response = httpx.post(getUrl)
|
||||
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 = httpx.get(rsurl)
|
||||
fileContent = fileRes.text
|
||||
if fileRes.status_code == 200:
|
||||
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]
|
||||
runJs = js_code_ym.replace('content_code', content).replace("'ts_code'", code1Content + fileContent)
|
||||
execjsRun = RefererCookie(runJs)
|
||||
return {
|
||||
'cookie': cookie,
|
||||
'execjsRun': execjsRun
|
||||
}
|
||||
|
||||
def RefererCookie(runJs):
|
||||
try:
|
||||
execjsRun = execjs.compile(runJs)
|
||||
return execjsRun
|
||||
except execjs._exceptions.CompileError as e:
|
||||
print(f"JavaScript 编译错误: {e}")
|
||||
except execjs._exceptions.RuntimeError as e:
|
||||
print(f"JavaScript 运行时错误: {e}")
|
||||
except Exception as e:
|
||||
print(f"其他错误: {e}")
|
||||
|
||||
js_code_ym = '''delete __filename
|
||||
delete __dirname
|
||||
ActiveXObject = undefined
|
||||
|
||||
window = global;
|
||||
|
||||
content="content_code"
|
||||
|
||||
navigator = {"platform": "Linux aarch64"}
|
||||
navigator = {"userAgent": "CtClient;11.0.0;Android;13;22081212C;NTIyMTcw!#!MTUzNzY"}
|
||||
|
||||
location={
|
||||
"href": "https://",
|
||||
"origin": "",
|
||||
"protocol": "",
|
||||
"host": "",
|
||||
"hostname": "",
|
||||
"port": "",
|
||||
"pathname": "",
|
||||
"search": "",
|
||||
"hash": ""
|
||||
}
|
||||
|
||||
i = {length: 0}
|
||||
base = {length: 0}
|
||||
div = {
|
||||
getElementsByTagName: function (res) {
|
||||
console.log('div中的getElementsByTagName:', res)
|
||||
if (res === 'i') {
|
||||
return i
|
||||
}
|
||||
return '<div></div>'
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
script = {
|
||||
|
||||
}
|
||||
meta = [
|
||||
{charset:"UTF-8"},
|
||||
{
|
||||
content: content,
|
||||
getAttribute: function (res) {
|
||||
console.log('meta中的getAttribute:', res)
|
||||
if (res === 'r') {
|
||||
return 'm'
|
||||
}
|
||||
},
|
||||
parentNode: {
|
||||
removeChild: function (res) {
|
||||
console.log('meta中的removeChild:', res)
|
||||
|
||||
return content
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
]
|
||||
form = '<form></form>'
|
||||
|
||||
window.addEventListener= function (res) {
|
||||
console.log('window中的addEventListener:', res)
|
||||
|
||||
}
|
||||
|
||||
document = {
|
||||
createElement: function (res) {
|
||||
console.log('document中的createElement:', res)
|
||||
|
||||
if (res === 'div') {
|
||||
return div
|
||||
} else if (res === 'form') {
|
||||
return form
|
||||
}
|
||||
else{return res}
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
addEventListener: function (res) {
|
||||
console.log('document中的addEventListener:', res)
|
||||
|
||||
},
|
||||
appendChild: function (res) {
|
||||
console.log('document中的appendChild:', res)
|
||||
return res
|
||||
},
|
||||
removeChild: function (res) {
|
||||
console.log('document中的removeChild:', res)
|
||||
},
|
||||
getElementsByTagName: function (res) {
|
||||
console.log('document中的getElementsByTagName:', res)
|
||||
if (res === 'script') {
|
||||
return script
|
||||
}
|
||||
if (res === 'meta') {
|
||||
return meta
|
||||
}
|
||||
if (res === 'base') {
|
||||
return base
|
||||
}
|
||||
},
|
||||
getElementById: function (res) {
|
||||
console.log('document中的getElementById:', res)
|
||||
if (res === 'root-hammerhead-shadow-ui') {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setInterval = function () {}
|
||||
setTimeout = function () {}
|
||||
window.top = window
|
||||
|
||||
'ts_code'
|
||||
|
||||
function main() {
|
||||
cookie = document.cookie.split(';')[0]
|
||||
return cookie
|
||||
}'''
|
||||
|
||||
async def main(timeValue):
|
||||
global runTime, js_codeRead
|
||||
tasks = []
|
||||
|
||||
init_result = initCookie()
|
||||
if init_result:
|
||||
cookie = init_result['cookie']
|
||||
execjsRun = init_result['execjsRun']
|
||||
else:
|
||||
print("初始化 cookies 失败")
|
||||
return
|
||||
|
||||
runcookie = {
|
||||
'cookie': cookie,
|
||||
'execjsRun': execjsRun
|
||||
}
|
||||
|
||||
# 添加输出 cookies 的代码
|
||||
cookies = {
|
||||
'yiUIIlbdQT3fO': runcookie['cookie'],
|
||||
'yiUIIlbdQT3fP': runcookie['execjsRun'].call('main').split('=')[1]
|
||||
}
|
||||
print(json.dumps(cookies)) # 确保输出是 JSON 格式的
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main(0))
|
||||
205
电信/ruishucookie.py
Normal file
205
电信/ruishucookie.py
Normal file
@@ -0,0 +1,205 @@
|
||||
# ruishucookie.py
|
||||
import os
|
||||
import execjs
|
||||
import httpx
|
||||
httpx._config.DEFAULT_CIPHERS += ":ALL:@SECLEVEL=1"
|
||||
|
||||
|
||||
|
||||
filename = 'Cache.js'
|
||||
if os.path.exists(filename):
|
||||
with open(filename, 'r', encoding='utf-8') as file:
|
||||
fileContent = file.read()
|
||||
else:
|
||||
fileContent = ''
|
||||
|
||||
def initCookie(getUrl='https://wapact.189.cn:9001/gateway/standQuery/detailNew/exchange'):
|
||||
global js_code_ym, fileContent
|
||||
cookie = ''
|
||||
response = httpx.post(getUrl)
|
||||
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 = httpx.get(rsurl)
|
||||
fileContent = fileRes.text
|
||||
if fileRes.status_code == 200:
|
||||
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]
|
||||
runJs = js_code_ym.replace('content_code', content).replace("'ts_code'", code1Content + fileContent)
|
||||
execjsRun = RefererCookie(runJs)
|
||||
|
||||
# 将 cookies 转换为字符串格式
|
||||
cookies_str = f"yiUIIlbdQT3fO={cookie}; yiUIIlbdQT3fP={execjsRun.call('main').split('=')[1]}"
|
||||
return cookies_str
|
||||
|
||||
def RefererCookie(runJs):
|
||||
try:
|
||||
execjsRun = execjs.compile(runJs)
|
||||
return execjsRun
|
||||
except execjs._exceptions.CompileError as e:
|
||||
print(f"JavaScript 编译错误: {e}")
|
||||
except execjs._exceptions.RuntimeError as e:
|
||||
print(f"JavaScript 运行时错误: {e}")
|
||||
except Exception as e:
|
||||
print(f"其他错误: {e}")
|
||||
|
||||
js_code_ym = '''delete __filename
|
||||
delete __dirname
|
||||
ActiveXObject = undefined
|
||||
|
||||
window = global;
|
||||
|
||||
content="content_code"
|
||||
|
||||
navigator = {"platform": "Linux aarch64"}
|
||||
navigator = {"userAgent": "CtClient;11.0.0;Android;13;22081212C;NTIyMTcw!#!MTUzNzY"}
|
||||
|
||||
location={
|
||||
"href": "https://",
|
||||
"origin": "",
|
||||
"protocol": "",
|
||||
"host": "",
|
||||
"hostname": "",
|
||||
"port": "",
|
||||
"pathname": "",
|
||||
"search": "",
|
||||
"hash": ""
|
||||
}
|
||||
|
||||
i = {length: 0}
|
||||
base = {length: 0}
|
||||
div = {
|
||||
getElementsByTagName: function (res) {
|
||||
console.log('div中的getElementsByTagName:', res)
|
||||
if (res === 'i') {
|
||||
return i
|
||||
}
|
||||
return '<div></div>'
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
script = {
|
||||
|
||||
}
|
||||
meta = [
|
||||
{charset:"UTF-8"},
|
||||
{
|
||||
content: content,
|
||||
getAttribute: function (res) {
|
||||
console.log('meta中的getAttribute:', res)
|
||||
if (res === 'r') {
|
||||
return 'm'
|
||||
}
|
||||
},
|
||||
parentNode: {
|
||||
removeChild: function (res) {
|
||||
console.log('meta中的removeChild:', res)
|
||||
|
||||
return content
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
]
|
||||
form = '<form></form>'
|
||||
|
||||
window.addEventListener= function (res) {
|
||||
console.log('window中的addEventListener:', res)
|
||||
|
||||
}
|
||||
|
||||
document = {
|
||||
createElement: function (res) {
|
||||
console.log('document中的createElement:', res)
|
||||
|
||||
if (res === 'div') {
|
||||
return div
|
||||
} else if (res === 'form') {
|
||||
return form
|
||||
}
|
||||
else{return res}
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
addEventListener: function (res) {
|
||||
console.log('document中的addEventListener:', res)
|
||||
|
||||
},
|
||||
appendChild: function (res) {
|
||||
console.log('document中的appendChild:', res)
|
||||
return res
|
||||
},
|
||||
removeChild: function (res) {
|
||||
console.log('document中的removeChild:', res)
|
||||
},
|
||||
getElementsByTagName: function (res) {
|
||||
console.log('document中的getElementsByTagName:', res)
|
||||
if (res === 'script') {
|
||||
return script
|
||||
}
|
||||
if (res === 'meta') {
|
||||
return meta
|
||||
}
|
||||
if (res === 'base') {
|
||||
return base
|
||||
}
|
||||
},
|
||||
getElementById: function (res) {
|
||||
console.log('document中的getElementById:', res)
|
||||
if (res === 'root-hammerhead-shadow-ui') {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setInterval = function () {}
|
||||
setTimeout = function () {}
|
||||
window.top = window
|
||||
|
||||
'ts_code'
|
||||
|
||||
function main() {
|
||||
cookie = document.cookie.split(';')[0]
|
||||
return cookie
|
||||
}'''
|
||||
|
||||
async def main(timeValue):
|
||||
global runTime, js_codeRead
|
||||
tasks = []
|
||||
|
||||
init_result = initCookie()
|
||||
if init_result:
|
||||
cookie = init_result['cookie']
|
||||
execjsRun = init_result['execjsRun']
|
||||
else:
|
||||
print("初始化 cookies 失败")
|
||||
return
|
||||
|
||||
runcookie = {
|
||||
'cookie': cookie,
|
||||
'execjsRun': execjsRun
|
||||
}
|
||||
|
||||
# 添加输出 cookies 的代码
|
||||
cookies = {
|
||||
'yiUIIlbdQT3fO': runcookie['cookie'],
|
||||
'yiUIIlbdQT3fP': runcookie['execjsRun'].call('main').split('=')[1]
|
||||
}
|
||||
print(f"Cookies: {cookies}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main(0))
|
||||
139
电信/瑞数通杀.js
Normal file
139
电信/瑞数通杀.js
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
|
||||
const $ = new Env("瑞数通杀");
|
||||
|
||||
*/
|
||||
delete __filename
|
||||
delete __dirname
|
||||
ActiveXObject = undefined
|
||||
|
||||
window = global;
|
||||
|
||||
|
||||
content="content_code"
|
||||
|
||||
|
||||
navigator = {"platform": "Linux aarch64"}
|
||||
navigator = {"userAgent": "CtClient;11.0.0;Android;13;22081212C;NTIyMTcw!#!MTUzNzY"}
|
||||
|
||||
location={
|
||||
"href": "https://",
|
||||
"origin": "",
|
||||
"protocol": "",
|
||||
"host": "",
|
||||
"hostname": "",
|
||||
"port": "",
|
||||
"pathname": "",
|
||||
"search": "",
|
||||
"hash": ""
|
||||
}
|
||||
|
||||
i = {length: 0}
|
||||
base = {length: 0}
|
||||
div = {
|
||||
getElementsByTagName: function (res) {
|
||||
console.log('div中的getElementsByTagName:', res)
|
||||
if (res === 'i') {
|
||||
return i
|
||||
}
|
||||
return '<div></div>'
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
script = {
|
||||
|
||||
}
|
||||
meta = [
|
||||
{charset:"UTF-8"},
|
||||
{
|
||||
content: content,
|
||||
getAttribute: function (res) {
|
||||
console.log('meta中的getAttribute:', res)
|
||||
if (res === 'r') {
|
||||
return 'm'
|
||||
}
|
||||
},
|
||||
parentNode: {
|
||||
removeChild: function (res) {
|
||||
console.log('meta中的removeChild:', res)
|
||||
|
||||
return content
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
]
|
||||
form = '<form></form>'
|
||||
|
||||
|
||||
window.addEventListener= function (res) {
|
||||
console.log('window中的addEventListener:', res)
|
||||
|
||||
}
|
||||
|
||||
|
||||
document = {
|
||||
|
||||
|
||||
createElement: function (res) {
|
||||
console.log('document中的createElement:', res)
|
||||
|
||||
|
||||
if (res === 'div') {
|
||||
return div
|
||||
} else if (res === 'form') {
|
||||
return form
|
||||
}
|
||||
else{return res}
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
addEventListener: function (res) {
|
||||
console.log('document中的addEventListener:', res)
|
||||
|
||||
},
|
||||
appendChild: function (res) {
|
||||
console.log('document中的appendChild:', res)
|
||||
return res
|
||||
},
|
||||
removeChild: function (res) {
|
||||
console.log('document中的removeChild:', res)
|
||||
},
|
||||
getElementsByTagName: function (res) {
|
||||
console.log('document中的getElementsByTagName:', res)
|
||||
if (res === 'script') {
|
||||
return script
|
||||
}
|
||||
if (res === 'meta') {
|
||||
return meta
|
||||
}
|
||||
if (res === 'base') {
|
||||
return base
|
||||
}
|
||||
},
|
||||
getElementById: function (res) {
|
||||
console.log('document中的getElementById:', res)
|
||||
if (res === 'root-hammerhead-shadow-ui') {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setInterval = function () {}
|
||||
setTimeout = function () {}
|
||||
window.top = window
|
||||
|
||||
|
||||
'ts_code'
|
||||
|
||||
|
||||
|
||||
function main() {
|
||||
cookie = document.cookie.split(';')[0]
|
||||
return cookie
|
||||
}
|
||||
|
||||
2569
电信/电信营业厅.js
Normal file
2569
电信/电信营业厅.js
Normal file
File diff suppressed because it is too large
Load Diff
2569
电信/电信营业厅不带喂食.js
Normal file
2569
电信/电信营业厅不带喂食.js
Normal file
File diff suppressed because it is too large
Load Diff
688
电信/话费兑换.py
Normal file
688
电信/话费兑换.py
Normal file
@@ -0,0 +1,688 @@
|
||||
"""
|
||||
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 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.Cipher import AES
|
||||
from http import 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)
|
||||
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, 10, 30)
|
||||
afternoon_start = datetime.time(13, 30, 3)
|
||||
afternoon_end = datetime.time(14, 10, 30)
|
||||
|
||||
# 获取当前时间
|
||||
now = get_network_time().time()
|
||||
|
||||
# 判断当前时间是否在指定的时间段内
|
||||
if (morning_start <= now <= morning_end) or (afternoon_start <= now <= afternoon_end):
|
||||
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")
|
||||
|
||||
# 新增:从环境变量获取外层循环次数,默认20次
|
||||
OUTER_LOOP_COUNT = int(os.getenv("OUTER_LOOP_COUNT", "20"))
|
||||
|
||||
INNER_LOOP_COUNT = int(os.getenv("INNER_LOOP_COUNT", "10"))
|
||||
|
||||
|
||||
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")
|
||||
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] = {}
|
||||
else:
|
||||
# 将现有字符串记录转换为集合(仅首次加载时执行)
|
||||
for di in dhjl[yf]:
|
||||
if isinstance(dhjl[yf][di], str):
|
||||
# 拆分字符串为列表,去重后转为集合
|
||||
phone_list = dhjl[yf][di].strip('#').split('#') if dhjl[yf][di] else []
|
||||
dhjl[yf][di] = set(phone_list)
|
||||
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分钟可兑换此奖品📶",
|
||||
"Y0003": "共享流量400M可兑换此奖品💧",
|
||||
"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())
|
||||
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_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")
|
||||
uid = os.getenv("WXPUSHER_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": "#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)}}}).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']
|
||||
|
||||
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
|
||||
return decrypt(tk[0])
|
||||
|
||||
|
||||
async def exchange(phone, s, title, aid, uid, amount):
|
||||
global h
|
||||
masked_phone = phone[:3] + '****' + phone[-4:]
|
||||
try:
|
||||
tt = time_module.time()
|
||||
start_time = time_module.time()
|
||||
end_time = time_module.time()
|
||||
#print_time_log(f"📱{masked_phone} 准备兑换 {title} 啦~ ⏳用时: {end_time - start_time:.3f} 秒")
|
||||
|
||||
now = get_network_time()
|
||||
if h is None:
|
||||
h = now.hour
|
||||
|
||||
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()
|
||||
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, 10, 5)
|
||||
afternoon_start = datetime.time(13, 30, 40)
|
||||
afternoon_end = datetime.time(14, 10, 5)
|
||||
current_time = now.time()
|
||||
|
||||
proxy = None
|
||||
#if (morning_start <= current_time <= morning_end) or (afternoon_start <= current_time <= afternoon_end):
|
||||
#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} 用本地网络哦~ 📶")
|
||||
#else:
|
||||
#print_time_log(f"📱{masked_phone} 用本地网络啦~ 📶")
|
||||
#else:
|
||||
#print_time_log(f"📱{masked_phone} 用本地网络哦~ 📶")
|
||||
|
||||
#if h == 9:
|
||||
#second_target_time = now.replace(hour=h, minute=59, second=56, microsecond=803600)
|
||||
#elif h == 13:
|
||||
#second_target_time = now.replace(hour=h, minute=59, second=56, microsecond=793600)
|
||||
|
||||
#second_time_diff = (second_target_time - get_network_time()).total_seconds()
|
||||
#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} 正在用本地网络~")
|
||||
|
||||
url = "https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange"
|
||||
request_start_time = datetime.datetime.now()
|
||||
|
||||
async with s.post(url, json={"activityId": aid}, 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].add(phone)
|
||||
with open('电信金豆换话费.log', 'w') as f:
|
||||
temp_dhjl = {k: {m: list(n) for m, n in v.items()} for k, v in dhjl.items()}
|
||||
json.dump(temp_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}")
|
||||
|
||||
|
||||
async def dh(phone, s, title, aid, wt, uid):
|
||||
global h
|
||||
masked_phone = phone[:3] + '****' + phone[-4:]
|
||||
print_time_log(f"📱{masked_phone} 💕{title} 开始兑换咯~")
|
||||
cs = 0
|
||||
tasks = []
|
||||
creat_start_time = datetime.datetime.now()
|
||||
# 每个账号10次兑换循环
|
||||
while cs < INNER_LOOP_COUNT:
|
||||
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.3)
|
||||
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字节哦~")
|
||||
|
||||
padded_data = pad(plaintext.encode('utf-8'), AES.block_size)
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
ciphertext = cipher.encrypt(padded_data)
|
||||
return base64.b64encode(ciphertext).decode('utf-8')
|
||||
|
||||
|
||||
async def ks(phone, ticket, uid):
|
||||
global h, wt
|
||||
masked_phone = phone[:3] + '****' + phone[-4:]
|
||||
print_time_log(f"📱{masked_phone} 准备开始兑换流程啦~")
|
||||
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:
|
||||
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} 登录失败,重新尝试~")
|
||||
return await ks(phone, ticket, uid)
|
||||
else:
|
||||
print_time_log(f"📱{masked_phone} 登录请求失败,状态码: {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} 登录失败,重新尝试~")
|
||||
return await ks(phone, ticket, uid)
|
||||
|
||||
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
|
||||
# 优化后:提前过滤,仅保留未兑换的商品
|
||||
valid_products = []
|
||||
for di in sorted(d.keys(), key=lambda x: float(x.replace('元话费', '')), reverse=True):
|
||||
if phone not in dhjl[yf].get(di, set()): # 用集合快速判断
|
||||
valid_products.append(di)
|
||||
# 新增:外层循环控制
|
||||
for loop in range(OUTER_LOOP_COUNT):
|
||||
print_time_log(f"📱{masked_phone} 开始第 {loop + 1}/{OUTER_LOOP_COUNT} 轮兑换")
|
||||
tasks = []
|
||||
for di in valid_products:
|
||||
if wt - time_module.time() > 30 * 60:
|
||||
print_time_log(f"等待太久啦,退出咯~")
|
||||
return
|
||||
tasks.append(dh(phone, s, di, d[di], wt, uid))
|
||||
print_time_log(f"📱{masked_phone} 第 {loop + 1} 轮共有【{len(tasks)}】个兑换任务哦~")
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
# 轮次之间休息3秒,避免请求过于频繁
|
||||
if loop < OUTER_LOOP_COUNT - 1:
|
||||
await asyncio.sleep(0.01)
|
||||
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
|
||||
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)
|
||||
rs = 0
|
||||
accounts = []
|
||||
for key, value in os.environ.items():
|
||||
if key == 'chinaTelecomAccount':
|
||||
accounts.extend(re.split(r'@|&',value))
|
||||
if not accounts:
|
||||
print("没有检测到账号哦~")
|
||||
return
|
||||
account_count = len(accounts)
|
||||
print_time_log(f"💖检测到 【{account_count}】 个账号")
|
||||
print_time_log(f"💖外层兑换循环次数: 【{OUTER_LOOP_COUNT}】 次")
|
||||
|
||||
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)
|
||||
|
||||
|
||||
START_LOG = rf'''
|
||||
+--------------------------------------------------------------------+
|
||||
| 🌸 欢迎使用 金豆兑换话费 ✨
|
||||
+--------------------------------------------------------------------+
|
||||
'''
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(START_LOG)
|
||||
print(f"💌 提醒:程序会提前【{kswt} 秒】准备好哦~")
|
||||
if len(sys.argv) > 1:
|
||||
h = int(sys.argv[1])
|
||||
else:
|
||||
h = 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():
|
||||
if isinstance(phones, list):
|
||||
phone_list = phones
|
||||
else:
|
||||
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)
|
||||
|
||||
current_time = get_network_time()
|
||||
start_time_1 = current_time.replace(hour=10, minute=0, second=30)
|
||||
end_time_1 = current_time.replace(hour=10, minute=10, second=0)
|
||||
start_time_2 = current_time.replace(hour=14, minute=0, second=30)
|
||||
end_time_2 = current_time.replace(hour=14, minute=10, second=0)
|
||||
|
||||
if (start_time_1 <= current_time < end_time_1) or (start_time_2 <= current_time < end_time_2):
|
||||
print("任务执行完成~")
|
||||
else:
|
||||
print("当前不在推送时间哦~")
|
||||
Reference in New Issue
Block a user