114 lines
3.5 KiB
Python
114 lines
3.5 KiB
Python
|
|
import hmac
|
|||
|
|
import hashlib
|
|||
|
|
import time
|
|||
|
|
import urllib.parse
|
|||
|
|
from functools import reduce
|
|||
|
|
from hashlib import md5
|
|||
|
|
from aiohttp import ClientSession
|
|||
|
|
|
|||
|
|
# doc: https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md
|
|||
|
|
|
|||
|
|
headers = {
|
|||
|
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# fmt: off
|
|||
|
|
mixinKeyEncTab = [
|
|||
|
|
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
|
|||
|
|
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
|
|||
|
|
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
|
|||
|
|
36, 20, 34, 44, 52
|
|||
|
|
]
|
|||
|
|
# fmt: on
|
|||
|
|
|
|||
|
|
|
|||
|
|
def getMixinKey(orig: str):
|
|||
|
|
"对 imgKey 和 subKey 进行字符顺序打乱编码"
|
|||
|
|
return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, "")[:32]
|
|||
|
|
|
|||
|
|
|
|||
|
|
def encWbi(params: dict, img_key: str, sub_key: str):
|
|||
|
|
"为请求参数进行 wbi 签名"
|
|||
|
|
mixin_key = getMixinKey(img_key + sub_key)
|
|||
|
|
curr_time = round(time.time())
|
|||
|
|
params["wts"] = curr_time # 添加 wts 字段
|
|||
|
|
params = dict(sorted(params.items())) # 按照 key 重排参数
|
|||
|
|
# 过滤 value 中的 "!'()*" 字符
|
|||
|
|
params = {
|
|||
|
|
k: "".join(filter(lambda chr: chr not in "!'()*", str(v)))
|
|||
|
|
for k, v in params.items()
|
|||
|
|
}
|
|||
|
|
query = urllib.parse.urlencode(params) # 序列化参数
|
|||
|
|
wbi_sign = md5((query + mixin_key).encode()).hexdigest() # 计算 w_rid
|
|||
|
|
params["w_rid"] = wbi_sign
|
|||
|
|
return params
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def getWbiKeys():
|
|||
|
|
"获取最新的 img_key 和 sub_key"
|
|||
|
|
async with ClientSession(headers=headers) as session:
|
|||
|
|
async with session.get("https://api.bilibili.com/x/web-interface/nav") as resp:
|
|||
|
|
json_content = await resp.json()
|
|||
|
|
img_url: str = json_content["data"]["wbi_img"]["img_url"]
|
|||
|
|
sub_url: str = json_content["data"]["wbi_img"]["sub_url"]
|
|||
|
|
img_key = img_url.rsplit("/", 1)[1].split(".")[0]
|
|||
|
|
sub_key = sub_url.rsplit("/", 1)[1].split(".")[0]
|
|||
|
|
return img_key, sub_key
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def get_query(params: dict):
|
|||
|
|
"""
|
|||
|
|
获取签名后的查询参数
|
|||
|
|
"""
|
|||
|
|
img_key, sub_key = await getWbiKeys()
|
|||
|
|
signed_params = encWbi(params=params, img_key=img_key, sub_key=sub_key)
|
|||
|
|
query = urllib.parse.urlencode(signed_params)
|
|||
|
|
return query
|
|||
|
|
|
|||
|
|
|
|||
|
|
def hmac_sha256(key, message):
|
|||
|
|
"""
|
|||
|
|
使用HMAC-SHA256算法对给定的消息进行加密
|
|||
|
|
:param key: 密钥
|
|||
|
|
:param message: 要加密的消息
|
|||
|
|
:return: 加密后的哈希值
|
|||
|
|
"""
|
|||
|
|
# 将密钥和消息转换为字节串
|
|||
|
|
key = key.encode("utf-8")
|
|||
|
|
message = message.encode("utf-8")
|
|||
|
|
|
|||
|
|
# 创建HMAC对象,使用SHA256哈希算法
|
|||
|
|
hmac_obj = hmac.new(key, message, hashlib.sha256)
|
|||
|
|
|
|||
|
|
# 计算哈希值
|
|||
|
|
hash_value = hmac_obj.digest()
|
|||
|
|
|
|||
|
|
# 将哈希值转换为十六进制字符串
|
|||
|
|
hash_hex = hash_value.hex()
|
|||
|
|
|
|||
|
|
return hash_hex
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def get_ticket():
|
|||
|
|
"""
|
|||
|
|
获取ticket
|
|||
|
|
"""
|
|||
|
|
o = hmac_sha256("XgwSnGZ1p", f"ts{int(time.time())}")
|
|||
|
|
url = "https://api.bilibili.com/bapis/bilibili.api.ticket.v1.Ticket/GenWebTicket"
|
|||
|
|
params = {
|
|||
|
|
"key_id": "ec02",
|
|||
|
|
"hexsign": o,
|
|||
|
|
"context[ts]": f"{int(time.time())}",
|
|||
|
|
"csrf": "",
|
|||
|
|
}
|
|||
|
|
async with ClientSession(headers=headers) as session:
|
|||
|
|
async with session.post(url, params=params) as resp:
|
|||
|
|
json_content = await resp.json()
|
|||
|
|
return json_content["data"]["ticket"]
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
import asyncio
|
|||
|
|
|
|||
|
|
loop = asyncio.get_event_loop()
|
|||
|
|
loop.run_until_complete(get_ticket())
|