和我有过邮件联系的dalao们应该会发现,两年前我就提及BiliAPI会有Python版本,然而……咕咕咕。然后最近,一股来自东方的神秘力量催使我又打开了这个项目。于是我翻了翻Python3.6的新特性,又跑过来填坑了。然而惨不忍睹的旧设计实在是没有改的空间了,于是我打算开始一波重构。repo位于码云:https://gitee.com/kaaass/biliapi_python,重构分支为reconstruct,欢迎Star、测试、issue、PR。
看commit和issue记录你会发现,其实已经有一次重构了,但是由于当时设计的时候并没有考虑到一些接口的特性,所以后续开发根本没法弄。现在借鉴了一下B站客户端的实现,重新进行了设计。
请求部分目前已经重写完成。采用了ISigner实现不同的签名方式,参数拼接采用了IParamAppender接口来实现。引入了Builder,采用链式调用让代码看着更舒服。旧的请求方法也是完全支持的,所以现在有三种接口请求的方法。
代码语言:javascript复制import biliapi
from biliapi.endpoint import Endpoint
AK = "" # AppKey
SK = "" # SecretKey
biliapi.set_default_key_pair(AK, SK, biliapi.AppType.phone_android)
if __name__ == '__main__':
# 方法1:Endpoint
@Endpoint(
endpoint=biliapi.APP_HOST '/x/v2/space',
mapping={'mid': 'vmid'},
index='data'
)
def space(mid, req=None):
pass
print(space(1))
# 方法2:使用Builder
data = biliapi.request.builder()
.host(biliapi.APP_HOST)
.path('/x/v2/space').param('vmid', 1).do_request()
print(data)
# 方法3:直接调用
data = biliapi.request.get(biliapi.APP_HOST '/x/v2/space', {'vmid': 1})
print(data)
鉴权部分由Auth、Authenticator、AuthManager、AuthParamAppeder组成。Auth用于鉴权信息的存放,不具任何业务逻辑,类似POJO。AuthManager用于管理多用户的凭据和登录对象Authenticator的创建,全局持有一个默认对象,也可以创建一个手动管理。Authenticator存放登陆用逻辑,目前计划由IAuthenticator、ClientAuthenticator、QrCodeAuthenticator、WebAuthenticator组成。AuthParamAppeder用于和Request对接,增加登录凭据用,内部持有一个Auth对象。这部分目前咕咕咕。
其实鉴权方面我还是比较纠结的。设计首先要和Request尽量分离。其次,客户端的鉴权我个人是很想去掉的,因为access_key=>cookies可行,但反着来目前还不是很清楚怎么搞。所以仅有cookie的情况很难管理,且会大大增加程序编写的难度。(部分接口需要兼容两种调用方式)于是一直纠结着也没开始动手写。(这就是你咕咕咕的理由?)
接口还是采取客户端逆向为主要获取方式。上次逆向都是两年前的事情了,所以这次采用最新版本重新更新了下代码。由于时间限制,我也没处理逆向出来的代码(可运行、重命名)。具体的工作状态可以查看DIARY:https://blog.kaaass.net/diary/2018/bilidroid-decomplie-diary/ 。
还是想提及BiliAPI的设计理念——方便。我的目标就是,开发者可以在不显式声明任何BiliAPI对象的情况下使用BiliAPI的所有功能。复杂的内部结构是便于进一步开发和第三方再次开发的,而一般使用的开发者不应该关系这些内部实现。我的逻辑和之前翻译的文章里说的一样,code should be self-revealing(代码本身就应该可被理解)。文档是所有接口的介绍,注释是具体实现的说明,而这些通常会提供很多暂时无用的信息。而简洁的代码甚至能起到无需文档的效果。这就是我一直坚持把不同模块解耦的原因。
以我第一次重构后的接口为例,请求是通过Request对象实现的,而接口内部就有一个默认对象。App对象用于存放ak、sk和app_type,通用库也会持有一个默认对象。所以开发者只需要调用biliapi.set_default_key_pair(AK, SK, biliapi.AppType.phone_android)就会自动创建App对象和请求用的Request对象,而调用接口也不需要传入Request对象。比如获取某个用户的信息,两行足矣:
代码语言:javascript复制biliapi.set_default_key_pair(AK, SK, biliapi.AppType.phone_android)
data = biliapi.user.info(1)
(biliapi.user模块YY中)
鉴权都在biliapi.auth,无脑biliapi.auth.login(usr, pwd)。程序会自动向Request注册包含鉴权信息(access_key cookies)的Auth对象(原先的设计是Request持有Auth对象)。唯一麻烦的就是oauth2(默认oauth2图片验证码,oauth3网页形式更加复杂)有个图片验证码,需要catch一个CapthcaRequire的Exception。具体可以看authtest.py(虽然名字叫test,但并没有单元测试,看起来更像是example 23333)。
最后还是咕咕咕。