前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >webdriver使用已打开过的chrome

webdriver使用已打开过的chrome

作者头像
dongfanger
发布于 2020-09-23 01:51:13
发布于 2020-09-23 01:51:13
2.4K00
代码可运行
举报
文章被收录于专栏:dongfangerdongfanger
运行总次数:0
代码可运行

基本功能:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
执行脚本a,打开一个chrome,脚本a执行完成,chrome未关闭。
执行脚本b,继续使用a打开的chrome,不新启浏览器。

附加:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
如果已打开的chrome未关闭,则在chrome中新建标签页来打开新的页面。
如果已打开的chrome已关闭,则新启浏览器。

最近用python+selenium+pytest,写了个测试小工具用来自动化登陆浏览器,一方面是方便管理网址、账号、密码,存放在脚本中,另一方面也省去了频繁输入登陆网站的操作,节省了不少时间。

但这个小工具用起来存在明显问题:每次都新启一个浏览器,多了后就是这样的

根本不知道谁是谁。

于是就想到要实现前面提到的这些功能。

首先要解决的第一个问题就是,怎么重新使用已打开的chrome。百度后知晓,是通过session_id。浏览器都有一个session_id,拿到这个session_id就可以通过webdriver.Remote去调chrome。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
driver = webdriver.Chrome()
params["session_id"] = driver.session_id
params["server_url"] = driver.command_executor._url

driver = webdriver.Remote(command_executor=params["server_url"])
driver.session_id = params["session_id"]

经过试验,python存在一个坑是每次初始化就会调start_session去新开一个空白的浏览器。网上有解决方案是继承Remote,重写start_session方法。然而,仔细看完代码就发现,何必多此一举,直接quit()就搞定。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
driver = webdriver.Remote(command_executor=params["server_url"])
driver.quit()  # 退出start_session新开的空白浏览器
driver.session_id = params["session_id"]

quit是quit了,但driver还存在呀,所以还是多理清思路,才能避免走冤枉路。

然后要解决的第二个问题就是,如何在执行脚本b的时候再接着用session。当然就是存本地咯。这里用到的是pickle,能很方便的在本地存取变量。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
with open(session_file, 'wb') as f:
    pickle.dump(params, f)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
with open(session_file, 'rb') as f:
    params = pickle.load(f)

第三个问题就是新开标签页和切换窗口。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
driver.execute_script('window.open("");')  # 调js
driver.switch_to.window(driver.window_handles[-1])  # 切换到最后一个页签

最后要解决的一个问题就是,如果已经打开的chrome关掉了,从本地文件读取的session就会过时。拿这个过时session去用,就会”chrome not reachable“。解决思路就是,捕获driver抛出的WebDriverException,重新创建新的driver。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
try:
    driver = webdriver.Remote(command_executor=params["server_url"])
    driver.quit()  # 退出start_session新开的空白浏览器
    driver.session_id = params["session_id"]
    driver.execute_script('window.open("");')
    driver.switch_to.window(driver.window_handles[-1])
except:
    driver = create_driver()

完整代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
session_file = 'browser_session.data'


def create_driver():
    driver = webdriver.Chrome()
    with open(session_file, 'wb') as f:
        params = {"session_id": driver.session_id, "server_url": driver.command_executor._url}
        pickle.dump(params, f)
    return driver

  
if not Path(session_file).exists():
    driver = create_driver()
else:
    with open(session_file, 'rb') as f:
        params = pickle.load(f)
        try:
            driver = webdriver.Remote(command_executor=params["server_url"])
            driver.quit()  # 退出start_session新开的空白浏览器
            driver.session_id = params["session_id"]
            driver.execute_script('window.open("");')
            driver.switch_to.window(driver.window_handles[-1])
        except:
            driver = create_driver()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-10-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
golang 使用时间通过md5生成token
package main import ( "crypto/md5" "fmt" "io" "strconv" "time" ) func main() { crutime := time.Now().Unix() fmt.Println("crutime-->", crutime) h := md5.New() fmt.Println("h-->", h)
李海彬
2018/03/23
2.1K0
Golang语言情怀-第15期 Go 语言设计模式 创建模式-生成器
3.有时我们希望生成器能够自动的退出,这时可以使用golang channel的
李海彬
2021/01/21
3720
如何开发ChatOps
现在各种Ops,比如DevOps,AIOps,ChatOps,NoOps等等,反正其背后的意义就是各种卷运维,让运维无路可走。
没有故事的陈师傅
2022/12/06
5520
如何开发ChatOps
文件上传下载
package main import ( "fmt" "html/template" "log" "net/http" "os" "io" "crypto/md5" "time" "strconv" "archive/zip" ) var buf []byte func sayhelloName(w http.ResponseWriter, r *http.Request){ /*if r.Method == "Ge
李海彬
2018/03/27
1.2K0
golang源码分析:grpc 链接池(4)自定义resolver 、balancer和picker
在分析完源码后golang源码分析:grpc 链接池(3)resolver 、balancer和picker,我们尝试自定义实现相应的插件。grpc 通过服务发现或者直连形式获取到 gRPC server 的实例的 endpoints,然后通知负载均衡器进行 SubConn 更新,对于新加入的 endpoint 进行实例创建,移出废弃的 endpoint, 最后通过状态更新将状态为 Idle 的 SubConn 进行管理,gRPC 在调用 Invoke时,则会通过负载均衡器中的 Picker 去按照某一个负载均衡算法选择一个 SubConn 创建链接,如果创建成功则不再进行其他 SubConn 的尝试,否则会按照一定的退避算法进行重试,直到退避失败或者创建链接成功为止。上述三个组件的功能分别如下:
golangLeetcode
2023/03/01
9870
golang源码分析:grpc 链接池(4)自定义resolver 、balancer和picker
Go 每日一库之 nutsdb
nutsdb是一个完全由 Go 编写的简单、快速、可嵌入的持久化存储。nutsdb与我们之前介绍过的buntdb有些类似,但是支持List、Set、Sorted Set这些数据结构。
用户7731323
2020/09/08
4960
Go语言基于Socket编写服务器端与客户端通信的实例
在golang中,网络协议已经被封装的非常完好了,想要写一个Socket的Server,我们并不用像其他语言那样需要为socket、bind、listen、receive等一系列操作头疼,只要使用Golang中自带的net包即可很方便的完成连接等操作~ 在这里,给出一个最最基础的基于Socket的Server的写法: package main import ( "fmt" "net" "log" "os" ) func main() {
李海彬
2018/03/23
2.2K0
转--Go语言基于Socket编写服务器端与客户端通信的实例
在golang中,网络协议已经被封装的非常完好了,想要写一个Socket的Server,我们并不用像其他语言那样需要为socket、bind、listen、receive等一系列操作头疼,只要使用Golang中自带的net包即可很方便的完成连接等操作~ 在这里,给出一个最最基础的基于Socket的Server的写法: 代码如下: package main import ( "fmt" "net" "log" "os" ) func main()
李海彬
2018/03/22
1.2K0
从0使用gin框架搭建博客(2)-问题解决
binding是引入了validator10.0 ,这里是系统可自动校验email格式
爽朗地狮子
2022/10/20
3150
52. Socket Server 自定义协议的简单实现 | 厚土Go学习笔记
在 Server 和 Client 通讯中,由于网络等原因很有可能会发生数据丢包的现象。如果数据确实,服务端接收的信息不完整,就会造成混乱。 我们就需要在 Server 和 Client 之间建立一个通讯协议,通过协议中的规则,判断当前接收到的信息是否完整。根据信息的完整情况,采取不同的处理方法。 通讯协议 protocol 的核心就是设计一个头部。如果传来的信息不包含这个头部,就说明当前信息和之前的信息是同一条。那么就把当前信息和之前的那条信息合并成一条。 而协议主要包含的功能是封装(Enpack)和解析
李海彬
2018/03/19
2K0
52. Socket Server 自定义协议的简单实现 | 厚土Go学习笔记
golang使用 mongo
 连接集群 mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?o
架构师刀哥
2018/03/20
2.3K0
GO-字符串常用操作
package main import ( "fmt" "strconv" "strings" ) func main() { /*字符串基本操作--strings*/ str := "wangdy" //是否包含 fmt.Println(strings.Contains(str, "wang"), strings.Contains(str, "123")) //true false //获取字符串长度
李海彬
2018/03/27
6270
Golang 泛型实现类型转换
Golang 标准库提供了很多类型转换的函数,如 strconv 包可完成 string 与基本数据类型之间的转换。
恋喵大鲤鱼
2022/12/30
3.5K0
54. 心跳的实现 | 厚土Go学习笔记
在多客户端同时访问服务器的工作模式下,首先要保证服务端的运行正常。因此,Server在和Client建立通讯后,确保连接的及时断开就非常重要。否则,多个客户端长时间占用着连接不关闭,是非常可怕的服务器资源浪费。会使得服务器可服务的客户端数量大幅度减少。 因此,针对短连接和长连接,根据业务的需要,配套不同的处理机制。 短连接 一般建立完连接,就立刻传输数据。传输完数据,连接就关闭。服务端根据需要,设定连接的时长。超过时间长度,就算客户端超时。立刻关闭连接。 长连接 建立连接后,传输数据,然后要保持连接,然后再
李海彬
2018/03/19
2.2K0
54. 心跳的实现 | 厚土Go学习笔记
Golang 将切片连接成字符串
Join 将字符串切片的所有元素连接成一个字符串,各个元素间使用给定的字符串分隔。
恋喵大鲤鱼
2023/10/12
3320
Golang 将切片连接成字符串
[系列] - go-gin-api 路由中间件 - 签名验证(七)
上篇文章分享了,路由中间件 - Jaeger 链路追踪(实战篇),文章反响真是出乎意料, 「Go中国」 公众号也转发了,有很多朋友加我好友交流,直呼我大神,其实我哪是什么大神,只不过在本地实践了而已,对于 Go 语言的使用,我还是个新人,在这里感谢大家的厚爱!
新亮
2019/10/14
2.7K0
[系列] - go-gin-api 路由中间件 - 签名验证(七)
go语言学习-类型转换
1.字符串到整形(string to int):ParseInt 返回的是 int64
solate
2019/07/19
9900
go 如何给服务做限流?
【1】限流就是限制流量进入或者从系统出去的速率,防止流量过高导致系统过载或者崩溃。
Johns
2021/07/15
3K0
go 如何给服务做限流?
go语言微信公众号开发后台接口封装
业余时间做了个有意思的小功能,每天早上7点准时给发天气预报,每晚8点发布一条英语说说,提醒自己不能忘记学习。
杨永贞
2020/08/04
2.1K0
【共识算法】--“raft的实现”
看过之前几期的朋友们应该知道在1号第1期最初的时候就实现过一次raft,但之前实现基本是基于python实现的,这次可结合着PBFT,用golang实现了raft。
帆说区块链
2022/04/26
4770
【共识算法】--“raft的实现”
相关推荐
golang 使用时间通过md5生成token
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档