185 lines
6.6 KiB
Python
185 lines
6.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# 本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
|
|
# 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
|
|
|
|
import traceback
|
|
from base64 import b64encode
|
|
from base.spider import Spider
|
|
from Crypto.PublicKey import RSA
|
|
from Crypto.Util.Padding import pad
|
|
from urllib.parse import quote_plus, unquote_plus, urlencode
|
|
import sys,time,json,random,hashlib,urllib3
|
|
from Crypto.Cipher import AES, PKCS1_v1_5
|
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
sys.path.append('..')
|
|
|
|
class Spider(Spider):
|
|
cache_host = {}
|
|
def localProxy(self, params):
|
|
if params.get('type') == 'drama':
|
|
response = '获取域名失败'
|
|
try:
|
|
if params.get('from') == 'host':
|
|
url = params.get('url')
|
|
if url.startswith('http'):
|
|
response = self.cache_host.get(url)
|
|
if not(response and isinstance(response,str) and response.startswith('http')):
|
|
res = self.fetch(url,headers={'User-Agent': 'okhttp/3.12.1'}).json()
|
|
print('域名获取结果:',res)
|
|
if res['domain'].startswith('http'):
|
|
response = res['domain']
|
|
self.cache_host[url] = response
|
|
elif params.get('from') == 'paramsData':
|
|
data = self.params_data(params)
|
|
response = data
|
|
return [200, 'text/text;charset=utf-8', response]
|
|
except Exception as e:
|
|
return [500, 'text/text;charset=utf-8', f'处理出错: {e}\n\n错误堆栈:\n{traceback.format_exc()}']
|
|
return None
|
|
|
|
def params_data(self,params):
|
|
ver_name = params.get('verName')
|
|
ver = params.get('ver',ver_name.replace('.',''))
|
|
app_name = params.get('AppName')
|
|
pkg = params.get('pkg')
|
|
public_key = params.get('publicKey').replace(' ','+')
|
|
if not(ver and ver_name and app_name and pkg and public_key): return '请按要求传参'
|
|
|
|
# 设备信息
|
|
android_id = '313c3eeeb2a098a1'
|
|
mac = '02:00:00:00:00:00' # 网卡MAC地址
|
|
model = '23113RKC6C' # 型号
|
|
manufacturer = 'Xiaomi' # 制造商
|
|
|
|
# 计算UUID
|
|
uuid = hashlib.md5(f"{android_id}{mac}{model}{manufacturer}".encode()).hexdigest().upper()
|
|
|
|
timestamp = self.get_13_digit_timestamp()
|
|
random_str = self.random_str_function()
|
|
|
|
# AES加密生成sign
|
|
aes_key = 'OC1A06E197EF10CF3F6058CA7A803B5E'.encode()
|
|
cipher_aes = AES.new(aes_key, AES.MODE_ECB)
|
|
sign_data = f"{timestamp}{random_str}".encode()
|
|
sign_encrypted = cipher_aes.encrypt(pad(sign_data, AES.block_size))
|
|
sign = b64encode(sign_encrypted).decode()
|
|
|
|
# 构建设备信息
|
|
device_info = {
|
|
"country": "CN",
|
|
"vName": ver_name,
|
|
"cpuId": "",
|
|
"young": 0,
|
|
"facturer": manufacturer,
|
|
"pkg": pkg,
|
|
"uuid": uuid,
|
|
"resolution": "900x1600",
|
|
"mac": quote_plus(mac),
|
|
"sig": self.rsa_encrypt(f"{timestamp}{random_str}{ver}", public_key),
|
|
"abid": "6249",
|
|
"model": model,
|
|
"plat": "android",
|
|
"udid": uuid,
|
|
"dpi": "240",
|
|
"net": "1",
|
|
"lang": "zh",
|
|
"random_str": random_str,
|
|
"brand": "Redmi", # 品牌
|
|
"timestamp": timestamp,
|
|
"density": "3.25",
|
|
"appName": quote_plus(app_name),
|
|
"cpu": "arm64-v8a",
|
|
"chid": "10000",
|
|
"carrier": quote_plus('移动'), # 网络运营商
|
|
"sig2": sign[:8],
|
|
"sig3": sign[8:],
|
|
"_vOsCode": "32",
|
|
"vOs": "12", # 安卓版本
|
|
"vApp": ver,
|
|
"device": "0",
|
|
"androidID": android_id
|
|
}
|
|
|
|
# JSON序列化并AES加密
|
|
dat = json.dumps(device_info, ensure_ascii=False, separators=(',', ':'))
|
|
|
|
# AES-128-CBC加密
|
|
aes_key2 = 'ed5fdsgucxumegqa'.encode()
|
|
iv = 'ed5fdsgucxumegqa'.encode()
|
|
cipher_aes2 = AES.new(aes_key2, AES.MODE_CBC, iv)
|
|
dat_encrypted = cipher_aes2.encrypt(pad(dat.encode(), AES.block_size))
|
|
dat_hex = dat_encrypted.hex()
|
|
return dat_hex
|
|
|
|
def rsa_encrypt(self,plaintext, public_key_str):
|
|
"""RSA加密"""
|
|
# 构建PEM格式的公钥
|
|
public_key_pem = f"-----BEGIN PUBLIC KEY-----\n{public_key_str}\n-----END PUBLIC KEY-----"
|
|
|
|
# 导入公钥
|
|
rsa_key = RSA.import_key(public_key_pem)
|
|
cipher_rsa = PKCS1_v1_5.new(rsa_key)
|
|
|
|
# 加密
|
|
encrypted = cipher_rsa.encrypt(plaintext.encode())
|
|
|
|
# Base64编码
|
|
return b64encode(encrypted).decode()
|
|
|
|
def random_str_function(self,length=16):
|
|
"""生成随机字符串"""
|
|
char_array = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
|
result_str = ''
|
|
i = 0
|
|
|
|
while i < length - 1:
|
|
c = random.choice(char_array)
|
|
if c not in result_str:
|
|
result_str += c
|
|
i += 1
|
|
|
|
return result_str + "="
|
|
|
|
def get_13_digit_timestamp(self):
|
|
"""获取13位时间戳"""
|
|
return int(round(time.time() * 1000))
|
|
|
|
def init(self, extend=''):
|
|
pass
|
|
|
|
def homeContent(self, filter):
|
|
pass
|
|
|
|
def homeVideoContent(self):
|
|
pass
|
|
|
|
def categoryContent(self, tid, pg, filter, extend):
|
|
pass
|
|
|
|
def searchContent(self, key, quick, pg='1'):
|
|
pass
|
|
|
|
def detailContent(self, ids):
|
|
pass
|
|
|
|
def playerContent(self, flag, id, vipflags):
|
|
pass
|
|
|
|
def getName(self):
|
|
pass
|
|
|
|
def isVideoFormat(self, url):
|
|
pass
|
|
|
|
def manualVideoCheck(self):
|
|
pass
|
|
|
|
def destroy(self):
|
|
pass
|
|
|
|
if __name__ == "__main__":
|
|
sp = Spider()
|
|
formatJo = None
|
|
# formatJo = sp.localProxy({"type": "drama", "from": "host", "url":"https://1234-1349250429.cos.ap-hongkong.myqcloud.com/app.txt"}) # host
|
|
formatJo = sp.localProxy({"type": "drama","from": "paramsData", "verName": "3.0.1.7", "AppName": "橘汁", "pkg": "com.tjjiangh.android", "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp9Ek4wIlQAtwFnuBRlsFiow2tr%2B4UOciGeNKbY7nL74etUqUb6fvpOSOHhFEfaWlfwUpOB17x3JEL3No19nfjCeVYrYPjlJcgoqUWH%2FtfIfFAQWvtxBIBlKazkhw8d3ChysWmeWRikKqkBsVRY4oqNPuj4sjm6Zult0U4I4prRQIDAQAB"}) # paramsData
|
|
print(formatJo) |