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