Golang 百度云扫码登录

文件结构:

在这里插入图片描述

http_client.go代码如下:

package client

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"
)


// HTTPClient http client
type HTTPClient struct {
	*http.Client
	UserAgent string
}

var (
	UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"
)


func NewHTTPClient() *HTTPClient {

	j,_ := cookiejar.New(nil)
	h := &HTTPClient{
		Client: &http.Client{
			Timeout: 30 * time.Second,
			Jar:j,
		},
		UserAgent: UserAgent,
	}

	return h
}

// SetUserAgent 设置 UserAgent 浏览器标识
func (h *HTTPClient) SetUserAgent(ua string) {
	h.UserAgent = ua
}

// SetTimeout 设置 http 请求超时时间, 默认30s
func (h *HTTPClient) SetTimeout(t time.Duration) {
	h.Client.Timeout = t
}


func(h *HTTPClient)Fetch(webUrl string,method string,headers map[string]string,data interface{})(respBody []byte,err error){

	var req *http.Request
	var obody io.Reader
	if data != nil {
		switch value := data.(type) {
		case io.Reader:
			obody = value
		case map[string]string:
			query := url.Values{}
			for k := range value {
				query.Set(k, value[k])
			}
			obody = strings.NewReader(query.Encode())
		case map[string]interface{}:
			query := url.Values{}
			for k := range value {
				query.Set(k, fmt.Sprint(value[k]))
			}
			obody = strings.NewReader(query.Encode())
		case map[interface{}]interface{}:
			query := url.Values{}
			for k := range value {
				query.Set(fmt.Sprint(k), fmt.Sprint(value[k]))
			}
			obody = strings.NewReader(query.Encode())
		case string:
			obody = strings.NewReader(value)
		case []byte:
			obody = bytes.NewReader(value[:])
		default:
			return nil, fmt.Errorf("requester.Req: unknown post type: %s", value)
		}
	}

	req, err = http.NewRequest(method, webUrl, obody)
	if err!=nil{
		return
	}
	if headers!=nil{
		for k,v:=range headers{
			req.Header.Set(k,v)
		}
	}

	if method==http.MethodPost{
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	req.Header.Set("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36")

	resp,err:=h.Client.Do(req)
	if err!=nil{
		return
	}
	defer resp.Body.Close()
	//fmt.Println("res Cookies is :",resp.Cookies())
	//u,_:= url.Parse(webUrl)
	//h.Client.Jar.SetCookies(u,resp.Cookies())
	//fmt.Println("cookie jar is:",h.Client.Jar.Cookies(u))
	respBody,err=ioutil.ReadAll(resp.Body)
	return
}

main.go代码如下:

package main

import (
	"baidu_qr/client"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/robertkrimen/otto"
)

type QrImageData struct {
	ImageUrl string `json:"imgurl"`
	Errno    int64  `json:"errno"`
	Sign     string `json:"sign"`
}

type QueryData struct {
	ChannelV string `json:"channel_v"`
}

type QrCodeLogin struct {
	httpClient *client.HTTPClient
}

func (q *QrCodeLogin) initClient() {
	q.httpClient = client.NewHTTPClient()
}

func (*QrCodeLogin) generateGid() (gid string, err error) {
	vm := otto.New()
	vm.Run(`
        function u(x, K) {
			x += '';
			for (var N = [], T = 0; T < K.length; T++) N[T % 4] ^= K.charCodeAt(T);
			var U = ['EC', 'OK'],
			V = [];
			V[0] = x >> 24 & 255 ^ U[0].charCodeAt(0);
			V[1] = x >> 16 & 255 ^ U[0].charCodeAt(1);
			V[2] = x >> 8 & 255 ^ U[1].charCodeAt(0);
			V[3] = x & 255 ^ U[1].charCodeAt(1);
			U = [];
			for (T = 0; T < 8; T++) U[T] = T % 2 == 0 ? N[T >> 1] : V[T >> 1];
			N = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
			V = '';
			for (T = 0; T < U.length; T++) {
				V += N[U[T] >> 4 & 15];
				V += N[U[T] & 15]
			}
			return V
        }

		function generate_gid() {
			return "xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(e) {
				var t = 16 * Math.random() | 0
				var n = "x" === e ? t : 3 & t | 8;
				return n.toString(16)
			}).toUpperCase()
		}
        
		//var abc = '1'+'2'

		`)
	//使用vm.Call(函数名,nil,传递的参数,如果后面有多个参数,用逗号隔开就可以了)
	//value, _ := vm.Call("u", nil, "12345678", "234")
	//value, _ := vm.Get("abc")
	var value otto.Value
	value, err = vm.Call("generate_gid", nil)
	if err != nil {
		fmt.Println("generate gid error,error is:", err.Error())
		return
	}
	fmt.Println(value)
	gid = value.String()
	return
}

func (q *QrCodeLogin) getQrCode(gid string) (callBack string, respBody []byte, err error) {

	t := int64(time.Now().Unix() * 1000)
	t1 := t + 21232
	t2 := t1 + 4
	callBack = fmt.Sprintf("tangram_guid_%d", t)
	webUrl := fmt.Sprintf("https://passport.baidu.com/v2/api/getqrcode?lp=pc&qrloginfrom=pc&gid=%s&callback=%s&apiver=v3&tt=%d&tpl=netdisk&_=%d", gid, callBack, t1, t2)

	headers := map[string]string{
		"Accept":          "*/*",
		"Accept-Encoding": "gzip, deflate, br",
		"Accept-Language": "en,zh-CN;q=0.9,zh;q=0.8",
		"Connection":      "keep-alive",
		"Host":            "passport.baidu.com",
		"Referer":         "https://pan.baidu.com/",
		"Sec-Fetch-Dest":  "script",
		"Sec-Fetch-Mode":  "no-cors",
		"Sec-Fetch-Site":  "same-site",
		"User-Agent":      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
	}

	respBody, err = q.httpClient.Fetch(webUrl, http.MethodGet, headers, nil)
	if err != nil {
		fmt.Println("get image url error,error is:", err.Error())
		return
	}

	fmt.Println("res is:", string(respBody))
	return
}

func (q *QrCodeLogin) downloadQrCode(imageUrl string) (err error) {

	headers := map[string]string{
		"Accept":          "image/webp,image/apng,image/*,*/*;q=0.8",
		"Accept-Encoding": "gzip, deflate, br",
		"Accept-Language": "en,zh-CN;q=0.9,zh;q=0.8",
		"Connection":      "keep-alive",
		"Host":            "passport.baidu.com",
		"Referer":         "https://pan.baidu.com/",
		"Sec-Fetch-Dest":  "image",
		"Sec-Fetch-Mode":  "no-cors",
		"Sec-Fetch-Site":  "same-site",
		"User-Agent":      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
	}
	respBody, err := q.httpClient.Fetch(imageUrl, http.MethodGet, headers, nil)
	if err!=nil {
		panic(err)
	}

	file, err := ioutil.TempFile("", "*.png")
	if err != nil {
		panic(err)
	}
	//defer os.Remove(file.Name())

	_, err = file.Write(respBody)
	if err!=nil {
		panic(err)
	}
	file.Close()
	fmt.Println("qrcode image file path is:",file.Name())
	//imageFile, err := os.Create("F:\\test\\baidu.png")
	//defer imageFile.Close()
	//
	//if err != nil {
	//	return
	//}
	//
	//imageFile.Write(respBody)
	return
}

func (q *QrCodeLogin) queryQrCode(channelId string, gid string) (v string, err error) {

	for ; ; {

		time.Sleep(2 * time.Second)
		t := time.Now().Unix() * 1000
		callBack := fmt.Sprintf("tangram_guid_%d", t)
		t1 := t + 5
		t2 := t1 + 5

		webUrl := fmt.Sprintf("https://passport.baidu.com/channel/unicast?channel_id=%s&tpl=netdisk&gid=%s&callback=%s&apiver=v3&tt=%d&_=%d", channelId, gid, callBack, t1, t2)
		headers := map[string]string{
			"Accept":          "*/*",
			"Accept-Encoding": "gzip, deflate, br",
			"Accept-Language": "en,zh-CN;q=0.9,zh;q=0.8",
			"Connection":      "keep-alive",
			"Host":            "passport.baidu.com",
			"Referer":         "https://pan.baidu.com/",
			"Sec-Fetch-Dest":  "script",
			"Sec-Fetch-Mode":  "no-cors",
			"Sec-Fetch-Site":  "same-site",
			"User-Agent":      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
		}

		var respBody []byte
		respBody, err = q.httpClient.Fetch(webUrl, http.MethodGet, headers, nil)
		if err != nil {
			fmt.Println("error is:", err.Error())
			return
		}

		reg := regexp.MustCompile(fmt.Sprintf("%s\\(([\\S]+?)\\)", callBack))
		res := reg.FindAllSubmatch(respBody, -1)

		if len(res) <= 0 {
			return
		}

		respBody = res[0][1]
		d := &QueryData{}
		fmt.Println("res is:", string(respBody))

		err = json.Unmarshal(respBody, d)
		if err != nil {
			fmt.Println("error is:", err.Error())
			return
		}

		channelV := d.ChannelV
		fmt.Println("channel v is:", channelV)
		var tempMap map[string]interface{}

		err = json.Unmarshal([]byte(channelV), &tempMap)
		if err != nil {
			fmt.Println("error is:", err.Error())
			continue
		}
		var ok bool
		v, ok = tempMap["v"].(string)
		if ok {
			fmt.Println("tempMap v is:", v)
			return
		}
	}

	return
}


func (q *QrCodeLogin) parseCallBackData(callBack string,respBody []byte) (parsedBody []byte,err error){

	if callBack == ""{
		return
	}
	reg := regexp.MustCompile(fmt.Sprintf("%s\\(([\\s\\S]+?)\\)", callBack))
	res := reg.FindAllSubmatch(respBody, -1)

	if len(res) <= 0 {
		err = errors.New("CallBackError")
		return
	}

	parsedBody = res[0][1]
	return
}

func (q *QrCodeLogin) login(fakeBduss string) (bduss string,err error) {

	t := time.Now().Unix() * 1000
	t1 := t + 225
	callBack:="bd__cbs__ay6xvs"
	webUrl := fmt.Sprintf("https://passport.baidu.com/v3/login/main/qrbdusslogin?v=%d&bduss=%s&loginVersion=v4&qrcode=1&tpl=netdisk&apiver=v3&tt=%d&traceid=&time=%d&alg=v3&callback=%s", t, fakeBduss, t, t1, callBack)
	webUrl = webUrl + "&u=https%253A%252F%252Fpan.baidu.com%252Fdisk%252Fhome"
	headers := map[string]string{
		"Accept":                    "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
		"Accept-Encoding":           "deflate, br",
		"Accept-Language":           "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
		"Cache-Control":             "max-age=0",
		"Connection":                "keep-alive",
		"Host":                      "passport.baidu.com",
		"Sec-Fetch-Dest":            "document",
		"Sec-Fetch-Mode":            "navigate",
		"Sec-Fetch-Site":            "none",
		"Sec-Fetch-User":            "?1",
		"Upgrade-Insecure-Requests": "1",
		"User-Agent":                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66",
	}
	var respBody []byte
	respBody, err = q.httpClient.Fetch(webUrl, http.MethodGet, headers, nil)
	if err != nil {
		fmt.Println("error is:", err.Error())
		return
	}

	respBody,err = q.parseCallBackData(callBack,respBody)
	if err!=nil{
		fmt.Println("parse callback data error",err.Error())
		return
	}
	fmt.Println("-----------------------------------------------------------------------------------------------")
	text := string(respBody)
	fmt.Println("res is:", text)
	// "Accept-Encoding":           "deflate, br", 去掉了gzip 解码有点问题
	text = strings.ReplaceAll(text, "'", "\"") // 返回的格式中 'data' 可能是单引号 
	text = strings.ReplaceAll(text, " ", "")
	text = strings.ReplaceAll(text, "\\", "")
	fmt.Println("text is :", text)
	d := &LoginData{}
	err = json.Unmarshal([]byte(text), d)
	if err != nil {
		fmt.Println("error is:", err.Error())
		return
	}
	bduss = d.Data.Session.Bduss
	fmt.Println("-----------------------------------------------------------------------------------------------")
	fmt.Println("bduss is:", bduss)    // 只需要bduss的可以下车了
	fmt.Println("-----------------------------------------------------------------------------------------------")
	return
}

type LoginData struct {
	Data SessionData `json:"data"`
}

type SessionData struct {
	Session SessionInfo `json:"session"`
}
type SessionInfo struct {
	Bduss  string `json:"bduss"`
	Stoken string `json:"stoken"`
	Ptoken string `json:"ptoken"`
}

func (q *QrCodeLogin) getHomePage() {

	webUrl := "https://pan.baidu.com/disk/home"
	headers := map[string]string{
		"Host": "pan.baidu.com",
		"Connection": "keep-alive",
		"Upgrade-Insecure-Requests": "1",
		"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
		"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
		"Sec-Fetch-Site": "same-origin",
		"Sec-Fetch-Mode": "navigate",
		"Sec-Fetch-Dest": "document",
		"Referer": "https://pan.baidu.com/",
		"Accept-Language": "en,zh-CN;q=0.9,zh;q=0.8",
	}
	respBody,err:=q.httpClient.Fetch(webUrl,http.MethodGet,headers,nil)
	if err!=nil{
		fmt.Println("error is:",err.Error())
		return
	}
	fmt.Println("home page res is",string(respBody))
}

func (q *QrCodeLogin)getBdstoken()(bdstoken string,err error){

	webUrl := "https://tongxunlu.baidu.com"

	respBody,err:=q.httpClient.Fetch(webUrl,http.MethodGet,nil,nil)
	fmt.Println("bdstoken res is",string(respBody))
	if err != nil {
		fmt.Println("error is",err.Error())
		return
	}

	reg := regexp.MustCompile(`var bdstoken = '(.*?)'`)
	res := reg.FindAllSubmatch(respBody, -1)

	//fmt.Println("bdstoken is", string(res[0][1]))
	if len(res)>0{
		if len(res[0])>1{
			bdstoken=string(res[0][1])
		}
	}
	if bdstoken==""{
		err=errors.New("bdstoken not found")
	}
	return
}



func main() {

	q := &QrCodeLogin{}
	q.initClient()
	gid, err := q.generateGid()
	if err != nil {
		return
	}
	fmt.Println("gid is:", gid)

	callBack, respBody, err := q.getQrCode(gid)
	if err != nil {
		return
	}

	reg := regexp.MustCompile(fmt.Sprintf("%s\\(([\\S]+?)\\)", callBack))
	res := reg.FindAllSubmatch(respBody, -1)

	if len(res) <= 0 {
		return
	}

	respBody = res[0][1]
	d := &QrImageData{}

	err = json.Unmarshal(respBody, d)
	if err != nil {
		fmt.Println("error is:", err.Error())
		return
	}
	sign := d.Sign

	imageUrl := fmt.Sprintf("https://%s", d.ImageUrl)
	fmt.Println("image url is:", imageUrl)

	q.downloadQrCode(imageUrl)

	channelV, err := q.queryQrCode(sign, gid)
	if err != nil {
		fmt.Println("error is:", err.Error())
		return
	}
	fmt.Println("channelV is:", channelV)
	q.login(channelV)

	q.getHomePage()

	fmt.Println("------------------------------------------------------------")
	bdstoken,err:=q.getBdstoken()
	if err!=nil{
		fmt.Println("failed to get bdstoken,error is:",err.Error())
		return
	}

	fmt.Println("bdstoken is:",bdstoken)
}


找到输出的路径并用百度云APP扫码,确认登录就行,二维码路径在临时目录中:在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值