224 lines
9.0 KiB
Python
224 lines
9.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# 本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
|
|
# 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
|
|
|
|
from base.spider import Spider
|
|
import sys,time,base64,secrets,hashlib,urllib3
|
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
sys.path.append('..')
|
|
|
|
class Spider(Spider):
|
|
headers, host = {
|
|
'User-Agent': 'okhttp/3.12.11',
|
|
'Connection': 'Keep-Alive',
|
|
'Accept-Encoding': 'gzip'
|
|
}, ''
|
|
|
|
def init(self, extend=''):
|
|
default_host = 'http://194.147.100.13'
|
|
try:
|
|
if not extend.startswith('http'):
|
|
extend = default_host
|
|
self.host = extend.strip().rstrip('/')
|
|
except Exception:
|
|
self.host = default_host
|
|
|
|
def homeContent(self, filter):
|
|
if not self.host: return None
|
|
response = self.fetch(f'{self.host}/api.php/v2.vod/androidtypes', headers=self.headers, verify=False).json()
|
|
data = response['data']
|
|
filters, class_list = {}, []
|
|
for item in data:
|
|
type_id = item.get('type_id', '')
|
|
type_name = item.get('type_name', '')
|
|
if not (type_id == '' and type_name == ''):
|
|
class_list.append({'type_id': type_id,'type_name': type_name})
|
|
classes = item.get('classes', [])
|
|
areas = item.get('areas', [])
|
|
years = item.get('years', [])
|
|
filter_items = []
|
|
class_values = [{'n': '全部', 'v': ''}]
|
|
for cls in classes:
|
|
n_val,v_val = cls,cls
|
|
if not (n_val == '' and v_val == ''):
|
|
class_values.append({'n': n_val, 'v': v_val})
|
|
filter_items.append({'key': 'class','name': '类型','value': class_values})
|
|
area_values = [{'n': '全部', 'v': ''}]
|
|
for area in areas:
|
|
n_val,v_val = area,area
|
|
if not (n_val == '' and v_val == ''): area_values.append({'n': n_val, 'v': v_val})
|
|
filter_items.append({'key': 'area','name': '地区','value': area_values})
|
|
year_values = [{'n': '全部', 'v': ''}]
|
|
for year in years:
|
|
n_val,v_val = year,year
|
|
if not (n_val == '' and v_val == ''):
|
|
year_values.append({'n': n_val, 'v': v_val})
|
|
filter_items.append({'key': 'year','name': '年份','value': year_values})
|
|
filter_items.append({
|
|
'key': 'sortby','name': '排序',
|
|
'value': [{'n': '时间', 'v': 'updatetime'},{'n': '人气', 'v': 'hits'},{'n': '评分', 'v': 'score'}]
|
|
})
|
|
if type_id != '': filters[type_id] = filter_items
|
|
return {'class': class_list, 'filters': filters}
|
|
|
|
def homeVideoContent(self):
|
|
response = self.fetch(f'{self.host}/api.php/v2.main/androidhome', headers=self.headers, verify=False).json()
|
|
data = response['data']
|
|
videos = self.arr2vods(data.get('top', []))
|
|
for i in data.get('list', []):
|
|
if isinstance(i, dict):
|
|
videos.extend(self.arr2vods(i.get('list', [])))
|
|
return {'list': videos}
|
|
|
|
def categoryContent(self, tid, pg, filter, extend):
|
|
params = {
|
|
k: v for k, v in {
|
|
'page': pg,
|
|
'type': tid,
|
|
'area': extend.get('area'),
|
|
'year': extend.get('year'),
|
|
'sortby': extend.get('sortby'),
|
|
'class': extend.get('class')
|
|
}.items() if v is not None and v != ''
|
|
}
|
|
response = self.fetch(f'{self.host}/api.php/v2.vod/androidfilter10086',params=params, headers=self.headers, verify=False).json()
|
|
videos = self.arr2vods(response.get('data', []))
|
|
return {'list': videos, 'page': pg}
|
|
|
|
def searchContent(self, key, quick, pg='1'):
|
|
response = self.fetch(f"{self.host}/api.php/v2.vod/androidsearch10086?page=1&wd={key}", headers=self.headers, verify=False).json()
|
|
videos = self.arr2vods(response.get('data', []))
|
|
return {'list': videos, 'page': pg}
|
|
|
|
def detailContent(self, ids):
|
|
response = self.fetch(f"{self.host}/api.php/v3.vod/androiddetail2?vod_id={ids[0]}", headers=self.headers2(), verify=False).json()
|
|
data = response['data']
|
|
play_urls = []
|
|
for i in data['urls']:
|
|
if not(i['key'] == '及时雨' or i['url'] == 'dlNQWVppbnZXVVZsZnRhMnRpTkVNT2JaTnpyS010VEs='):
|
|
play_urls.append(f"{i['key']}${i['url']}")
|
|
video = {
|
|
'vod_id': data['id'],
|
|
'vod_name': data['name'],
|
|
'vod_pic': data['pic'],
|
|
'vod_year': data['year'],
|
|
'vod_area': data['area'],
|
|
'vod_actor': data['actor'],
|
|
'vod_director': data['director'],
|
|
'vod_content': data['content'],
|
|
'vod_play_from': 'LiteApple',
|
|
'vod_play_url': '#'.join(play_urls),
|
|
'type_name': data['className'],
|
|
}
|
|
return {'list': [video]}
|
|
|
|
def playerContent(self, flag, vid, vip_flags):
|
|
parse, url, headers = 0, '', {'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'}
|
|
if vid.startswith("JBN_"):
|
|
url = "https://www.yangshipin.cn/tv/home?pid=" + vid[4:]
|
|
parse, headers = 1, {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'}
|
|
elif "HTTP" in vid.upper():
|
|
url = vid
|
|
else:
|
|
url = 'http://c.xpgtv.net/m3u8/' + vid + '.m3u8'
|
|
headers = {**self.headers2(), 'User-Agent': 'com.stub.StubApp/1.6.0 (Linux;Android 12) ExoPlayerLib/2.14.2'}
|
|
return {'jx': 0, 'parse': parse, 'url': url, 'header': headers}
|
|
|
|
def headers2(self):
|
|
token_param_cache_key = 'com.phoenix.tv_33ee1768b8ee539a_token_param'
|
|
token_param = self.getCache(token_param_cache_key)
|
|
if not token_param:
|
|
token_param = F'{self.random32()}||||{self.random11()}||||unknown||xiaomi/b0q/b0q:12/V417IR/913:user/release-keys'
|
|
self.setCache(token_param_cache_key, token_param)
|
|
token2_cache_key = 'com.phoenix.tv_33ee1768b8ee539a_token2'
|
|
token2 = self.getCache(token2_cache_key)
|
|
if not token2:
|
|
token2 = self.encrypt(self.random32())
|
|
self.setCache(token2_cache_key, token2)
|
|
timestamp = str(int(time.time()))
|
|
version = 'XPGBOX com.phoenix.tv1.6.0'
|
|
return {
|
|
**self.headers.copy(),
|
|
'token': self.encrypt(token_param),
|
|
'token2': token2,
|
|
'user_id': "XPGBOX",
|
|
'version': version,
|
|
'timestamp': timestamp,
|
|
'hash': self.hash(f'{token_param}{version}{timestamp}'),
|
|
'screenx': "1600",
|
|
'screeny': "900"
|
|
}
|
|
|
|
def cipher(self, data):
|
|
bytes_key = "XPINGGUO".encode('utf-8')
|
|
b_arr2 = bytearray(i % 256 for i in range(333))
|
|
if len(bytes_key) > 0:
|
|
i2 = 0
|
|
i3 = 0
|
|
for i4 in range(333):
|
|
i5 = bytes_key[i2] & 0xFF
|
|
b_val = b_arr2[i4]
|
|
i3 = (i5 + (b_val & 0xFF) + i3) % 333
|
|
b_arr2[i4], b_arr2[i3] = b_arr2[i3], b_val
|
|
i2 = (i2 + 1) % len(bytes_key)
|
|
b_arr3 = bytearray(len(data))
|
|
i6 = 0
|
|
i7 = 0
|
|
for i8 in range(len(data)):
|
|
i6 = (i6 + 1) % 333
|
|
b2 = b_arr2[i6]
|
|
i9 = b2 & 0xFF
|
|
i7 = (i7 + i9) % 333
|
|
b_arr2[i6], b_arr2[i7] = b_arr2[i7], b2
|
|
i10 = ((b_arr2[i6] & 0xFF) + i9) % 333
|
|
b_arr3[i8] = b_arr2[i10] ^ data[i8]
|
|
return bytes(b_arr3)
|
|
|
|
def arr2vods(self, arr):
|
|
videos = []
|
|
if isinstance(arr, list):
|
|
for i in arr:
|
|
videos.append({
|
|
'vod_id': i['id'],
|
|
'vod_name': i['name'],
|
|
'vod_pic': i['pic'],
|
|
'vod_remarks': i['updateInfo'],
|
|
'vod_year': i.get('year'),
|
|
'vod_content': i.get('content')
|
|
})
|
|
return videos
|
|
|
|
def encrypt(self, s):
|
|
try:
|
|
byte_data = s.encode('utf-8')
|
|
encrypted_data = self.cipher(byte_data)
|
|
return base64.b64encode(encrypted_data).decode('utf-8')
|
|
except UnicodeEncodeError:
|
|
return ""
|
|
|
|
def random11(self):
|
|
return ''.join(secrets.choice('0123456789ABCDEF') for _ in range(11))
|
|
|
|
def random32(self):
|
|
random_bytes = secrets.token_bytes(32)
|
|
return base64.b64encode(random_bytes).decode('utf-8')
|
|
|
|
def hash(self, s):
|
|
hash_hex = hashlib.md5(s.encode()).hexdigest()
|
|
return hash_hex[8:12]
|
|
|
|
def getName(self):
|
|
pass
|
|
|
|
def isVideoFormat(self, url):
|
|
pass
|
|
|
|
def manualVideoCheck(self):
|
|
pass
|
|
|
|
def destroy(self):
|
|
pass
|
|
|
|
def localProxy(self, param):
|
|
pass
|