28

BiliAPI Python版本重构手记

 5 years ago
source link: https://blog.kaaass.net/archives/910?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

和我有过邮件联系的dalao们应该会发现,两年前我就提及BiliAPI会有Python版本,然而……咕咕咕。然后最近,一股

来自东方的 神秘力量催使我又打开了这个项目。于是我翻了翻Python3.6的新特性,又跑过来填坑了。然而惨不忍睹的旧设计实在是没有改的空间了,于是我打算开始一波重构。repo位于码云: https://gitee.com/kaaass/biliapi_python

,重构分支为reconstruct,欢迎Star、测试、issue、PR。

看commit和issue记录你会发现,其实已经有一次重构了,但是由于当时设计的时候并没有考虑到一些接口的特性,所以后续开发根本没法弄。现在借鉴了一下B站客户端的实现,重新进行了设计。

请求部分目前已经重写完成。采用了ISigner实现不同的签名方式,参数拼接采用了IParamAppender接口来实现。引入了Builder,采用链式调用让代码看着更舒服。旧的请求方法也是完全支持的,所以现在有三种接口请求的方法。

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对象。比如获取某个用户的信息,两行足矣:

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)。

最后还是咕咕咕。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK