mirror of
https://github.com/wbt5/real-url.git
synced 2025-06-16 15:59:57 +08:00
143 lines
4.0 KiB
Python
143 lines
4.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
# @Time: 2021/6/19 20:39
|
||
# @Project: my-spiders
|
||
# @Author: wbt5
|
||
# @Blog: https://wbt5.com
|
||
|
||
|
||
import binascii
|
||
import hashlib
|
||
import json
|
||
import re
|
||
import time
|
||
from urllib.parse import urlencode
|
||
|
||
import execjs
|
||
import requests
|
||
|
||
|
||
class sIQiYi:
|
||
|
||
def __init__(self, rid):
|
||
"""
|
||
收费直播间、未开播直播间、已结束直播间获取到的地址均无法播放;
|
||
Args:
|
||
rid: 这里传入完整的直播间地址
|
||
"""
|
||
url = rid
|
||
self.rid = url.split('/')[-1]
|
||
self.s = requests.Session()
|
||
|
||
def decodeurl(self):
|
||
"""
|
||
传入url地址,截取url中的直播间id
|
||
字符串lgqipu倒序后转为十进制数,作为qpid解码的传参
|
||
Returns:
|
||
qpid
|
||
"""
|
||
o = 'lgqipu'
|
||
o = int(binascii.hexlify(o[::-1].encode()), 16)
|
||
|
||
s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||
a = 0
|
||
rr = enumerate(self.rid)
|
||
for i, _ in rr:
|
||
a += s.index(_) * pow(36, len(self.rid) - (i + 1))
|
||
|
||
a = f'{a:b}'
|
||
n = f'{o:b}'
|
||
x = len(a)
|
||
y = len(n)
|
||
if x > y:
|
||
i = a[:x - y]
|
||
a = a[x - y:]
|
||
else:
|
||
i = n[:y - x]
|
||
n = n[y - x:]
|
||
|
||
for rs, ele in enumerate(a):
|
||
if ele == n[rs]:
|
||
i += '0'
|
||
else:
|
||
i += '1'
|
||
qpid = int(i, 2)
|
||
return qpid
|
||
|
||
def get_real_url(self):
|
||
"""
|
||
里面iqiyi.js是个加盐的md5,execjs执行后获取cmd5x的返回值
|
||
Returns:
|
||
m3u8格式播放地址
|
||
Raises:
|
||
Could not find an available JavaScript runtime: 是否安装了js环境
|
||
"""
|
||
qpid = self.decodeurl()
|
||
uid = 'ba4fe551bd889d73f3d321d2fadc6130'
|
||
ve = hashlib.md5(f'{qpid}function getTime() {{ [native code] }}{uid}'.encode('utf-8')).hexdigest()
|
||
v = {
|
||
'lp': qpid,
|
||
'src': '01014351010000000000',
|
||
'ptid': '02037251010000000000',
|
||
'uid': '',
|
||
'rateVers': 'H5_QIYI',
|
||
'k_uid': uid,
|
||
'qdx': 'n',
|
||
'qdv': 3,
|
||
'dfp': '',
|
||
've': ve,
|
||
'v': 1,
|
||
'k_err_retries': 0,
|
||
'tm': int(time.time()),
|
||
'k_ft4': 17179869185,
|
||
'k_ft1': 141287244169216,
|
||
'k_ft5': 1,
|
||
'qd_v': 1,
|
||
'qdy': 'a',
|
||
'qds': 0,
|
||
# 'callback': 'Q3d080ff19d8f233acb05683bf38e3a15',
|
||
# 'vf': 'f0b986f100ae81fff8e8f8f96053e815',
|
||
}
|
||
k = '/jp/live?' + urlencode(v)
|
||
cb = hashlib.md5(k.encode('utf-8')).hexdigest()
|
||
k = f'{k}&callback=Q{cb}'
|
||
|
||
# 生成vf
|
||
with open('iqiyi.js', 'r') as f:
|
||
content = f.read()
|
||
try:
|
||
cmd5x = execjs.compile(content)
|
||
vf = cmd5x.call('cmd5x', k)
|
||
except RuntimeError:
|
||
raise Exception('Could not find an available JavaScript runtime.')
|
||
|
||
# 请求url
|
||
url = f'https://live.video.iqiyi.com{k}&vf={vf}'
|
||
res = self.s.get(url).text
|
||
data = re.search(r'try{\w{33}\(([\w\W]+)\s\);}catch\(e\){};', res).group(1)
|
||
data = json.loads(data)
|
||
if data['code'] == 'A00004':
|
||
raise Exception('直播间地址错误!')
|
||
elif data['code'] == 'A00000':
|
||
try:
|
||
url = data['data']['streams'][-1]['url']
|
||
except IndexError:
|
||
raise Exception('可能直播未开始直播或为付费直播!')
|
||
else:
|
||
raise Exception('无法定位错误原因,可提交issue!')
|
||
return url
|
||
|
||
|
||
def get_real_url(rid):
|
||
try:
|
||
siqiyi = sIQiYi(rid)
|
||
return siqiyi.get_real_url()
|
||
except Exception as e:
|
||
print('Exception:', e)
|
||
return False
|
||
|
||
|
||
if __name__ == '__main__':
|
||
r = input('请输入爱奇艺体育直播间完整地址地址,注意只能获取免费直播:\n')
|
||
# https://sports.iqiyi.com/resource/pcw/live/gwbgbfbgc3
|
||
print(get_real_url(r))
|