diff --git a/README.md b/README.md index 30a9a7e..782ed73 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,35 @@ func main() { } ``` +或者可以使用扫码登录,此时无需手动指定cookie +```go +package main + +import ( + bg "github.com/iyear/biligo" + "fmt" + "time" +) + +func main() { + b, err := bg.NewBiliClientScanQrcode(&bg.BiliSetting{ + // DEBUG 模式将输出请求和响应 + DebugMode: true, + // Client: myClient, + // UserAgent: "My UA", + }) + + if err != nil { + log.Fatal("failed to make new bili client; error: ", err) + return + } + + fmt.Printf("mid: %d, uname: %s,userID: %s,rank: %s\n", b.Me.MID, b.Me.UName, b.Me.UserID, b.Me.Rank) + fmt.Printf("birthday: %s,sex: %s\n", b.Me.Birthday, b.Me.Sex) + fmt.Printf("sign: %s\n", b.Me.Sign) +} +``` + ### 例子 同目录下的 `example` 文件夹 diff --git a/bili_client.go b/bili_client.go index ea6644d..e5b6ae1 100644 --- a/bili_client.go +++ b/bili_client.go @@ -75,6 +75,36 @@ func NewBiliClient(setting *BiliSetting) (*BiliClient, error) { return bili, nil } +// NewBiliClientScanQrcode +// +// 通过扫描二维码获取Cookie无需手动设置Cookies +func NewBiliClientScanQrcode(setting *BiliSetting) (*BiliClient, error) { + cookies := util.GetCookie() + bili := &BiliClient{ + auth: &CookieAuth{ + DedeUserID: cookies.DedeUserID, + SESSDATA: cookies.SESSDATA, + BiliJCT: cookies.Bili_jct, + DedeUserIDCkMd5: cookies.DedeUserID__ckMd5, + }, + baseClient: newBaseClient(&baseSetting{ + Client: setting.Client, + DebugMode: setting.DebugMode, + UserAgent: setting.UserAgent, + Prefix: "BiliClient ", + }), + } + + account, err := bili.GetMe() + if err != nil { + return nil, err + } + + bili.Me = account + + return bili, nil +} + // GetMe // // 获取个人基本信息 diff --git a/go.mod b/go.mod index 7aa0f74..4a7ac31 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.16 require ( github.com/golang/protobuf v1.5.2 github.com/pkg/errors v0.9.1 + github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/tidwall/gjson v1.8.1 github.com/tidwall/pretty v1.2.0 // indirect google.golang.org/protobuf v1.27.1 diff --git a/go.sum b/go.sum index e3e5aef..543bae8 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/tidwall/gjson v1.8.1 h1:8j5EE9Hrh3l9Od1OIEDAb7IpezNA20UdRngNAj5N0WU= github.com/tidwall/gjson v1.8.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= diff --git a/internal/util/login_by_qrcode.go b/internal/util/login_by_qrcode.go new file mode 100644 index 0000000..3bb49e3 --- /dev/null +++ b/internal/util/login_by_qrcode.go @@ -0,0 +1,162 @@ +package util + +import ( + "crypto/tls" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" + + qrcode "github.com/skip2/go-qrcode" +) + +type Cookie struct { + SESSDATA string + Bili_jct string + DedeUserID string + DedeUserID__ckMd5 string + Sid string +} + +type GetQrcodeResponse struct { + Code int `json:"code"` + Message string `json:"message"` + Ttl int `json:"ttl"` + Data struct { + URL string `json:"url"` + QrcodeKey string `json:"qrcode_key"` + } `json:"data"` +} + +type ScanResponse struct { + Code int `json:"code"` + Message string `json:"message"` + Ttl int `json:"ttl"` + Data struct { + URL string `json:"url"` + RefreshToken string `json:"refresh_token"` + Timestamp int `json:"timestamp"` + Code int `json:"code"` + Message string `json:"message"` + } `json:"data"` +} + +func getQrcode() *GetQrcodeResponse { + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + Timeout: time.Second * 30, + } + + req, err := http.NewRequest("GET", "https://passport.bilibili.com/x/passport-login/web/qrcode/generate", nil) + if err != nil { + panic(err) + } + + req.Header = http.Header{ + "Referer": []string{"https://passport.bilibili.com/login?from_spm_id=333.851.top_bar.login_window"}, + "User-Agent": []string{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.51 Safari/537.36 Edg/93.0.961.27"}, + } + + // Send the GET request + resp, err := client.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + // Read the response body + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + // Parse the JSON data + var getQrcodeResp *GetQrcodeResponse + if err := json.Unmarshal(body, &getQrcodeResp); err != nil { + panic(err) + } + + qr, err := qrcode.New(getQrcodeResp.Data.URL, qrcode.Medium) + if err != nil { + fmt.Println("无法生成二维码:", err) + return nil + } + + // 打印二维码到控制台 + fmt.Println(qr.ToSmallString(false)) + + return getQrcodeResp +} + +func getCookie(getQrcodeResp *GetQrcodeResponse) *Cookie { + // 等待扫码 + fmt.Println("请在8秒内完成扫码...") + time.Sleep(time.Second * 8) + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + Timeout: time.Second * 30, + } + + url := "https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=" + getQrcodeResp.Data.QrcodeKey + req, err := http.NewRequest("GET", url, nil) + if err != nil { + panic(err) + } + + req.Header = http.Header{ + "Referer": []string{"https://passport.bilibili.com/login?from_spm_id=333.851.top_bar.login_window"}, + "User-Agent": []string{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.51 Safari/537.36 Edg/93.0.961.27"}, + } + + // Send the GET request + resp, err := client.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + // Read the response body + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + // 解析 JSON 数据 + var scanResp *ScanResponse + if err := json.Unmarshal(body, &scanResp); err != nil { + panic(err) + } + + if scanResp.Message != "0" { + fmt.Println("扫码失败") + } + + cookies := resp.Cookies() + result := &Cookie{} + for _, cookie := range cookies { + switch cookie.Name { + case "SESSDATA": + result.SESSDATA = cookie.Value + case "bili_jct": + result.Bili_jct = cookie.Value + case "DedeUserID": + result.DedeUserID = cookie.Value + case "DedeUserID__ckMd5": + result.DedeUserID__ckMd5 = cookie.Value + case "sid": + result.Sid = cookie.Value + } + } + return result +} + +func GetCookie() *Cookie { + resp := getQrcode() + cookies := getCookie(resp) + return cookies +}