XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/bilibili-API-collect

:sparkles: feat: add golang wbi demo (#696)

fc0c687
Jianqi Pan <jannchie@gmail.com>
提交于

代码差异

1 个文件 +153 -1
Modified docs/misc/sign/wbi.md +153 -1
@@ -93,7 +93,7 @@
93 93
94 94 ## Wbi签名算法实现Demo
95 95
96 该 Demo 提供 [Python](#Python)、[JavaScript](#JavaScript) 语言
96 该 Demo 提供 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang) 语言
97 97
98 98 ### Python
99 99
@@ -248,3 +248,155 @@ console.log(query)
248 248 ```
249 249 bar=514&baz=1919810&foo=114&wts=1684805578&w_rid=bb97e15f28edf445a0e4420d36f0157e
250 250 ```
251
252 ### Golang
253
254 需要 `github.com/tidwall/gjson` 作为依赖
255
256 ```golang
257 package main
258
259 import (
260 "crypto/md5"
261 "encoding/hex"
262 "fmt"
263 "io/ioutil"
264 "net/http"
265 "net/url"
266 "sort"
267 "strconv"
268 "strings"
269 "sync"
270 "time"
271
272 "github.com/tidwall/gjson"
273 )
274
275 var mixinKeyEncTab = []int{
276 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
277 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
278 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
279 36, 20, 34, 44, 52,
280 }
281
282 func getMixinKey(orig string) string {
283 var str strings.Builder
284 for _, v := range mixinKeyEncTab {
285 if v < len(orig) {
286 str.WriteByte(orig[v])
287 }
288 }
289 return str.String()[:32]
290 }
291 func EncWbi(params map[string]string, imgKey string, subKey string) map[string]string {
292 mixinKey := getMixinKey(imgKey + subKey)
293 currTime := strconv.FormatInt(time.Now().Unix(), 10)
294 params["wts"] = currTime
295 // Sort keys
296 keys := make([]string, 0, len(params))
297 for k := range params {
298 keys = append(keys, k)
299 }
300 sort.Strings(keys)
301 // Remove unwanted characters
302 for k, v := range params {
303 v = strings.ReplaceAll(v, "!", "")
304 v = strings.ReplaceAll(v, "'", "")
305 v = strings.ReplaceAll(v, "(", "")
306 v = strings.ReplaceAll(v, ")", "")
307 v = strings.ReplaceAll(v, "*", "")
308 params[k] = v
309 }
310 // Build URL parameters
311 var str strings.Builder
312 for _, k := range keys {
313 str.WriteString(fmt.Sprintf("%s=%s&", k, params[k]))
314 }
315 query := strings.TrimSuffix(str.String(), "&")
316 // Calculate w_rid
317 hash := md5.Sum([]byte(query + mixinKey))
318 params["w_rid"] = hex.EncodeToString(hash[:])
319 return params
320 }
321
322 var cache sync.Map
323 var lastUpdateTime time.Time
324
325 func updateCache() {
326 if time.Now().Sub(lastUpdateTime).Minutes() < 10 {
327 return
328 }
329 imgKey, subKey := GetWbiKeys()
330 cache.Store("imgKey", imgKey)
331 cache.Store("subKey", subKey)
332 lastUpdateTime = time.Now()
333 }
334
335 func GetWbiKeysCached() (string, string) {
336 updateCache()
337 imgKeyI, _ := cache.Load("imgKey")
338 subKeyI, _ := cache.Load("subKey")
339 return imgKeyI.(string), subKeyI.(string)
340 }
341
342 func GetWbiKeys() (string, string) {
343 resp, err := http.Get("https://api.bilibili.com/x/web-interface/nav")
344 if err != nil {
345 fmt.Println("Error:", err)
346 return "", ""
347 }
348 defer resp.Body.Close()
349 body, err := ioutil.ReadAll(resp.Body)
350 if err != nil {
351 fmt.Println("Error:", err)
352 return "", ""
353 }
354 json := string(body)
355 imgURL := gjson.Get(json, "data.wbi_img.img_url").String()
356 subURL := gjson.Get(json, "data.wbi_img.sub_url").String()
357 imgKey := strings.Split(strings.Split(imgURL, "/")[len(strings.Split(imgURL, "/"))-1], ".")[0]
358 subKey := strings.Split(strings.Split(subURL, "/")[len(strings.Split(subURL, "/"))-1], ".")[0]
359 return imgKey, subKey
360 }
361
362 func SignURL(urlStr string) string {
363 urlObj, _ := url.Parse(urlStr)
364 imgKey, subKey := GetWbiKeysCached()
365 fmt.Println(imgKey, subKey)
366 query := urlObj.Query()
367 params := map[string]string{}
368 for k, v := range query {
369 params[k] = v[0]
370 }
371 newParams := EncWbi(params, imgKey, subKey)
372 for k, v := range newParams {
373 query.Set(k, v)
374 }
375 urlObj.RawQuery = query.Encode()
376 newUrlStr := urlObj.String()
377 return newUrlStr
378 }
379 func main() {
380 urlStr := "https://api.bilibili.com/x/space/wbi/acc/info?mid=1850091"
381 newUrlStr := utils.SignURL(urlStr) // 签名
382 req, err := http.NewRequest("GET", newUrlStr, nil)
383 if err != nil {
384 return nil, err
385 }
386 // 设置请求头,模拟浏览器
387 req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
388 response, err := http.DefaultClient.Do(req)
389 fmt.Println(newUrlStr)
390 if err != nil {
391 fmt.Printf("请求发送失败:%s", err)
392 return nil, err
393 }
394 defer response.Body.Close()
395 body, err := ioutil.ReadAll(response.Body)
396 if err != nil {
397 fmt.Printf("读取响应失败:%s", err)
398 return nil, err
399 }
400 fmt.Println(string(body))
401 }
402 ```