go语言使用Chromedp实现二维码登陆教程示例源码
来源:脚本之家
时间:2022-12-30 16:45:57 104浏览 收藏
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《go语言使用Chromedp实现二维码登陆教程示例源码》,聊聊goChromedp、二维码、登陆,我们一起来看看吧!
1 Chromedp是什么
chromedp是一个更快、更简单的Golang库用于调用支持Chrome DevTools协议的浏览器,同时不需要额外的依赖(例如Selenium和PhantomJS)
Chrome和Golang都与Google有着相当密切的关系,而Chrome DevTools其实就是Chrome浏览器按下F12之后的控制终端
2 为什么不使用Selenium
对于Golang开发来说,使用chromedp更为便捷,因为它仅仅需要Chrome浏览器而并不需要依赖ChromeDriver,省去了依赖问题,有助于自动化的构建和多平台架构的迁移
3 文章解决了什么需求
- 如何使用chromedp进行二维码登陆
- 如何将二维码展示在无图形化的终端上(makiuchi-d/gozxing解码skip2/ go-qrcode编码)
- 如何保存Cookies实现短时间免登陆
网站会更新,文章不保证更新,请务必学会举一反三
4.如何使用chromedp进行二维码登陆
4.1 安装chromedp
- 下载并安装Chrome浏览器
- 创建Golang项目,开启Go Module(在项目目录下使用终端输入go mod init)
- 在项目目录下使用终端输入:
go get -u github.com/chromedp/chromedp
(如果有依赖问题请删除-u)
4.2 尝试打开网站
(以金山文档https://account.wps.cn/为例)
1.重新设置chromedp使用"有头"的方式打开,以便于我们进行debug
func main(){ // chromdp依赖context上限传递参数 ctx, _ := chromedp.NewExecAllocator( context.Background(), // 以默认配置的数组为基础,覆写headless参数 // 当然也可以根据自己的需要进行修改,这个flag是浏览器的设置 append( chromedp.DefaultExecAllocatorOptions[:], chromedp.Flag("headless", false), )..., ) }
2.创建chromedp上下文对象
func main(){ // chromdp依赖context上限传递参数 ... // 创建新的chromedp上下文对象,超时时间的设置不分先后 // 注意第二个返回的参数是cancel(),只是我省略了 ctx, _ = context.WithTimeout(ctx, 30*time.Second) ctx, _ = chromedp.NewContext( ctx, // 设置日志方法 chromedp.WithLogf(log.Printf), ) // 通常可以使用 defer cancel() 去取消 // 但是在Windows环境下,我们希望程序能顺带关闭掉浏览器 // 如果不希望浏览器关闭,使用cancel()方法即可 // defer cancel() // defer chromedp.Cancel(ctx) }
3.执行自定义的任务
func main(){ // chromdp依赖context上限传递参数 ... // 创建新的chromedp上下文对象,超时时间的设置不分先后 // 注意第二个返回的参数是cancel(),只是我省略了 ... // 执行我们自定义的任务 - myTasks函数在第4步 if err := chromedp.Run(ctx, myTasks()); err != nil { log.Fatal(err) return } }
4.至此程序的初始化过程已经完成,接下来就是任务——打开登陆页面
// 自定义任务 func myTasks() chromedp.Tasks { return chromedp.Tasks{ // 1. 打开金山文档的登陆界面 chromedp.Navigate(loginURL), } }
5.运行一下程序,可以看到Chrome被打开,同时访问了我们指定的网站
4.3 获取二维码(点击过程)
1.需要点击微信登陆按钮,先找到按钮的选择器,右键按钮并在菜单中点击检查,然后可以看到按钮的元素
2.右键元素打开菜单找到copy下的copy selector,即获取到选择器
3.我们尝试点击微信登陆按钮,发现还需要点击一下确认,重复上述步骤获取确认按钮的选择器
4.用代码执行上述点击步骤
// 自定义任务 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.用代码实现获取二维码
有两点需要注意,第一是二维码有加载过程,第二是二维码是元素渲染,
我们需要用截图的方式获取(也可以用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. 用于存储图片的字节切片 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.执行程序即可发现目录下已经存储了二维码图片文件,我们可以通过扫描此二维码进行登陆,与浏览器上扫描为同一种效果
5. 如何将二维码展示在无图形化的终端上
(与chromedp无关,属于额外内容)
1.在上述步骤中,我们已经获取了二维码,接下来我们需要在终端显示二维码,首先是解码,这里使用gozxing库
func printQRCode(code []byte) (err error) { // 1. 因为我们的字节流是图像,所以我们需要先解码字节流 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的库发生了重名 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. 因为我们的字节流是图像,所以我们需要先解码字节流 ... // 2. 然后使用gozxing库解码图片获取二进制位图 ... // 3. 用二进制位图解码获取gozxing的二维码对象 ... // 4. 用结果来获取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. 用于存储图片的字节切片 ... // 2. 截图 // 注意这里需要注明直接使用ID选择器来获取元素(chromedp.ByID) ... // 3. 把二维码输出到标准输出流 if err = printQRCode(code); err != nil { return err } return } }
4.运行程序即可查看效果
6. 如何保存Cookies实现短时间免登陆
1.在上述过程中,我们可以通过二维码扫描登陆,网站会在登陆之后进行跳转,跳转后我们需要保存cookies来维持我们的登录状态,代码实现如下
// 保存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的数据 cookiesData, err := ioutil.ReadFile("cookies.tmp") if err != nil { return } // 反序列化 cookiesParams := network.SetCookiesParams{} if err = cookiesParams.UnmarshalJSON(cookiesData); err != nil { return } // 设置cookies return network.SetCookies(cookiesParams.Cookies).Do(ctx) } }
3.通过上述两步我们已经可以保持登陆状态,然后我们需要检查一下是否成功,这里调用浏览器执行js脚本获取当前页面的网址,判断是否已经个人中心页面,如果为真,则停止操作
// 检查是否登陆 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("已经使用cookies登陆") chromedp.Stop() } return } }
4.最终重新设置我们的浏览器任务即可
// 自定义任务 func myTasks() chromedp.Tasks { return chromedp.Tasks{ // 0. 加载cookies span:nth-child(2) ... // 3. 点击确认按钮 // #dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-ok ... // 4. 获取二维码 // #wximport ... // 5. 若二维码登录后,浏览器会自动跳转到用户信息页面5.我们使用已经登陆的cookies运行程序可以发现我们成功跳过登陆过程
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。
-
154 收藏
-
219 收藏
-
202 收藏
-
199 收藏
-
145 收藏
-
168 收藏
-
165 收藏
-
473 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 清脆的板凳
- 很棒,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢老哥分享文章!
- 2023-02-01 10:41:07
-
- 还单身的魔镜
- 很详细,码起来,感谢博主的这篇技术贴,我会继续支持!
- 2023-01-23 23:42:11
-
- 糊涂的飞鸟
- 这篇文章内容太及时了,太详细了,受益颇多,码住,关注up主了!希望up主能多写Golang相关的文章。
- 2023-01-20 11:31:39
-
- 天真的故事
- 这篇博文太及时了,太全面了,感谢大佬分享,码住,关注up主了!希望up主能多写Golang相关的文章。
- 2023-01-19 17:45:10
-
- 简单的香氛
- 这篇技术贴太及时了,太详细了,很有用,mark,关注作者了!希望作者能多写Golang相关的文章。
- 2023-01-15 18:03:38
-
- 复杂的柚子
- 这篇文章内容出现的刚刚好,太详细了,很棒,收藏了,关注博主了!希望博主能多写Golang相关的文章。
- 2023-01-15 16:29:24
-
- 舒心的哑铃
- 很详细,码起来,感谢大佬的这篇文章内容,我会继续支持!
- 2023-01-10 11:20:06
-
- 谨慎的红牛
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢博主分享技术文章!
- 2023-01-09 11:00:12
-
- 从容的黑米
- 赞 👍👍,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢大佬分享文章!
- 2023-01-04 13:17:32