diff --git a/chinatelecom.py b/chinatelecom.py
index bb1e0d7..34da1b9 100644
--- a/chinatelecom.py
+++ b/chinatelecom.py
@@ -1,118 +1,127 @@
-# !/usr/bin/python3
-# -- coding: utf-8 --
-# cron: 53 59 09,13 * * *
-# const $ = new Env("电信金豆换话费");
-import requests
+"""
+新电信抢话费
+
+群里发的,未测试好,自测
+修改内容如下“
+1.删除内置的一个手机账号
+2.修改环境变量名保持和拉菲电信金豆本环境变量一致
+3.恢复瑞数通杀.js调用地址,确实也不知道是啥。398、399行注释
+
+环境变量chinaTelecomAccount,值为:账号#密码
+
+cron: 57 9,13,23 * * *
+const $ = new Env("新电信抢话费");
+
+"""
+#!/usr/bin/env python3
+import os
import re
+import sys
+import ssl
import time
import json
-import random
-import datetime
-import base64
-import threading
-import ssl
import execjs
-import os
-import sys
-
-from bs4 import BeautifulSoup
-
+import base64
+import random
+import certifi
+import aiohttp
+import asyncio
+import certifi
+import datetime
+import requests
+import binascii
+from lxml import etree
+from http import cookiejar
+from Crypto.Cipher import AES
+from Crypto.Cipher import DES3
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
-from Crypto.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
+from aiohttp import ClientSession, TCPConnector
+from concurrent.futures import ThreadPoolExecutor
+import subprocess
+
+run_num=os.environ.get('reqNUM') or "2"
+
+MAX_RETRIES = 3
+RATE_LIMIT = 10 # 每秒请求数限制
+
+class RateLimiter:
+ def __init__(self, rate_limit):
+ self.rate_limit = rate_limit
+ self.tokens = rate_limit
+ self.updated_at = time.monotonic()
+
+ async def acquire(self):
+ while self.tokens < 1:
+ self.add_new_tokens()
+ await asyncio.sleep(0.1)
+ self.tokens -= 1
+
+ def add_new_tokens(self):
+ now = time.monotonic()
+ time_since_update = now - self.updated_at
+ new_tokens = time_since_update * self.rate_limit
+ if new_tokens > 1:
+ self.tokens = min(self.tokens + new_tokens, self.rate_limit)
+ self.updated_at = now
+
+class AsyncSessionManager:
+ def __init__(self):
+ self.session = None
+ self.connector = None
+
+ async def __aenter__(self):
+ ssl_context = ssl.create_default_context(cafile=certifi.where())
+ ssl_context.set_ciphers('DEFAULT@SECLEVEL=1')
+ self.connector = TCPConnector(ssl=ssl_context, limit=1000)
+ self.session = ClientSession(connector=self.connector)
+ return self.session
+
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
+ await self.session.close()
+ await self.connector.close()
+
+async def retry_request(session, method, url, **kwargs):
+ for attempt in range(MAX_RETRIES):
+ try:
+ await asyncio.sleep(1)
+ async with session.request(method, url, **kwargs) as response:
+ return await response.json()
+ # return await response.json()
+
+ except (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError) as e:
+ print(f"请求失败,第 {attempt + 1} 次重试: {e}")
+ if attempt == MAX_RETRIES - 1:
+ raise
+ await asyncio.sleep(2 ** attempt)
class BlockAll(cookiejar.CookiePolicy):
return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: False
netscape = True
rfc2965 = hide_cookie2 = False
-
-def printn(m):
- print(f'\n{m}')
-ORIGIN_CIPHERS = ('DEFAULT@SECLEVEL=1')
-ip_list = []
-class DESAdapter(HTTPAdapter):
- def __init__(self, *args, **kwargs):
- """
- A TransportAdapter that re-enables 3DES support in Requests.
- """
- CIPHERS = ORIGIN_CIPHERS.split(':')
- random.shuffle(CIPHERS)
- CIPHERS = ':'.join(CIPHERS)
- self.CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'
- super().__init__(*args, **kwargs)
-
+def 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):
- context = create_urllib3_context(ciphers=self.CIPHERS)
kwargs['ssl_context'] = context
- return super(DESAdapter, self).init_poolmanager(*args, **kwargs)
-
- def proxy_manager_for(self, *args, **kwargs):
- context = create_urllib3_context(ciphers=self.CIPHERS)
- kwargs['ssl_context'] = context
- return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)
-
+ return super().init_poolmanager(*args, **kwargs)
requests.packages.urllib3.disable_warnings()
-ssl_context = ssl.create_default_context()
-ssl_context.check_hostname = False
-ssl_context.verify_mode = ssl.CERT_NONE
-ssl_context.set_ciphers('DEFAULT@SECLEVEL=0')
+# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
ss = requests.session()
-ss.ssl=ssl_context
-ss.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","Referer":"https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"}
-ss.mount('https://', DESAdapter())
-yc = 0.1
-wt = 0
-kswt = -3
-yf = datetime.datetime.now().strftime("%Y%m")
-
-
-jp = {"9":{},"12":{},"13":{},"23":{}}
-
-
-try:
- with open('telecom_doudou.log') as fr:
- dhjl = json.load(fr)
-except:
- dhjl = {}
-if yf not in dhjl:
- dhjl[yf] = {}
-
-
-
-
-wxp={}
-errcode = {
- "0":"兑换成功",
- "412":"兑换次数已达上限",
- "413":"商品已兑完",
- "420":"未知错误",
- "410":"该活动已失效~",
- "Y0001":"当前等级不足,去升级兑当前话费",
- "Y0002":"使用翼相连网络600分钟或连接并拓展网络500分钟可兑换此奖品",
- "Y0003":"使用翼相连共享流量400M或共享WIFI:2GB可兑换此奖品",
- "Y0004":"使用翼相连共享流量2GB可兑换此奖品",
- "Y0005":"当前等级不足,去升级兑当前话费",
- "E0001":"您的网龄不足10年,暂不能兑换"
-}
-
-
-
-
-
-
-
-
-
-
-#加密参数
+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'
@@ -124,16 +133,22 @@ public_key_data = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+ugG5A8cZ3FqUKDwM57GM4io6JGcStivT8UdGt67PEOihLZTw3P7371+N47PrmsCpnTRzbTgcupKtUv8ImZalYk65dU8rjC/ridwhw9ffW2LBwvkEnDkkKKRi2liWIItDftJVBiWOh17o6gfbPoNrWORcAdcbpk2L+udld5kZNwIDAQAB
-----END PUBLIC KEY-----'''
+def get_first_three(value):
+ # 处理数字情况
+ if isinstance(value, (int, float)):
+ return int(str(value)[:3])
+ elif isinstance(value, str):
+ return str(value)[:3]
+ else:
+ raise TypeError("error")
-def t(h):
+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=h, minute=59, second=59)
+ 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):
+def encrypt(text):
cipher = DES3.new(key, DES3.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(text.encode(), DES3.block_size))
return ciphertext.hex()
@@ -143,348 +158,322 @@ def decrypt(text):
cipher = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), DES3.block_size)
return plaintext.decode()
-
-
-
+
def b64(plaintext):
public_key = RSA.import_key(public_key_b64)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
return base64.b64encode(ciphertext).decode()
-
+
def encrypt_para(plaintext):
+ if not isinstance(plaintext, str):
+ plaintext = json.dumps(plaintext)
public_key = RSA.import_key(public_key_data)
cipher = PKCS1_v1_5.new(public_key)
ciphertext = cipher.encrypt(plaintext.encode())
- return ciphertext.hex()
-
-
+ 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 ophone(t):
- key = b'34d7cb0bcdf07523'
- utf8_key = key.decode('utf-8')
- utf8_t = t.encode('utf-8')
- cipher = AES.new(key, AES.MODE_ECB)
- ciphertext = cipher.encrypt(pad(utf8_t, AES.block_size))
- return ciphertext.hex()
-def send(uid,content):
- r = requests.post('https://wxpusher.zjiecode.com/api/send/message',json={"appToken":"AT_3hr0wdZn5QzPNBbpTHFXawoDIsSUmPkN","content":content,"contentType":1,"uids":[uid]}).json()
- return r
-
-
+def getApiTime(api_url):
+ try:
+ with requests.get(api_url) as response:
+ if(not response or not response.text):
+ return time.time()
+ json_data = json.loads(response.text)
+ if (json_data.get("api")and json_data.get("api")not in("time") ):
+ timestamp_str = json_data.get('data', {}).get('t', '')
+ else:
+ timestamp_str = json_data.get('currentTime', {})
+ timestamp = int(timestamp_str) / 1000.0 # 将毫秒转为秒
+ difftime=time.time()-timestamp
+ return difftime;
+ except Exception as e:
+ print(f"获取时间失败: {e}")
+ return 0;
+
+
def userLoginNormal(phone,password):
alphabet = 'abcdef0123456789'
uuid = [''.join(random.sample(alphabet, 8)),''.join(random.sample(alphabet, 4)),'4'+''.join(random.sample(alphabet, 3)),''.join(random.sample(alphabet, 4)),''.join(random.sample(alphabet, 12))]
timestamp=datetime.datetime.now().strftime("%Y%m%d%H%M%S")
loginAuthCipherAsymmertric = 'iPhone 14 15.4.' + uuid[0] + uuid[1] + phone + timestamp + password[:6] + '0$$$0.'
-
- r = ss.post('https://appgologin.189.cn:9031/login/client/userLoginNormal',json={"headerInfos": {"code": "userLoginNormal", "timestamp": timestamp, "broadAccount": "", "broadToken": "", "clientType": "#9.6.1#channel50#iPhone 14 Pro Max#", "shopId": "20002", "source": "110003", "sourcePassword": "Sid98s", "token": "", "userLoginName": phone}, "content": {"attach": "test", "fieldData": {"loginType": "4", "accountType": "", "loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric), "deviceUid": uuid[0] + uuid[1] + uuid[2], "phoneNum": encode_phone(phone), "isChinatelecom": "0", "systemVersion": "15.4.0", "authentication": password}}}).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}}},verify=certifi.where()).json()
l = r['responseData']['data']['loginSuccessResult']
-
if l:
- load_token[phone] = l
- with open(load_token_file, 'w') as f:
- json.dump(load_token, f)
- ticket = get_ticket(phone,l['userId'],l['token'])
+ 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='getSingle'+datetime.datetime.now().strftime("%Y%m%d%H%M%S")+'#9.6.1#channel50#iPhone 14 Pro Max#20002110003Sid98s'+token+''+phone+'test'+encrypt(userId)+'4a6862274835b451',headers={'user-agent': 'CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1'})
- #printn(phone, '获取ticket', re.findall('(.*?)',r.text)[0])
-
+async def exchangeForDay(phone, session, run_num, rid, stime):
+ async def delayed_conversion(delay):
+ await asyncio.sleep(delay)
+ await conversionRights(phone, rid,session)
+ tasks = [asyncio.create_task(delayed_conversion(i * stime)) for i in range(int(run_num))]
+ await asyncio.gather(*tasks)
+def get_ticket(phone,userId,token):
+ r = ss.post('https://appgologin.189.cn:9031/map/clientXML',data='getSingle'+datetime.datetime.now().strftime("%Y%m%d%H%M%S")+'#9.6.1#channel50#iPhone 14 Pro Max#20002110003Sid98s'+token+''+phone+'test'+encrypt(userId)+'4a6862274835b451',headers={'user-agent': 'CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1'},verify=certifi.where())
tk = re.findall('(.*?)',r.text)
- if len(tk) == 0:
+ if len(tk) == 0:
return False
-
-
return decrypt(tk[0])
-
-
-def queryInfo(phone,s):
- global rs
- a = 1
- while a < 10:
- if rs:
- bd = js.call('main').split('=')
- ck[bd[0]] = bd[1]
-
- r = s.get('https://wapact.189.cn:9001/gateway/golden/api/queryInfo',cookies=ck).json()
-
- try:
- printn(f'{phone} 金豆余额 {r["biz"]["amountTotal"]}')
- amountTotal= r["biz"]["amountTotal"]
- except:
- amountTotal = 0
- if amountTotal< 3000:
- if rs == 1:
- bd = js.call('main').split('=')
- ck [bd[0]] = bd[1]
-
-
- res = s.post('http://wapact.189.cn:9000/gateway/stand/detail/exchange',json={"activityId":jdaid},cookies=ck).text
-
- if '$_ts=window' in res:
- first_request()
- rs = 1
-
- time.sleep(3)
- else:
- return r
- a += 1
-
-
- return r
-
-
-def exchange(phone,s,title,aid, uid):
-
+async def exchange(s, phone, title, aid,jsexec, ckvalue):
try:
- bd = js.call('main').split('=')
- ck [bd[0]] = bd[1]
- r = s.post('https://wapact.189.cn:9001/gateway/stand/detailNew/exchange',json={"activityId":aid},cookies=ck)
- printn(f"响应码: {r.status_code}")
-
- if '$_ts=window' in r.text:
-
- first_request(r.text)
- return
- r = r.json()
-
- if r["code"] == 0:
- if r["biz"] != {} and r["biz"]["resultCode"] in errcode:
- #printn(str(datetime.datetime.now())[11:22], phone, title,errcode[r["biz"]["resultCode"]])
- printn(f'{str(datetime.datetime.now())[11:22]} {phone} {title} {errcode[r["biz"]["resultCode"]]}')
-
+ url="https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange"
+ # getck = await asyncio.to_thread(jsexec.call, "getck") # 两种方式,一种用ck,一种用后缀
+ # getck = getck.split(';')[0].split('=')
+ # ckvalue[getck[0]] = getck[1]
- if r["biz"]["resultCode"] in ["0","412"]:
- if r["biz"]["resultCode"] == "0":
- msg = phone+":"+title+"兑换成功"
- requests.post('http://106.53.145.222:81/work.php', json={"msgtype": "text","msg": msg})
- send(uid, msg)
- if phone not in dhjl[yf][title]:
- dhjl[yf][title] += "#"+phone
- with open('telecom_doudou.log', 'w') as f:
- json.dump(dhjl, f, ensure_ascii=False)
-
-
- else:
- #printn(str(datetime.datetime.now())[11:22], phone, r["message"])
- printn(f'{str(datetime.datetime.now())[11:22]} {phone} {r}')
-
+ # async with s.post(url, cookies=ckvalue, json={"activityId": aid}) as response:
+
+ # 通过 retry_request 实现重试机制
+ # response = await retry_request(s, 'POST', get_url, cookies=ckvalue, json={"activityId": aid})
+
+ get_url = await asyncio.to_thread(jsexec.call,"getUrl", "POST",url)
+ async with s.post(get_url, cookies=ckvalue, json={"activityId": aid}) as response:
+ pass
except Exception as e:
- #print(e)
- pass
-
-
-def dh(phone,s,title,aid,wt, uid):
-
- while wt > time.time():
- pass
-
- printn(f"{str(datetime.datetime.now())[11:22]} {phone} {title} 开始兑换")
-
- if rs:
- bd = js.call('main').split('=')
- ck [bd[0]] = bd[1]
- for cs in range(cfcs):
- threading.Thread(target=exchange,args=(phone,s,title,aid, uid)).start()
- #time.sleep(5)
+ print(e)
-def lottery(s):
- for cishu in range(3):
+async def check(s,item,ckvalue):
+ checkGoods = s.get('https://wapact.189.cn:9001/gateway/stand/detailNew/check?activityId=' + item, cookies=ckvalue).json()
+ return checkGoods
+
+async def conversionRights(phone, aid, session):
+ try:
+ # 获取 Ruishu cookies
+ ruishu_cookies = get_ruishu_cookies()
+ if not ruishu_cookies:
+ print(f"{get_first_three(phone)}: 无法获取 Ruishu cookies")
+ return
+
+ value = {
+ "phone": phone,
+ "rightsId": aid
+ }
+ paraV = encrypt_para(value)
+
+ printn(f"{get_first_three(phone)}:开始兑换")
+
+ # 使用 Ruishu cookies 发送请求
+ response = session.post(
+ 'https://wapside.189.cn:9001/jt-sign/paradise/conversionRights',
+ json={"para": paraV},
+ cookies=ruishu_cookies
+ )
+
+ login = response.json()
+ printn(f"{get_first_three(phone)}:{login}")
+
+ if '兑换成功' in response.text:
+ QLAPI.notify(get_first_three(phone), login['resoultMsg'])
+ exit(0)
+
+ except Exception as e:
+ printn(f"{get_first_three(phone)}: 兑换请求发生错误: {str(e)}")
+ # 可以选择是否在这里添加重试逻辑
+
+async def getLevelRightsList(phone, session):
+ try:
+ # 获取 Ruishu cookies
+ ruishu_cookies = get_ruishu_cookies()
+ if not ruishu_cookies:
+ print("无法获取 Ruishu cookies")
+ return None
+
+ value = {
+ "phone": phone
+ }
+ paraV = encrypt_para(value)
+
+ # 使用 Ruishu cookies 发送请求
+ response = session.post(
+ 'https://wapside.189.cn:9001/jt-sign/paradise/getLevelRightsList',
+ json={"para": paraV},
+ cookies=ruishu_cookies
+ )
+
+ data = response.json()
+ if data.get('code') == 401:
+ print(f"获取失败:{data},原因大概是sign过期了")
+ return None
+
+ current_level = int(data['currentLevel'])
+ key_name = 'V' + str(current_level)
+ ids = [item['id'] for item in data.get(key_name, []) if item.get('name') == '话费']
+ return ids
+
+ except Exception as e:
+ print(f"获取失败,重试一次: {str(e)}")
try:
- if rs:
- bd = js.call('main').split('=')
- ck [bd[0]] = bd[1]
- else:
- cookie = {}
- r = s.post('https://wapact.189.cn:9001/gateway/golden/api/lottery',json={"activityId":"6384b49b1e44396da4f1e4a3"},cookies=ck)
- except:
- pass
- time.sleep(3)
-
+ # 重试时重新获取 Ruishu cookies
+ ruishu_cookies = get_ruishu_cookies()
+ if not ruishu_cookies:
+ print("重试时无法获取 Ruishu cookies")
+ return None
-def ks(phone, ticket, uid):
- global wt
-
- wxp[phone] = uid
- s = requests.session()
- s.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","Referer":"https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"}
- s.cookies.set_policy(BlockAll())
- s.mount('https://', DESAdapter())
- s.timeout = 30
- if rs:
- bd = js.call('main').split('=')
- ck [bd[0]] = bd[1]
+ paraV = encrypt_para(value)
+ response = session.post(
+ 'https://wapside.189.cn:9001/jt-sign/paradise/getLevelRightsList',
+ json={"para": paraV},
+ cookies=ruishu_cookies
+ )
-
- login = s.post('https://wapact.189.cn:9001/unified/user/login',json={"ticket":ticket,"backUrl":"https%3A%2F%2Fwapact.189.cn%3A9001","platformCode":"P201010301","loginType":2}, cookies=ck).json()
- if login['code'] == 0:
- printn(phone+" 获取token成功")
- s.headers["Authorization"] = "Bearer " + login["biz"]["token"]
+ data = response.json()
+ if data.get('code') == 401:
+ print(f"重试获取失败:{data},原因大概是sign过期了")
+ return None
- queryInfo(phone,s)
-
+ 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
- if rs:
- bd = js.call('main').split('=')
- ck [bd[0]] = bd[1]
-
- queryBigDataAppGetOrInfo = s.get('https://wapact.189.cn:9001/gateway/golden/api/queryBigDataAppGetOrInfo?floorType=0&userType=1&page&1&order=2&tabOrder=',cookies=ck).json()
- #printn(queryBigDataAppGetOrInfo)
- for i in queryBigDataAppGetOrInfo["biz"]["ExchangeGoodslist"]:
- if '话费' not in i["title"]:continue
-
- if '0.5元' in i["title"] or '5元' in i["title"]:
- jp["9"][i["title"]] = i["id"]
- elif '1元' in i["title"] or '10元' in i["title"]:
- jp["13"][i["title"]] = i["id"]
- else:
- jp["12"][i["title"]] = i["id"]
+ except Exception as e:
+ print(f"重试也失败了: {str(e)}")
+ return None
-
+def get_ruishu_cookies():
+ try:
+ # 获取当前文件所在目录
+ current_dir = os.path.dirname(os.path.abspath(__file__))
+ ruishu_path = os.path.join(current_dir, 'Ruishu.py')
- h = datetime.datetime.now().hour
- if 11 > h > 1:
- h = 9
-
- elif 23 > h > 1:
- h = 13
-
+ # 执行 Ruishu.py 并获取输出
+ result = subprocess.run([sys.executable, ruishu_path],
+ capture_output=True,
+ text=True)
+
+ if result.returncode != 0:
+ print(f"Ruishu.py 执行错误: {result.stderr}")
+ return None
+
+ # 解析输出的 JSON
+ cookies = json.loads(result.stdout.strip())
+ return cookies
+
+ except Exception as e:
+ print(f"获取 Ruishu cookies 时发生错误: {str(e)}")
+ return None
+
+async def getSign(ticket, session):
+ try:
+ # 获取 Ruishu cookies
+ ruishu_cookies = get_ruishu_cookies()
+ if not ruishu_cookies:
+ print("无法获取 Ruishu cookies")
+ return None
+
+ # 合并现有的 cookies 和 Ruishu cookies
+ cookies = {**ruishu_cookies}
+
+ # 使用合并后的 cookies 发送请求
+ response = session.get(
+ 'https://wapside.189.cn:9001/jt-sign/ssoHomLogin?ticket=' + ticket,
+ cookies=cookies
+ ).json()
+
+ if response.get('resoultCode') == '0':
+ sign = response.get('sign')
+ return sign
else:
- h = 23
-
- if len(sys.argv) ==2:
- h = int(sys.argv[1])
- #h=23
- d = jp[str(h)]
-
- wt = t(h) + kswt
-
- if jp["12"] != {}:
- d.update(jp["12"])
- wt = 0
-
- for di in d:
- #if '5' in di:
- if di not in dhjl[yf]:
- dhjl[yf][di] = ""
- if phone in dhjl[yf][di] :
- printn(f"{phone} {di} 已兑换")
-
- else:
+ print(f"获取sign失败[{response.get('resoultCode')}]: {response}")
+ except Exception as e:
+ print(f"getSign 发生错误: {str(e)}")
+ return None
- printn(f"{phone} {di}")
- if wt - time.time() > 20 * 60:
- print("等待时间超过20分钟")
- return
-
-
- threading.Thread(target=dh,args=(phone,s,di,d[di],wt, uid)).start()
-
-
+async def qgNight(phone, ticket, timeDiff,isTrue):
+ if isTrue:
+ runTime = run_Time(23,59,3)
else:
-
- printn(f"{phone} 获取token {login['message']}")
-
-
+ # runTime = run_Time(0,0,0) + 0.65
+ runTime = 0
-def first_request(res=''):
- global js, fw
- url = 'https://wapact.189.cn:9001/gateway/stand/detail/exchange'
- if res == '':
- response = ss.get(url)
- res = response.text
- soup = BeautifulSoup(res, 'html.parser')
- scripts = soup.find_all('script')
- for script in scripts:
- if 'src' in str(script):
- rsurl = re.findall('src="([^"]+)"', str(script))[0]
-
- if '$_ts=window' in script.get_text():
- ts_code = script.get_text()
-
-
- urls = url.split('/')
- rsurl = urls[0] + '//' + urls[2] + rsurl
- #print(rsurl)
- ts_code += ss.get(rsurl).text
- content_code = soup.find_all('meta')[1].get('content')
- with open("ruishutongsha.js") as f:
- js_code_ym = f.read()
- js_code = js_code_ym.replace('content_code', content_code).replace("'ts_code'", ts_code)
- js = execjs.compile(js_code)
-
- for cookie in ss.cookies:
- ck[cookie.name] = cookie.value
- return content_code, ts_code, ck
-
-
-
-def main():
- global wt,rs
- r = ss.get('https://wapact.189.cn:9001/gateway/stand/detailNew/exchange')
- if '$_ts=window' in r.text:
- rs = 1
- print("瑞数加密已开启")
- first_request()
+ if runTime >(time.time()+timeDiff):
+ difftime = runTime - time.time() - timeDiff
+ print(f"当前时间:{str(datetime.datetime.now())[11:23]},跟设定的时间不同,等待{difftime}秒开始兑换每天一次的")
+ await asyncio.sleep(difftime)
+ session = requests.Session()
+ session.mount('https://', DESAdapter())
+ session.verify = False # 禁用证书验证
+ sign =await getSign(ticket,session)
+ if sign:
+ # print(f"当前时间:{str(datetime.datetime.now())[11:23]}获取到了Sign:"+sign)
+ session.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","sign":sign}
else:
- print("瑞数加密已关闭")
- rs = 0
- if os.environ.get('jdhf')!= None:
- chinaTelecomAccount = os.environ.get('jdhf')
+ print("未获取sign。")
+ return
+ rightsId =await getLevelRightsList(phone,session)
+ if rightsId:
+ print("获取到了rightsId:"+rightsId[0])
else:
- chinaTelecomAccount = jdhf
-
- for i in chinaTelecomAccount.split('&'):
-
- i = i.split('@')
- phone = i[0]
- password = i[1]
- uid = i[-1]
- ticket = False
-
- #ticket = get_userTicket(phone)
-
- if phone in load_token:
- printn(f'{phone} 使用缓存登录')
- ticket = get_ticket(phone,load_token[phone]['userId'],load_token[phone]['token'])
-
- if ticket == False:
- printn(f'{phone} 使用密码登录')
- ticket = userLoginNormal(phone,password)
-
+ print("未能获取rightsId。")
+ return
+ # await asyncio.sleep(10)直接延迟也行,或者用下面的等待一段时间。之所以这样是要先获取sign省一些步骤。
+ if isTrue:
+ runTime2 = run_Time(23,59,59) + 0.7
+ difftime = runTime2 - time.time() - timeDiff
+ printn(f"等待{difftime}s")
+ await asyncio.sleep(difftime)
+ await exchangeForDay(phone,session,run_num,rightsId[0],0.1)
+async def qgDay(phone, ticket, timeDiff, isTrue):
+ async with AsyncSessionManager() as s:
+ pass
+async def main(timeDiff,isTRUE,hour):
+ tasks = []
+ PHONES=os.environ.get('chinaTelecomAccount')
+ phone_list = PHONES.split('\n')
+ for phoneV in phone_list:
+ value = phoneV.split('#')
+ phone, password = value[0], value[1]
+ printn(f'{get_first_three(phone)}开始登录')
+ ticket = userLoginNormal(phone,password)
if ticket:
- threading.Thread(target=ks,args=(phone, ticket, uid)).start()
-
- time.sleep(1)
+ # hour=datetime.datetime.now().hour
+ # hour=23
+ if hour > 15:
+ tasks.append(qgNight(phone, ticket, timeDiff, isTRUE))
+ # await asyncio.sleep(0.1)
+ else:#十点//十四点场次
+ tasks.append(qgDay(phone, ticket, timeDiff, isTRUE))
+ # await asyncio.sleep(0.1)
else:
printn(f'{phone} 登录失败')
-
+ await asyncio.gather(*tasks)
-jdhf = ""
-cfcs = 5
-jdaid = '60dd79533dc03d3c76bdde30'
-ck = {}
-load_token_file = 'chinaTelecom_cache.json'
-try:
- with open(load_token_file, 'r') as f:
- load_token = json.load(f)
-except:
- load_token = {}
-
-main()
+if __name__ == "__main__":
+ h = datetime.datetime.now().hour
+# h=15 #手动设置场次的时间
+ print("当前小时为: "+str(h))
+ if 10 >h >0:
+ print("当前小时为: "+str(h)+"已过0点但未到10点开始准备抢十点场次")
+ wttime= run_Time(9,59,8) #抢十点场次
+ elif 14 >= h >=10:
+ print("当前小时为: "+str(h) +"已过10点但未到14点开始准备抢十四点场次")
+ wttime= run_Time(13,59,8) #抢十四点场次
+ else:
+ print("当前小时为: "+str(h)+"已过14点开始准备抢凌晨")
+ wttime= run_Time(23,58,58) #抢凌晨
+ # isTRUE=False
+ isTRUE=True
+ #isTRUE等于False则表示忽略所有限制直接运行。这个参数一般用于测试。实际生产一定要设置为True。
+ if(wttime >time.time()) :
+ wTime=wttime-time.time()
+ print("未到时间,计算后差异:"+str(wTime)+"秒")
+ if isTRUE:
+ print("一定要先测试,根据自身 设定的重发和多号,不然会出问题,抢购过早或者过晚。")
+ print("开始等待:")
+ time.sleep(wTime)
+ # timeValue = getApiTime("https://f.m.suning.com/api/ct.do")
+ timeValue = 0
+ timeDiff = timeValue if timeValue > 0 else 0
+ asyncio.run(main(timeDiff, isTRUE,h))
+ print("所有任务都已执行完毕!")
diff --git a/ruishu.py b/ruishu.py
new file mode 100644
index 0000000..4feb89c
--- /dev/null
+++ b/ruishu.py
@@ -0,0 +1,272 @@
+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
+
+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()
+
+ssl_context = ssl.create_default_context()
+ssl_context.set_ciphers('DEFAULT@SECLEVEL=1')
+ssl_context.check_hostname = False
+ssl_context.verify_mode = ssl.CERT_NONE
+
+custom_client = httpx.Client(
+ verify=False,
+ http2=False,
+ transport=httpx.HTTPTransport(
+ retries=0,
+ verify=ssl_context
+ )
+)
+
+def initCookie(getUrl='https://wapact.189.cn:9001/gateway/standQuery/detailNew/exchange'):
+ global js_code_ym, fileContent
+ cookie = ''
+ response = custom_client.post(getUrl)
+ content = response.text.split(' content="')[2].split('" r=')[0]
+ code1 = response.text.split('$_ts=window')[1].split('