go语言使用Chromedp实现二维码登陆教程示例源码

目录
  • 1 Chromedp是什么
  • 2 为什么不使用Selenium
  • 3 文章解决了什么需求
  • 4.如何使用chromedp进行二维码登陆
    • 4.1 安装chromedp
    • 4.2 尝试打开网站
    • 4.3 获取二维码(点击过程)
    • 5. 如何将二维码展示在无图形化的终端上
    • 6. 如何保存Cookies实现短时间免登陆

源码点击下载

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
	}
}

3.运行程序即可查看效果

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 <-- 变动
		loadCookies(),
		// 1. 打开金山文档的登陆界面
		...
		// 判断一下是否已经登陆  <-- 变动
		checkLoginStatus(),
		// 2. 点击微信登陆按钮
		// #wechat > span:nth-child(2)
		...
		// 3. 点击确认按钮
		// #dialog > div.dialog-wrapper > div > div.dialog-footer > div.dialog-footer-ok
		...
		// 4. 获取二维码
		// #wximport
		...
		// 5. 若二维码登录后,浏览器会自动跳转到用户信息页面  <-- 变动
		saveCookies(),
	}
}

5.我们使用已经登陆的cookies运行程序可以发现我们成功跳过登陆过程

以上就是go语言使用Chromedp实现二维码登陆教程示例源码的详细内容,更多关于go Chromedp二维码登陆的资料请关注我们其它相关文章!

(0)

相关推荐

  • go语言编程二维码生成及识别

    目录 安装 go-qrcode 生成普通二维码 生成有前后背景颜色的二维码 识别二维码 我们在做go web开发的时候,应该都遇到生成二维码分享的应用场景,下面我将介绍下使用go如何生成二维码. 安装 go-qrcode 我们不得不庆幸go的生态已经越来越丰富,有很多大牛已经帮我们写好了库,我们不必造轮子,直接拿过来用就好. 首先,我们安装我们用到的go-qrcode库. https://github.com/skip2/go-qrcode/ go get -u github.com/skip2

  • golang 生成二维码海报的实现代码

    生成带头像的二维码 import ( "errors" "fmt" "github.com/nfnt/resize" "github.com/skip2/go-qrcode" "image" "image/draw" "image/png" "os" ) var err error func createAvatar() (image.Image,

  • Android 带logo的二维码详解及实例

    Android 带logo的二维码详解及实例 好久没有写博客了,快元旦了公司的事情也不是很多,刚好和朋友一起出去玩玩,朋友是搞PHP的说到了每天在公司都是搞些什么二维码和微信支付的相关东西,因为上班的时间不忙,所以随便来搞下. 二维码(Quick Response Code),又称二维条码,它是用特定的几何图形按一定规律在平面(二维方向)上分布的黑白相间的图形,是所有信息数据的一把钥匙.在现代商业活动中,如果一个产品是不能通过二维码来进行访问什么的,显然是不成功的.用的比较多的生成二维码的jar

  • Android中google Zxing实现二维码与条形码扫描

    Android中google Zxing实现二维码与条形码扫描 了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候,老板说要加上二维码扫描功能,然后自己的屁颠屁颠的去百度,google啥的,发现很多朋友都有介绍二维码扫描的功能,然后我就跟着人家的介绍自己搞起了二维码扫描功能,跟着人家的帖子,很快我的项目就加入了扫描二维码的功能,然后自己还很开心. 随着微信的到来,二维码越来越火

  • go语言使用Chromedp实现二维码登陆教程示例源码

    目录 1 Chromedp是什么 2 为什么不使用Selenium 3 文章解决了什么需求 4.如何使用chromedp进行二维码登陆 4.1 安装chromedp 4.2 尝试打开网站 4.3 获取二维码(点击过程) 5. 如何将二维码展示在无图形化的终端上 6. 如何保存Cookies实现短时间免登陆 源码点击下载 1 Chromedp是什么 chromedp是一个更快.更简单的Golang库用于调用支持Chrome DevTools协议的浏览器,同时不需要额外的依赖(例如Selenium和

  • JavaScript动态创建二维数组的方法示例

    本文实例讲述了JavaScript动态创建二维数组的方法.分享给大家供大家参考,具体如下: 学过C语言的我太耿直 一般这种情况下我会直接 var arr = new Array[10][10]; 但是不出意外的话这样是会报错的,因为在js中根本没有这样的语法 在这之前,让我们先来回顾一下js中是怎么样创建一维数组的: 使用数组直接量,这个是最简单的,在方括号内将数组元素用逗号隔开即可: var arr = [ ]; //空数组 var s = [1,2,3,4]; //4个元素的数组 var n

  • MNIST数据集转化为二维图片的实现示例

    本文介绍了MNIST数据集转化为二维图片的实现示例,分享给大家,具体如下: #coding: utf-8 from tensorflow.examples.tutorials.mnist import input_data import scipy.misc import os # 读取MNIST数据集.如果不存在会事先下载. mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # 我们把原始图片保存在MNIST

  • C语言编程动态内存开辟实现升级版通讯录教程示例

    目录 前言 一.存放联系人信息 二.通讯录初始化 三.增加联系人 四.销毁通讯录 后记 前言 所谓动态内存开辟的通讯录,就是我需要多少联系人,就给多少联系人,防止给定一个联系人上限,需要增加联系人无法扩容,而联系人没有上限那么多又会造成内存浪费. 本文继之前的静态通讯录作出改进,有兴趣的同学可以看看之前的文章:C语言实现静态通讯录 一.存放联系人信息 这里是用struct PeoInfodata结构体指针指向通讯录,而不再直接 struct PeoInfo data[Max] 用结构体数组定义通

  • 通过示例源码解读React首次渲染流程

    目录 说明 题目 首次渲染流程 render beginWork completeUnitOfWork commit 准备阶段 before mutation 阶段 mutation 阶段 切换 Fiber Tree layout 阶段 题目解析 总结 说明 本文结论均基于 React 16.13.1 得出,若有出入请参考对应版本源码.参考了 React 技术揭秘. 题目 在开始进行源码分析前,我们先来看几个题目: 题目一: 渲染下面的组件,打印顺序是什么? import React from

  • C# Winform调用百度接口实现人脸识别教程(附源码)

    百度是个好东西,这篇调用了百度的接口(当然大牛也可以自己写),人脸检测技术,所以使用的前提是有网的情况下.当然大家也可以去参考百度的文档. 话不多说,我们开始: 第一步,在百度创建你的人脸识别应用 打开百度AI开放平台链接: 点击跳转百度人脸检测链接,创建新应用 创建成功成功之后.进行第二步 第二步,使用API Key和Secret Key,获取 AssetToken 平台会分配给你相关凭证,拿到API Key和Secret Key,获取 AssetToken 接下来我们创建一个AccessTo

  • VUE+Element实现增删改查的示例源码

    前言 &最近因为一些原因,没有更博客,昨天老师布置了一个作业,用vue实现增删改查功能,想想这也不难,就做一下试试吧. 因为自己写的样式没有别人做的好,因此我想用现成的UI框架,一直也没用过Element,就干脆趁机学一下吧. 实验步骤 首先引入一下element的css以及js <!-- 引入样式 --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chal

  • Mybatis-plus使用TableNameHandler分表详解(附完整示例源码)

    为什么要分表 Mysql是当前互联网系统中使用非常广泛的关系数据库,具有ACID的特性. 但是mysql的单表性能会受到表中数据量的限制,主要原因是B+树索引过大导致查询时索引无法全部加载到内存.读取磁盘的次数变多,而磁盘的每次读取对性能都有很大的影响. 这时一个简单可行的方案就是分表(当然土豪也可以堆硬件),将一张数据量庞大的表的数据,拆分到多个表中,这同时也减少了B+树索引的大小,减少磁盘读取次数,提高性能. 两种基础分表逻辑 说完了为什么要分表,下面聊聊业务开发中常见的两种基础的分表逻辑.

  • java编程Reference核心原理示例源码分析

    带着问题,看源码针对性会更强一点.印象会更深刻.并且效果也会更好.所以我先卖个关子,提两个问题(没准下次跳槽时就被问到). 我们可以用ByteBuffer的allocateDirect方法,申请一块堆外内存创建一个DirectByteBuffer对象,然后利用它去操作堆外内存.这些申请完的堆外内存,我们可以回收吗?可以的话是通过什么样的机制回收的? 大家应该都知道WeakHashMap可以用来实现内存相对敏感的本地缓存,为什么WeakHashMap合适这种业务场景,其内部实现会做什么特殊处理呢?

  • 易语言通过注册表将易文件关联修复的源码

    DLL命令表 .版本 2 .DLL命令 API_SendMessage, 整数型, "user32", "SendMessageA" .参数 窗口句柄, 整数型 .参数 消息值, 整数型 .参数 参数一, 整数型 .参数 参数二, 整数型 .DLL命令 API_SendMessageTimeout, 整数型, "user32", "SendMessageTimeoutA", , , .参数 hWnd, 整数型, , 要接收消息

随机推荐