记一次 selenium 处理浏览器证书弹窗的经历

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

有时候解决一个难题,解决思路往往更重要。

而分享解决难题的思考过程,比直接分享答案更有意义!

今天下午处理了一个关于 selenium+pytthon 的疑难杂症。
经过一番思考后成功解决,且方法极为简单可靠,具体代码在最后。
先看下这个疑难问题:

  • 访问一个内部平台登陆页面,

  • 然后弹出证书弹窗:

  • 必须点击确定按钮。否则无法继续加载登陆页面

  • 手动点击一次之后,关浏览器下次打开仍然会弹出。

  • 需求是想每次代码能自动点击确定关闭弹窗,然后继续执行

对于成熟的测开来说,需要在大脑中先思考解决这个问题的几种可能办法,然后迅速判断出每条方法的难度,复杂度,麻烦程度,成功概率,后续维护等。
首先思路有俩条大方向:

  • 1.设置浏览器方向,让浏览器自己永远不用弹这个证书弹窗。

  • 2.在自动化代码里动手脚,让每次到这之后自动点击确定好关闭弹窗。

先说说方法1: 从浏览器自身下手。可是作者对各种浏览器的证书设置实在是不精通,甚至百度都不知道怎么搜。而且要设置的不只有一个浏览器,谷歌/火狐/ie等等,很多。换台电脑,或者部署在服务器的时候,都是个问题。而且以自身的经验来说,可能要弄一下午,最终还是不成功。所以此路可行,但是成功率太低,优先级最后吧。

所以马上想方法2:从代码中处理,这种情况跨平台性好,而且也不会因机而异。方便快捷还省时省力。

方法2:从代码里动手脚 有以下几个子思路

1.利用alert.accept() 方法,但是对于自动化工程师而言,想都不用想,这个肯定不好使。因为这次不是一个简单的alert弹窗,而是一个复杂的证书选择器。所以此路不可行。

2.利用autoIt3: autoit3最早被selenium工程师熟知基本是因为其可以处理文件上传框,但是作者目前情况是:电脑没有安装autoit3,且电脑是mac,基本无法使用,即便换成windows,也需要先到处找安全的下载地址,然后下载,然后研究破解,然后录制脚本,然后打包成.exe,然后在python代码中 运行.exe。这个过程估计弄完,天都黑了。而且程序运行速度也会受制于.exe的启动执行速度。所以判断此路可行,但是不优先。

3.利用selenium的鼠标/键盘操作,强制点击确定或按回车功能。

此方法简单可靠快速,是最佳选择。所以作者立即进行可行性调研。

这种方法利用起来有个前提,就是浏览器没有在缓冲中,python代码可以在弹窗出来后继续执行。但是实际发现,在证书弹窗出现的全部时间内,浏览器都是一直在缓冲转啊转,别说后面什么点击回车,移动鼠标操作了,连个print都无法执行。

所以在此思路上引出新问题:如何能在弹窗出现后,点击回车。

解决方向有:

1.利用超时,强制运行driver.execute_script("window.stop()") 用js的强制停止页面

这种方法使用后,的确可以停止网页,然后程序点击了回车,关闭了证书弹窗,但是结果就是,浏览器不在继续加载了。登陆页面所有的东西都没有出来,相当于你为了把受伤人身上的子弹取出来,就把人给开肠破肚的解刨了,子弹是拿出来了,人也没了~

最终作者开始用另一种子思维:

2.利用多线程,新建一个小弟去帮你点回车

这种方法是先生成一个子线程,子线程干什么呢?就只有 等待2秒,然后点击键盘回车。就这么简单。

当主线程走到 driver.get() 方法打开网页的同时,子线程start。

然后主线程 使浏览器弹出了证书选择弹窗。子线程也在刚刚等待了2秒后,按下了回车,使浏览器证书选择弹窗成功确认并关闭,然后子线程死亡。浏览器成功加载出登陆页面,主流程开始接下来的 输入用户名/密码等工作。

最后把这个方法封装了一下,以后就不用driver.get()方法了,直接调用封装好的zs_get()即可。上面的2s为啥要等待呢,因为子线程相当于你的小弟,但是个瞎子,只能自己默数2秒然后挥刀。如果不等待,那就会导致子线程先按下回车,主流程才使浏览器弹出证书选择弹窗导致无法关闭。所以最后 奉上原码:

def zs_get(url):
    from selenium.webdriver.common.keys import Keys  #导入键盘按键方法,有很多这里随便举例一种
  import threading #导入多线程模块
  def press_enter():  #定义子线程函数
    time.sleep(2) #可以多等待几秒
    #ActionChains(driver).send_keys(Keys.ENTER).perform() : #按下回车代码
    #pyautogui 注意这里必须使用第三方界面工具,原ActionChains方法会被阻塞
  t = threading.Thread(target=press_enter) #初始化子线程
  t.setDaemon(True) 
  driver.get(url) #drver访问网址登陆页面
  t.start() #子线程启动

zs_get("http://xxxx/xxxx/xxxx.com") #调用此方法来代替driver.get() 即可自动处理上述难题
复制代码

其实作者还想了好多办法,只是在测试这种的时候直接就成功了,所以后续方法没有再进行测试和过多思考。
珍贵的不只是这个方法,而是面对一个陌生的难题的时候,要做到临危不惧,不自暴自弃,坚信没有解决不了难题,然后通过科学的方法一步一步最终 用最短的时间,确定出最好的那个方法。

Guess you like

Origin juejin.im/post/7054947659932991519