2024-05-22 补充
请求标头需要增加 Referer 指向https://space.bilibili.com
为减少风控提高稳定性,可在设备登录自己账号后复制
dm_img_list
, dm_img_str
, dm_cover_img_str
, dm_img_inter
四个参数覆盖 getDm()
方法返回值。
壹;简介
基于 Kotlin 开发封装的 Bilibili 接口客户端, 支持 WebAPI 鉴权。
贰;相关代码
封装类,支持异步调用,同步执行可直接实例化 HttpBilibiliClient
class HttpBilibiliClient(private val apiUrl: String, private val parameters: String = "") {
private var wbi: Boolean = false
private val cookies: MutableList<String> = mutableListOf()
private val headers: MutableMap<String, List<String>> = mutableMapOf()
fun request(): JsonObject {
var appendParameters = parameters
// 当启用 WBI 签名
if (wbi) {
val rawWBIKey: String = "替换成 img_key" + "替换成 sub_key"
val mixinKeyEncTab = intArrayOf(
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
)
val key = StringBuilder()
for (i in 0..31) {
key.append(rawWBIKey[mixinKeyEncTab[i]])
}
val mixinKey = key.toString()
val wts = System.currentTimeMillis() / 1000
val tempParamenters = "${this.getUrlParameters("$appendParameters&wts=$wts")}$mixinKey"
appendParameters = "$appendParameters&w_rid=${DigestUtil.calculateMD5(tempParamenters)}&wts=$wts"
}
val client = URL("$apiUrl${if (appendParameters.isEmpty()) "" else "?$appendParameters"}")
with(client.openConnection() as HttpURLConnection) {
val response = StringBuilder()
setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76")
setRequestProperty("Accept", "*/*")
setRequestProperty("Connection", "keep-alive")
if (cookies.isNotEmpty()) {
val strJoiner = StringJoiner("; ")
cookies.forEach { strJoiner.add(it) }
setRequestProperty("Cookie", strJoiner.toString())
}
requestMethod = "GET"
inputStream.bufferedReader().use {
it.lines().forEach { line ->
response.append(line)
}
it.close()
headers.putAll(headerFields)
return JsonUtil.strToObject(response.toString())
}
}
}
fun setCookie(key: String, value: String): HttpBilibiliClient {
this.cookies.add("$key=$value")
return this
}
fun enableWBI(wbi: Boolean = false): HttpBilibiliClient {
this.wbi = wbi
return this
}
fun getHeaders(): Map<String, List<String>> {
return headers
}
private fun getUrlParameters(query: String): String {
if (query.isEmpty()) {
return query
}
val params = mutableMapOf<String, String>()
query.split("&").forEach { param ->
val (key, value) = param.split("=")
params[key] = value
}
val sortedParams = params.toSortedMap()
return sortedParams.entries.joinToString("&") { (key, value) -> "$key=${URLEncoder.encode(value, "utf8")}" }
}
}
object BilibiliClient {
fun openClient(apiUrl: String, parameters: String = "", wbi: Boolean = false, consumer: Consumer<JsonObject>) {
CompletableFuture.supplyAsync {
HttpBilibiliClient(apiUrl, parameters).enableWBI(wbi).request()
}.thenApply { it }.thenAccept { o -> consumer.accept(o) }
}
fun getDm(): String {
val dmRand = "ABCDEFGHIJK".toCharArray()
val dmImgList = "[]"
val dmImgStr = randomSample(dmRand, 2).joinToString("")
val dmCoverImgStr = randomSample(dmRand, 2).joinToString("")
val dmImgInter = "{\"ds\":[],\"wh\":[0,0,0],\"of\":[0,0,0]}"
val entries = listOf(
"dm_img_list" to dmImgList,
"dm_img_str" to dmImgStr,
"dm_cover_img_str" to dmCoverImgStr,
"dm_img_inter" to dmImgInter
)
return entries.joinToString("&") { "${it.first}=${it.second}" }
}
}
object DigestUtil {
fun calculateMD5(input: String): String {
val md = MessageDigest.getInstance("MD5")
md.update(input.toByteArray())
val bytes = md.digest()
val hexString = StringBuilder()
bytes.forEach {
val hex = Integer.toHexString(0xFF and it.toInt())
hexString.append(if (hex.length == 1) "0$hex" else hex)
}
return hexString.toString()
}
}
object JsonUtil {
private val gson: Gson = GsonBuilder().create()
fun strToObject(string: String): JsonObject {
return gson.fromJson(string, JsonObject::class.java)
}
}
调用例子
其他接口请自行查找实现,这里只用两个接口做示例。
// 获取指定用户视频列表
BilibiliClient.openClient(
"https://api.bilibili.com/x/space/wbi/arc/search",
"mid=232720681&ps=30&${BilibiliClient.getDm()}",
true
) {
println(it) // 请求成功后返回的数据
}
// 获取最新 img_url, sub_url
BilibiliClient.openClient("https://api.bilibili.com/x/web-interface/nav") {
println(it)
}
叁;结尾
以上就是本次分享的全部内容,感谢大家的阅读。