日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Golang爬虫终极杀器——Chromedp让你成为二维码登陆终结者(教程)

發(fā)布時(shí)間:2023/12/29 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Golang爬虫终极杀器——Chromedp让你成为二维码登陆终结者(教程) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Golang爬蟲終極殺器——Chromedp讓你成為二維碼登陸終結(jié)者(教程)

  • Github源碼 - chromedp
  • 文章項(xiàng)目Gitee源碼
  • 1 Chromedp是什么

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

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

    2 為什么不使用Selenium

    對(duì)于Golang開發(fā)來說,使用chromedp更為便捷,因?yàn)樗鼉H僅需要Chrome瀏覽器而并不需要依賴ChromeDriver,省去了依賴問題,有助于自動(dòng)化的構(gòu)建和多平臺(tái)架構(gòu)的遷移

    3 文章解決了什么需求

  • 如何使用chromedp進(jìn)行二維碼登陸
  • 如何將二維碼展示在無圖形化的終端上(makiuchi-d/gozxing解碼 skip2/ go-qrcode編碼)
  • 如何保存Cookies實(shí)現(xiàn)短時(shí)間免登陸
  • 網(wǎng)站會(huì)更新,文章不保證更新,請(qǐng)務(wù)必學(xué)會(huì)舉一反三

    4 如何使用chromedp進(jìn)行二維碼登陸

    4.1 安裝chromedp

  • 下載并安裝Chrome瀏覽器
  • 創(chuàng)建Golang項(xiàng)目,開啟Go Module(在項(xiàng)目目錄下使用終端輸入go mod init)
  • 在項(xiàng)目目錄下使用終端輸入:go get -u github.com/chromedp/chromedp(如果有依賴問題請(qǐng)刪除-u)
  • 4.2 嘗試打開網(wǎng)站(以金山文檔https://account.wps.cn/為例)

  • 重新設(shè)置chromedp使用"有頭"的方式打開,以便于我們進(jìn)行debug
  • func main(){// chromdp依賴context上限傳遞參數(shù)ctx, _ := chromedp.NewExecAllocator(context.Background(),// 以默認(rèn)配置的數(shù)組為基礎(chǔ),覆寫headless參數(shù)// 當(dāng)然也可以根據(jù)自己的需要進(jìn)行修改,這個(gè)flag是瀏覽器的設(shè)置append(chromedp.DefaultExecAllocatorOptions[:],chromedp.Flag("headless", false),)...,) }
  • 創(chuàng)建chromedp上下文對(duì)象
  • func main(){// chromdp依賴context上限傳遞參數(shù)...// 創(chuàng)建新的chromedp上下文對(duì)象,超時(shí)時(shí)間的設(shè)置不分先后// 注意第二個(gè)返回的參數(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) }
  • 執(zhí)行自定義的任務(wù)
  • func main(){// chromdp依賴context上限傳遞參數(shù)...// 創(chuàng)建新的chromedp上下文對(duì)象,超時(shí)時(shí)間的設(shè)置不分先后// 注意第二個(gè)返回的參數(shù)是cancel(),只是我省略了...// 執(zhí)行我們自定義的任務(wù) - myTasks函數(shù)在第4步if err := chromedp.Run(ctx, myTasks()); err != nil {log.Fatal(err)return} }
  • 至此程序的初始化過程已經(jīng)完成,接下來就是任務(wù)——打開登陸頁面
  • // 自定義任務(wù) func myTasks() chromedp.Tasks {return chromedp.Tasks{// 1. 打開金山文檔的登陸界面chromedp.Navigate(loginURL),} }
  • 運(yùn)行一下程序,可以看到Chrome被打開,同時(shí)訪問了我們指定的網(wǎng)站
  • 4.3 獲取二維碼(點(diǎn)擊過程)

  • 需要點(diǎn)擊微信登陸按鈕,先找到按鈕的選擇器,右鍵按鈕并在菜單中點(diǎn)擊檢查,然后可以看到按鈕的元素
  • 右鍵元素打開菜單找到copy下的copy selector,即獲取到選擇器
  • 我們嘗試點(diǎn)擊微信登陸按鈕,發(fā)現(xiàn)還需要點(diǎn)擊一下確認(rèn),重復(fù)上述步驟獲取確認(rèn)按鈕的選擇器
  • 用代碼執(zhí)行上述點(diǎn)擊步驟
  • // 自定義任務(wù) func myTasks() chromedp.Tasks {return chromedp.Tasks{// 1. 打開金山文檔的登陸界面chromedp.Navigate(loginURL),// 2. 點(diǎn)擊微信登陸按鈕// #wechat > span:nth-child(2)chromedp.Click(`#wechat > span:nth-child(2)`),// 3. 點(diǎn)擊確認(rèn)按鈕// #dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-okchromedp.Click(`#dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-ok`),} }
  • 運(yùn)行程序即可直達(dá)二維碼展示界面
  • 用同樣的方式,獲取二維碼圖片的選擇器
  • 用代碼實(shí)現(xiàn)獲取二維碼,有兩點(diǎn)需要注意,第一是二維碼有加載過程,第二是二維碼是元素渲染,我們需要用截圖的方式獲取(也可以用js來獲取對(duì)應(yīng)的href并下載,但是為了照顧小白,選擇最簡(jiǎn)單的)
  • func myTasks() chromedp.Tasks {return chromedp.Tasks{// 1. 打開金山文檔的登陸界面...// 2. 點(diǎn)擊微信登陸按鈕...// 3. 點(diǎn)擊確認(rèn)按鈕...// 4. 獲取二維碼// #wximportgetCode(),} }func getCode() chromedp.ActionFunc {return func(ctx context.Context) (err error) {// 1. 用于存儲(chǔ)圖片的字節(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} }
  • 執(zhí)行程序即可發(fā)現(xiàn)目錄下已經(jīng)存儲(chǔ)了二維碼圖片文件,我們可以通過掃描此二維碼進(jìn)行登陸,與瀏覽器上掃描為同一種效果
  • 5. 如何將二維碼展示在無圖形化的終端上(與chromedp無關(guān),屬于額外內(nèi)容)

  • 在上述步驟中,我們已經(jīng)獲取了二維碼,接下來我們需要在終端顯示二維碼,首先是解碼,這里使用gozxing庫
  • func printQRCode(code []byte) (err error) {// 1. 因?yàn)槲覀兊淖止?jié)流是圖像,所以我們需要先解碼字節(jié)流img, _, err := image.Decode(bytes.NewReader(code))if err != nil {return}// 2. 然后使用gozxing庫解碼圖片獲取二進(jìn)制位圖bmp, err := gozxing.NewBinaryBitmapFromImage(img)if err != nil {return}// 3. 用二進(jìn)制位圖解碼獲取gozxing的二維碼對(duì)象res, err := qrcode.NewQRCodeReader().Decode(bmp, nil)if err != nil {return}return }
  • 然后重新編碼來輸出二維碼到終端,這里使用go-qrcode庫
  • // 請(qǐng)注意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. 因?yàn)槲覀兊淖止?jié)流是圖像,所以我們需要先解碼字節(jié)流...// 2. 然后使用gozxing庫解碼圖片獲取二進(jìn)制位圖...// 3. 用二進(jìn)制位圖解碼獲取gozxing的二維碼對(duì)象...// 4. 用結(jié)果來獲取go-qrcode對(duì)象(注意這里我用了庫的別名)qr, err := goQrcode.New(res.String(), goQrcode.High)if err != nil {return}// 5. 輸出到標(biāo)準(zhǔn)輸出流fmt.Println(qr.ToSmallString(false))return }
  • 修改我們第二步的過程
  • func getCode() chromedp.ActionFunc {return func(ctx context.Context) (err error) {// 1. 用于存儲(chǔ)圖片的字節(jié)切片...// 2. 截圖// 注意這里需要注明直接使用ID選擇器來獲取元素(chromedp.ByID)...// 3. 把二維碼輸出到標(biāo)準(zhǔn)輸出流if err = printQRCode(code); err != nil {return err}return} }
  • 運(yùn)行程序即可查看效果
  • 6. 如何保存Cookies實(shí)現(xiàn)短時(shí)間免登陸

  • 在上述過程中,我們可以通過二維碼掃描登陸,網(wǎng)站會(huì)在登陸之后進(jìn)行跳轉(zhuǎn),跳轉(zhuǎn)后我們需要保存cookies來維持我們的登錄狀態(tài),代碼實(shí)現(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的獲取對(duì)應(yīng)是在devTools的network面板中// 1. 獲取cookiescookies, err := network.GetAllCookies().Do(ctx)if err != nil {return}// 2. 序列化cookiesData, err := network.GetAllCookiesReturns{Cookies: cookies}.MarshalJSON()if err != nil {return}// 3. 存儲(chǔ)到臨時(shí)文件if err = ioutil.WriteFile("cookies.tmp", cookiesData, 0755); err != nil {return}return} }
  • 獲取到Cookies之后,我們需要在程序運(yùn)行時(shí)將Cookies從臨時(shí)文件中加載到瀏覽器中
  • // 加載Cookies func loadCookies() chromedp.ActionFunc {return func(ctx context.Context) (err error) {// 如果cookies臨時(shí)文件不存在則直接跳過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è)置cookiesreturn network.SetCookies(cookiesParams.Cookies).Do(ctx)} }
  • 通過上述兩步我們已經(jīng)可以保持登陸狀態(tài),然后我們需要檢查一下是否成功,這里調(diào)用瀏覽器執(zhí)行js腳本獲取當(dāng)前頁面的網(wǎng)址,判斷是否已經(jīng)個(gè)人中心頁面,如果為真,則停止操作
  • // 檢查是否登陸 func checkLoginStatus() chromedp.ActionFunc {return func(ctx context.Context) (err error) {var url stringif 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} }
  • 最終重新設(shè)置我們的瀏覽器任務(wù)即可
  • // 自定義任務(wù) func myTasks() chromedp.Tasks {return chromedp.Tasks{// 0. 加載cookies <-- 變動(dòng)loadCookies(),// 1. 打開金山文檔的登陸界面...// 判斷一下是否已經(jīng)登陸 <-- 變動(dòng)checkLoginStatus(),// 2. 點(diǎn)擊微信登陸按鈕// #wechat > span:nth-child(2)...// 3. 點(diǎn)擊確認(rèn)按鈕// #dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-ok...// 4. 獲取二維碼// #wximport...// 5. 若二維碼登錄后,瀏覽器會(huì)自動(dòng)跳轉(zhuǎn)到用戶信息頁面 <-- 變動(dòng)saveCookies(),} }
  • 我們使用已經(jīng)登陸的cookies運(yùn)行程序可以發(fā)現(xiàn)我們成功跳過登陸過程
  • 總結(jié)

    以上是生活随笔為你收集整理的Golang爬虫终极杀器——Chromedp让你成为二维码登陆终结者(教程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。