结合pychrom与selenium实现页面自动登录
缘起
一直在浏览器里用Katalon插件录制一些常用的流程,以减少重复操作,也就自然而然想自己搞搞自动化测试,但无奈登录一关跨不过去,就无法串起来。(不想让开发添加万能验证码的功能)首先想到的是识别验证码。用selenium模拟登录时,验证码一关实在过不了。无论怎么处理验证码图片,tesseract识别率还是太低,完全不可用。看到有机器学习提高验证码识别率的例子,但觉得实在太麻烦,就没有研究,搁置了一段时间。最近发现在登陆时,后台发起了2个请求。先是Get_VerifyCode,获得verifyCode和backEndKey,然后是Post_Authenticate,并传入用户名,md5加密后的密码,verifyCode和backEndKey。登录成功后,后台会返回token。登录后访问页面,请求头中就都有Authorization字段,后台会根据id和authorization发给权限。
我就想如果能先用Get_VerifyCode获取verifyCode和backEndKey,然后把加上其它信息,对Post_Authenticate发起请求,这样不就能登录成功了吗?先写好用到的方法,然后再发起用requests发起请求吧。结果是不成功。验证码虽然能获得,但Post_Authenticate总是返回500错误。原因是什么呢?第一次是猜测,是不是参数不对,用response.url查看响应的url,怎么参数没在里面?查询后知道,要给requests.post()传参数,得用params(keyword argument),不能用data。修改后再尝试,还是不行。再查询,可能是请求头不对,就用Chrome dev tools查看请求头。在请求Post_Authenticate时,给加上了几个。结果不行。再查,有人说一定要把请求头给加全了,一个都别缺,下面也有人回复有用。难道不能偷懒,不能只在请求头里加user-agent?补齐请求头后,还是不行。容我想想。是不是在获取验证码时就得加上,不然拿到的backEndKey也是无效的,试了,不行。观察下请求头吧。获取验证码时,有个cookie字段,是不是应该拿到cookie,然后放到2个请求的请求头中?怎么获取cookie呢?我发现打开登录页面后,发起的请求里就有cookie字段了。我想到的第一个办法是,用selenium模拟登录,用get_cookies()方法,试了,可以,但Post_Authenticate还是不通。第二个办法是,用requests发起请求后,也能在返回值里取到cookie,试了,可以,但最后还是一样的问题。请求走不通,难道是requests库的问题,于是又试了下urllib库。一样的结果。这么一圈下来还是解决不了,想想能能不能换个思路。能不能在页面上登录,但又用Get_VerifyCode获取验证码呢?试了,不行,根本就不是一次请求,获得了验证码也不可用。因为backendky不一致。那能不能selenium登录浏览器后,执行js脚本发起请求,就好像在页面上点击了验证码,也能更新验证码呢?奈何行不通。还是因为backendkey不一致。
在selenium模拟登录后,页面上点击验证码图片,在去监控网络请求,拿到Get_verifyCode的返回值,这样也能解决问题。于是就去搜索selenium capture net traffic,翻来拣去,总算是看到相关的。可以让selenium在启动后,打开一个dev tools,不过主要能用来观测浏览器性能。又看到chrome devtool protocol,似乎可行,就安装了python的对它的实现pychrome,想执行例子试试,但有报错。按最后给出的错误信息,有说关闭防火墙,有说把把代理设置改为自动,有说用cmd的命令行执行,有说是pycharm的问题,一一试了试,无一可行。
错误信息往前追溯,看到是urllib3报错,搜索后还是没解决。再往前看是socket问题,还是不行。
让我想想,之前有人遇到的类似问题是,服务端没有开启监听,所以客户端访问时,就会提示目标计算机拒绝了请求。
由于pychrome库,实例化Browser对象后,监听的是9222端口,会不会是9222端口的服务端问题呢,也就是浏览器设置的问题呢?这会用baidu吧,搜索“9222端口”,第一个就是
设置Chrome远程调试接口,是给前端打断点调试用的。试试看吧,总算可行,pychrome库能用了。
又了解了下chrome dev protocol,尝试了pychrome里的各种方法,试图捕捉到Get_verifyCode请求的返回值
试了多个方法,看了github仓库中提供的例子,总算弄好了
接下来的问题就变成了,怎么把selenium和pychrome结和起来,这样既能让selenium来做自动化操作,
又能使用pychrome监控请求。分开使用时,两个库都是会生成各自的浏览器实例,互不相干,
莫名其妙,执行写好的代码就不能用了,会提示chrome unreachable。
以为是chrome自动升级了,导致webriver不匹配,下载了新的webdriver,不行。
更新chrome时发现,原来自己早把chrome自动更新给停了,就更新到了75,又换了chromedriver,不行。
再查,有人说是hosts的问题,没有填入127.0.0.1和localhost的映射,打开hosts查看,已经有了,不是这个问题。
再查,有人说是代码中的webdriver配置问题,改了后不行。中间还遇到常用的js代理走不通,谷歌访问助手不能用的情况,又调了下这个问题。
再查,有人说防火墙问题,仍然不行。
停下俩想想吧,是不是浏览器的问题呢?以remote-debugging模式打开chrome,访问不到9222端口。用telnet local 9222命令,也是不通。
可能是浏览器问题吧。实在是查不到相关信息了,只能想到浏览器重装大法。查询中,记得看到过chrome canary的信息,就查了下,原来是类似nightly的版本,
就装了下,是77版。以远程调试模式,打开chrome canary后,发现可以访问到9222端口。再打开chrome stable版,发现居然也可以了。
试着卸载了canary版本,又不行了,只得再装回来。可是网络突然又不好了,无论如何都下载不成功。第二天到了公司,重装了下,总算原来的代码可以用了
我真的很困惑,问题不知道为什么就发生了,也不知道为什么就解决了。
卡在某处,就想一次性解决,不拖到下次。可是总会遇到各种各样的问题。要解决一个问题,查询后发现得先解决另一个问题,预置了前提,而前提又未必一定导向
原本的问题,于是就有了两个问题。以此类推,问题像锁链一样,一环套一环。卸掉一环,未必就能离原本的问题近一点,但却只能如此。
代码
from selenium import webdriver
import pychrome
import json
import subprocess
import time
from data import *
from commons import EventHandler, Task
import os
from action import Action
from action import * class ChromeClient(object):
options = webdriver.ChromeOptions()
options._debugger_address = "localhost:9222"
# options.add_argument('--remote-debugging-port=9222') def __init__(self):
# 原来用os.popen时不时就报错,打开的chrome一直无响应,改为用subprocess后就没报错了
# os.popen(CHROME_CMD) subprocess.Popen(CHROME_CMD)
self.browser = pychrome.Browser()
self.driver = webdriver.Chrome(executable_path=r'C:\Python36\chromedriver.exe', chrome_options=ChromeClient.options)
self.driver.implicitly_wait(30)
self.tab = None
self.event = None
self.token = None # self.driver.get('about:blank') def monitor(self):
self.tab = self.browser.list_tab()[0]
self.tab.start()
self.tab.Page.enable()
self.tab.Network.enable()
# self.tab.Page.enable()
self.event = EventHandler()
self.tab.Network.requestWillBeSent = self.event.on_request_will_be_sent
self.tab.Network.responseReceived = self.event.on_response_received
print('----Requests are being monitored....')
return True def naivigate(self, url):
self.tab.Page.navigate(url=url)
time.sleep(2.5)
print('----Navigate to ', url) def get_code_from_request(self, requestId):
try:
_response = self.tab.Network.getResponseBody(requestId=requestId)
_response_content = _response.get('body')
_response_dict = json.loads(json.loads(_response_content))
_verifyCode_str = _response_dict.get('data').get('verifyCode')
print("----Verifycode ", _verifyCode_str)
return _verifyCode_str
except Exception as e:
return False def get_token_from_request(self, requestId):
time.sleep(2)
_response = self.tab.Network.getResponseBody(requestId=requestId)
print(_response)
_response_content = _response.get('body')
_response_dict = json.loads(json.loads(_response_content))
_token = _response_dict.get('data').get('tokenID')
self.token = ''.join(['BasicAuth ', _token])
print("----Token ", self.token)
return self.token def login(self, username, password, verifycode):
_driver = self.driver
_username_input = _driver.find_element_by_name("username")
_password_input = _driver.find_element_by_name("password")
_verifycode_input = _driver.find_element_by_name("verificationCode") Task.delete_text(_username_input)
_username_input.send_keys(username)
Task.delete_text(_password_input)
_password_input.send_keys(password)
_verifycode_input.send_keys(verifycode) for _element in _driver.find_elements_by_css_selector('span'):
if "登录" in _element.text:
_driver.execute_script("arguments[0].click();", _element)
# self.tab.wait(2.5)
# _driver.execute_script('alert(1);')
# _driver.execute_script("arguments[0].click();", login_span) if __name__ == '__main__':
host = 'ppm-test'
role = 'la'
no = 0 client = ChromeClient()
client.monitor()
client.naivigate(url=LOGIN_URLS[host])
verifycode = client.get_code_from_request(client.event.request_id)
client.login(username=USERS[role][no][0], password=USERS[role][no][1], verifycode=verifycode)
token = client.get_token_from_request(client.event.request_id)
感想
即便是花了很多时间把登录搞好了,之后各类流程却又是个问题。各个业务用到的接口数据,复杂繁多,而且有诸多限制。况且录制的代码,常常无法直接变成selenium代码,嵌在项目里,往往还有经过多轮调试,还不一定能用。UI自动化测试收益果然不高。瞎折腾实在是费心费力。
参考文章
https://div.io/topic/1464
https://testerhome.com/topics/16526
https://testerhome.com/topics/16222
https://testerhome.com/topics/15817
https://blog.csdn.net/crisschan/article/details/79970813
结合pychrom与selenium实现页面自动登录的更多相关文章
- python+selenium+chrome实现自动登录百度
#python3.4+selenium3.5+chrome版本 63.0.3239.132+chrome驱动chromedriver.exe #实现自动登录百度 from selenium impor ...
- yii自动登录
在yii,登录页面选择记住密码,下次就会自动登陆 前些天,自己增加了一个web应用,但是发现虽然选择记住密码,没选退出,关闭浏览器,重新进入还会跳转到登陆页面 自动登录是利用cookie实现的 配置U ...
- [Python爬虫] Selenium实现自动登录163邮箱和Locating Elements介绍
前三篇文章介绍了安装过程和通过Selenium实现访问Firefox浏览器并自动搜索"Eastmount"关键字及截图的功能.而这篇文章主要简单介绍如何实现自动登录163邮箱,同时 ...
- 自动化测试: Selenium 自动登录授权,再 Requests 请求内容
Selenium 自动登录网站.截图及 Requests 抓取登录后的网页内容.一起了解下吧. Selenium: 支持 Web 浏览器自动化的一系列工具和库的综合项目. Requests: 唯一的一 ...
- HBuilder开发APP自动登录时跳过"登录页面"
刚接触开发公司APP项目,用HBuilder开发工具. manifest.json中的入口页面就是"登录页面",现在获取到自动登录状态是true,但是真机联调时"登录页面 ...
- 【2017-06-29】在登录页面自动返回上次请求页面、Js获取table中的行数与列数
一.在登录页面自动返回上次请求页面 Request.UrlReferrer比如 if (Request.UrlReferrer != null) { //如果能获取来路地址 Response.Redi ...
- C# 自动登录网页,浏览页面【转载】
需求:客户的数据同时存在在另外一个不可控的系统中,需要和当前系统同步. 思路:自动登录另外一个系统,然后抓取数据,同步到本系统中. 技术点:模拟用户登录:保存登录状态:抓取数据 /// <sum ...
- Python+fiddler(基于Cookie绕过验证码自动登录)
案例:使用Cookie绕过百度验证码自动登录账户 步骤: 1.浏览器进入百度首页,点击登录按钮,输入相关信息(注意:暂时不要点击登录按钮) 2.进入fiddler,首先获取证书,Tools--> ...
- python自动登录代码
公司有很多管理平台,账号有禁用机制,每个月至少登录一次,否则禁用.导致有时候想登录某个平台的时候,发现账号已经被禁用了,还得走流程解禁.因此用python实现了一下自动登录,每天定时任务运行一次.ps ...
随机推荐
- BZOJ 2097: [Usaco2010 Dec]Exercise 奶牛健美操 二分 + 贪心 + 树上问题
Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in",& ...
- 浙大PAT CCCC L3-013 非常弹的球 ( 高中物理题 )
题目链接 题意 : 刚上高一的森森为了学好物理,买了一个“非常弹”的球.虽然说是非常弹的球,其实也就是一般的弹力球而已.森森玩了一会儿弹力球后突然想到,假如他在地上用力弹球,球最远能弹到多远去呢?他不 ...
- HDU 6206 Apple ( 高精度 && 计算几何 && 三点构圆求圆心半径 )
题意 : 给出四个点,问你第四个点是否在前三个点构成的圆内,若在圆外输出"Accepted",否则输出"Rejected",题目保证前三个点不在一条直线上. 分 ...
- CentOS 6 修改时间和时区及设置修改及时间同步
一.时区 date -R; date ; hwclock --show ; ps -ef|grep ntpd 显示时区 date --help 获取帮助 date -R date +%z 上面两个命令 ...
- linux 挂载磁盘指令
fdisk -l (先df -h,如果没有xvdb盘信息,则敲这条指令) fdisk /dev/xvdb (进入对话状态,一问一答,结束后要保存w或者删除q) mkfs.ext3 /dev/xv ...
- Qt之zip压缩/解压缩(QuaZIP)
摘要: 简述 QuaZIP是使用Qt/C++对ZLIB进行简单封装的用于压缩及解压缩ZIP的开源库.适用于多种平台,利用它可以很方便的将单个或多个文件打包为zip文件,且打包后的zip文件可以通过其它 ...
- dd备份命令使用
转载——dd 参数解释 1. if=文件名:输入文件名,缺省为标准输入.即指定源文件.< if=input file > 2. of=文件名:输出文件名,缺省为标准输出.即指定目的文件.& ...
- ubuntu 安装java1.8
1.进入官网下载页面http://www.oracle.com/technetwork/java/javase/downloads/index.html 2.选择需要的版本,进入下载页面 下载 jdk ...
- VMware 虚拟机的虚拟磁盘编程知识点扫盲之一
目录 目录 前言 VMware 虚拟机文件类型 VMware 虚拟机的快照 Quiseced Snapshot Quiseced Snapshot 的创建过程 创建快照 创建快照的执行过程及原理 删除 ...
- QTP技术支持之QTP对象无法识别(转自582357212的个人空间,链接:http://www.51testing.com/html/64/305564-847787.html)
QTP自动化测试从业者,或者很多练习使用QTP开发自动化测试代码的人员遇到最多的问题恐怕就是对象无法识别了,对象无法识别原因有很多种,根据经常对QTP自动化测试脚本开发人员的技术Support,我总结 ...