最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

go語言使用Chromedp實現(xiàn)二維碼登陸教程示例源碼

 更新時間:2022年04月28日 19:15:42   作者:EvaCcino  
這篇文章主要為大家介紹了go語言使用Chromedp實現(xiàn)二維碼登陸示例源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

源碼點擊下載

1 Chromedp是什么

chromedp是一個更快、更簡單的Golang庫用于調(diào)用支持Chrome DevTools協(xié)議的瀏覽器,同時不需要額外的依賴(例如Selenium和PhantomJS)

Chrome和Golang都與Google有著相當密切的關(guān)系,而Chrome DevTools其實就是Chrome瀏覽器按下F12之后的控制終端

2 為什么不使用Selenium

對于Golang開發(fā)來說,使用chromedp更為便捷,因為它僅僅需要Chrome瀏覽器而并不需要依賴ChromeDriver,省去了依賴問題,有助于自動化的構(gòu)建和多平臺架構(gòu)的遷移

3 文章解決了什么需求

  • 如何使用chromedp進行二維碼登陸
  • 如何將二維碼展示在無圖形化的終端上(makiuchi-d/gozxing解碼skip2/ go-qrcode編碼)
  • 如何保存Cookies實現(xiàn)短時間免登陸

網(wǎng)站會更新,文章不保證更新,請務必學會舉一反三

4.如何使用chromedp進行二維碼登陸

4.1 安裝chromedp

  • 下載并安裝Chrome瀏覽器
  • 創(chuàng)建Golang項目,開啟Go Module(在項目目錄下使用終端輸入go mod init)
  • 在項目目錄下使用終端輸入:
go get -u github.com/chromedp/chromedp

(如果有依賴問題請刪除-u)

4.2 嘗試打開網(wǎng)站

(以金山文檔https://account.wps.cn/為例)

1.重新設(shè)置chromedp使用"有頭"的方式打開,以便于我們進行debug

func main(){
    // chromdp依賴context上限傳遞參數(shù)
	ctx, _ := chromedp.NewExecAllocator(
		context.Background(),
		// 以默認配置的數(shù)組為基礎(chǔ),覆寫headless參數(shù)
		// 當然也可以根據(jù)自己的需要進行修改,這個flag是瀏覽器的設(shè)置
		append(
			chromedp.DefaultExecAllocatorOptions[:],
			chromedp.Flag("headless", false),
		)...,
	)
}

2.創(chuàng)建chromedp上下文對象

func main(){
    // chromdp依賴context上限傳遞參數(shù)
    ...
    // 創(chuàng)建新的chromedp上下文對象,超時時間的設(shè)置不分先后
    // 注意第二個返回的參數(shù)是cancel(),只是我省略了
	ctx, _ = context.WithTimeout(ctx, 30*time.Second)
	ctx, _ = chromedp.NewContext(
		ctx,
		// 設(shè)置日志方法
		chromedp.WithLogf(log.Printf),
	)
	// 通??梢允褂?defer cancel() 去取消
	// 但是在Windows環(huán)境下,我們希望程序能順帶關(guān)閉掉瀏覽器
	// 如果不希望瀏覽器關(guān)閉,使用cancel()方法即可
	// defer cancel()
	// defer chromedp.Cancel(ctx)
}

3.執(zhí)行自定義的任務

func main(){
    // chromdp依賴context上限傳遞參數(shù)
    ...
    // 創(chuàng)建新的chromedp上下文對象,超時時間的設(shè)置不分先后
    // 注意第二個返回的參數(shù)是cancel(),只是我省略了
    ...
    // 執(zhí)行我們自定義的任務 - myTasks函數(shù)在第4步
	if err := chromedp.Run(ctx, myTasks()); err != nil {
		log.Fatal(err)
		return
	}
}

4.至此程序的初始化過程已經(jīng)完成,接下來就是任務——打開登陸頁面

// 自定義任務
func myTasks() chromedp.Tasks {
	return chromedp.Tasks{
		// 1. 打開金山文檔的登陸界面
		chromedp.Navigate(loginURL),
	}
}

5.運行一下程序,可以看到Chrome被打開,同時訪問了我們指定的網(wǎng)站

4.3 獲取二維碼(點擊過程)

1.需要點擊微信登陸按鈕,先找到按鈕的選擇器,右鍵按鈕并在菜單中點擊檢查,然后可以看到按鈕的元素

2.右鍵元素打開菜單找到copy下的copy selector,即獲取到選擇器

3.我們嘗試點擊微信登陸按鈕,發(fā)現(xiàn)還需要點擊一下確認,重復上述步驟獲取確認按鈕的選擇器

4.用代碼執(zhí)行上述點擊步驟

// 自定義任務
func myTasks() chromedp.Tasks {
	return chromedp.Tasks{
		// 1. 打開金山文檔的登陸界面
		chromedp.Navigate(loginURL),
		// 2. 點擊微信登陸按鈕
		// #wechat > span:nth-child(2)
		chromedp.Click(`#wechat > span:nth-child(2)`),
		// 3. 點擊確認按鈕
		// #dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-ok
		chromedp.Click(`#dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-ok`),
	}
}

5.運行程序即可直達二維碼展示界面

6.用同樣的方式,獲取二維碼圖片的選擇器

7.用代碼實現(xiàn)獲取二維碼

有兩點需要注意,第一是二維碼有加載過程,第二是二維碼是元素渲染,

我們需要用截圖的方式獲取(也可以用js來獲取對應的href并下載,但是為了照顧小白,選擇最簡單的)

func myTasks() chromedp.Tasks {
	return chromedp.Tasks{
		// 1. 打開金山文檔的登陸界面
		...
		// 2. 點擊微信登陸按鈕
		...
		// 3. 點擊確認按鈕
		...
		// 4. 獲取二維碼
		// #wximport
		getCode(),
	}
}
func getCode() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		// 1. 用于存儲圖片的字節(jié)切片
		var code []byte
		// 2. 截圖
		// 注意這里需要注明直接使用ID選擇器來獲取元素(chromedp.ByID)
		if err = chromedp.Screenshot(`#wximport`, &code, chromedp.ByID).Do(ctx); err != nil {
			return
		}
		// 3. 保存文件
		if err = ioutil.WriteFile("code.png", code, 0755); err != nil {
			return
		}
		return
	}
}

8.執(zhí)行程序即可發(fā)現(xiàn)目錄下已經(jīng)存儲了二維碼圖片文件,我們可以通過掃描此二維碼進行登陸,與瀏覽器上掃描為同一種效果

5. 如何將二維碼展示在無圖形化的終端上

(與chromedp無關(guān),屬于額外內(nèi)容)

1.在上述步驟中,我們已經(jīng)獲取了二維碼,接下來我們需要在終端顯示二維碼,首先是解碼,這里使用gozxing庫

func printQRCode(code []byte) (err error) {
	// 1. 因為我們的字節(jié)流是圖像,所以我們需要先解碼字節(jié)流
	img, _, err := image.Decode(bytes.NewReader(code))
	if err != nil {
		return
	}
	// 2. 然后使用gozxing庫解碼圖片獲取二進制位圖
	bmp, err := gozxing.NewBinaryBitmapFromImage(img)
	if err != nil {
		return
	}
	// 3. 用二進制位圖解碼獲取gozxing的二維碼對象
	res, err := qrcode.NewQRCodeReader().Decode(bmp, nil)
	if err != nil {
		return
	}
	return
}

2.然后重新編碼來輸出二維碼到終端,這里使用go-qrcode庫

// 請注意import的庫發(fā)生了重名
import (
	"github.com/makiuchi-d/gozxing"
	"github.com/makiuchi-d/gozxing/qrcode"
	goQrcode "github.com/skip2/go-qrcode"
)
func printQRCode(code []byte) (err error) {
	// 1. 因為我們的字節(jié)流是圖像,所以我們需要先解碼字節(jié)流
	...
	// 2. 然后使用gozxing庫解碼圖片獲取二進制位圖
	...
	// 3. 用二進制位圖解碼獲取gozxing的二維碼對象
	...
	// 4. 用結(jié)果來獲取go-qrcode對象(注意這里我用了庫的別名)
	qr, err := goQrcode.New(res.String(), goQrcode.High)
	if err != nil {
		return
	}
	// 5. 輸出到標準輸出流
	fmt.Println(qr.ToSmallString(false))
	return
}

3.修改我們第二步的過程

func getCode() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		// 1. 用于存儲圖片的字節(jié)切片
		...
		// 2. 截圖
		// 注意這里需要注明直接使用ID選擇器來獲取元素(chromedp.ByID)
		...
		// 3. 把二維碼輸出到標準輸出流
		if err = printQRCode(code); err != nil {
			return err
		}
		return
	}
}

4.運行程序即可查看效果

6. 如何保存Cookies實現(xiàn)短時間免登陸

1.在上述過程中,我們可以通過二維碼掃描登陸,網(wǎng)站會在登陸之后進行跳轉(zhuǎn),跳轉(zhuǎn)后我們需要保存cookies來維持我們的登錄狀態(tài),代碼實現(xiàn)如下

// 保存Cookies
func saveCookies() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		// 等待二維碼登陸
		if err = chromedp.WaitVisible(`#app`, chromedp.ByID).Do(ctx); err != nil {
			return
		}
		// cookies的獲取對應是在devTools的network面板中
		// 1. 獲取cookies
		cookies, err := network.GetAllCookies().Do(ctx)
		if err != nil {
			return
		}
		// 2. 序列化
		cookiesData, err := network.GetAllCookiesReturns{Cookies: cookies}.MarshalJSON()
		if err != nil {
			return
		}
		// 3. 存儲到臨時文件
		if err = ioutil.WriteFile("cookies.tmp", cookiesData, 0755); err != nil {
			return
		}
		return
	}
}

2.獲取到Cookies之后,我們需要在程序運行時將Cookies從臨時文件中加載到瀏覽器中

// 加載Cookies
func loadCookies() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		// 如果cookies臨時文件不存在則直接跳過
		if _, _err := os.Stat("cookies.tmp"); os.IsNotExist(_err) {
			return
		}
		// 如果存在則讀取cookies的數(shù)據(jù)
		cookiesData, err := ioutil.ReadFile("cookies.tmp")
		if err != nil {
			return
		}
		// 反序列化
		cookiesParams := network.SetCookiesParams{}
		if err = cookiesParams.UnmarshalJSON(cookiesData); err != nil {
			return
		}
		// 設(shè)置cookies
		return network.SetCookies(cookiesParams.Cookies).Do(ctx)
	}
}

3.通過上述兩步我們已經(jīng)可以保持登陸狀態(tài),然后我們需要檢查一下是否成功,這里調(diào)用瀏覽器執(zhí)行js腳本獲取當前頁面的網(wǎng)址,判斷是否已經(jīng)個人中心頁面,如果為真,則停止操作

// 檢查是否登陸
func checkLoginStatus() chromedp.ActionFunc {
	return func(ctx context.Context) (err error) {
		var url string
		if err = chromedp.Evaluate(`window.location.href`, &url).Do(ctx); err != nil {
			return
		}
		if strings.Contains(url, "https://account.wps.cn/usercenter/apps") {
			log.Println("已經(jīng)使用cookies登陸")
			chromedp.Stop()
		}
		return
	}
}

4.最終重新設(shè)置我們的瀏覽器任務即可

// 自定義任務
func myTasks() chromedp.Tasks {
	return chromedp.Tasks{
		// 0. 加載cookies <-- 變動
		loadCookies(),
		// 1. 打開金山文檔的登陸界面
		...
		// 判斷一下是否已經(jīng)登陸  <-- 變動
		checkLoginStatus(),
		// 2. 點擊微信登陸按鈕
		// #wechat > span:nth-child(2)
		...
		// 3. 點擊確認按鈕
		// #dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-ok
		...
		// 4. 獲取二維碼
		// #wximport
		...
		// 5. 若二維碼登錄后,瀏覽器會自動跳轉(zhuǎn)到用戶信息頁面  <-- 變動
		saveCookies(),
	}
}

5.我們使用已經(jīng)登陸的cookies運行程序可以發(fā)現(xiàn)我們成功跳過登陸過程

以上就是go語言使用Chromedp實現(xiàn)二維碼登陸教程示例源碼的詳細內(nèi)容,更多關(guān)于go Chromedp二維碼登陸的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • GPT回答:go語言和C語言切片對比

    GPT回答:go語言和C語言切片對比

    這篇文章主要為大家介紹了GPT回答:go語言和C語言切片對比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • go?zero微服務實戰(zhàn)處理每秒上萬次的下單請求

    go?zero微服務實戰(zhàn)處理每秒上萬次的下單請求

    這篇文章主要為大家介紹了go?zero微服務實戰(zhàn)處理每秒上萬次的下單請求示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • go mod tidy加載模塊超時的問題及解決

    go mod tidy加載模塊超時的問題及解決

    go mod tidy加載模塊超時的問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Golang使用etcd構(gòu)建分布式鎖的示例分享

    Golang使用etcd構(gòu)建分布式鎖的示例分享

    在本教程中,我們將學習如何使用Go和etcd構(gòu)建分布式鎖系統(tǒng),分布式鎖系統(tǒng)對于管理對分布式系統(tǒng)中共享資源的并發(fā)訪問至關(guān)重要,它有助于維護一致性,防止競爭條件,并確保在任何給定時間只有一個進程獨占訪問資源,需要的朋友可以參考下
    2025-01-01
  • Go語言判斷文件或文件夾是否存在的方法

    Go語言判斷文件或文件夾是否存在的方法

    這篇文章主要介紹了Go語言判斷文件或文件夾是否存在的方法,結(jié)合具體實例形式對比分析了Go語言針對文件與目錄判斷的操作技巧與相關(guān)注意事項,需要的朋友可以參考下
    2017-05-05
  • golang函數(shù)的返回值實現(xiàn)

    golang函數(shù)的返回值實現(xiàn)

    本文主要介紹了golang函數(shù)的返回值實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • Go語言的常量、枚舉、作用域示例詳解

    Go語言的常量、枚舉、作用域示例詳解

    這篇文章主要介紹了Go語言的常量、枚舉、作用域,接下來,我們將詳細了解 Go 的變量作用域規(guī)則以及這些規(guī)則如何影響代碼編寫,需要的朋友可以參考下
    2024-07-07
  • Go語言定時任務的實現(xiàn)示例

    Go語言定時任務的實現(xiàn)示例

    本文主要介紹了Go語言定時任務的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • golang gin框架獲取參數(shù)的操作

    golang gin框架獲取參數(shù)的操作

    這篇文章主要介紹了golang gin框架獲取參數(shù)的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 一文理解Goland協(xié)程調(diào)度器scheduler的實現(xiàn)

    一文理解Goland協(xié)程調(diào)度器scheduler的實現(xiàn)

    本文主要介紹了Goland協(xié)程調(diào)度器scheduler的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06

最新評論

白水县| 宁蒗| 安图县| 乌兰县| 礼泉县| 濮阳市| 万载县| 乌海市| 梁山县| 建阳市| 广水市| 贡山| 余江县| 瑞安市| 威远县| 澳门| 潜山县| 彝良县| 柏乡县| 张北县| 岐山县| 梧州市| 鄱阳县| 韶关市| 苏尼特右旗| 郸城县| 密山市| 谢通门县| 东城区| 和田市| 崇阳县| 闻喜县| 故城县| 恩平市| 敦煌市| 乐平市| 青铜峡市| 博湖县| 平舆县| 韩城市| 南宁市|