缘起

一直在浏览器里用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实现页面自动登录的更多相关文章

  1. python+selenium+chrome实现自动登录百度

    #python3.4+selenium3.5+chrome版本 63.0.3239.132+chrome驱动chromedriver.exe #实现自动登录百度 from selenium impor ...

  2. yii自动登录

    在yii,登录页面选择记住密码,下次就会自动登陆 前些天,自己增加了一个web应用,但是发现虽然选择记住密码,没选退出,关闭浏览器,重新进入还会跳转到登陆页面 自动登录是利用cookie实现的 配置U ...

  3. [Python爬虫] Selenium实现自动登录163邮箱和Locating Elements介绍

    前三篇文章介绍了安装过程和通过Selenium实现访问Firefox浏览器并自动搜索"Eastmount"关键字及截图的功能.而这篇文章主要简单介绍如何实现自动登录163邮箱,同时 ...

  4. 自动化测试: Selenium 自动登录授权,再 Requests 请求内容

    Selenium 自动登录网站.截图及 Requests 抓取登录后的网页内容.一起了解下吧. Selenium: 支持 Web 浏览器自动化的一系列工具和库的综合项目. Requests: 唯一的一 ...

  5. HBuilder开发APP自动登录时跳过"登录页面"

    刚接触开发公司APP项目,用HBuilder开发工具. manifest.json中的入口页面就是"登录页面",现在获取到自动登录状态是true,但是真机联调时"登录页面 ...

  6. 【2017-06-29】在登录页面自动返回上次请求页面、Js获取table中的行数与列数

    一.在登录页面自动返回上次请求页面 Request.UrlReferrer比如 if (Request.UrlReferrer != null) { //如果能获取来路地址 Response.Redi ...

  7. C# 自动登录网页,浏览页面【转载】

    需求:客户的数据同时存在在另外一个不可控的系统中,需要和当前系统同步. 思路:自动登录另外一个系统,然后抓取数据,同步到本系统中. 技术点:模拟用户登录:保存登录状态:抓取数据 /// <sum ...

  8. Python+fiddler(基于Cookie绕过验证码自动登录)

    案例:使用Cookie绕过百度验证码自动登录账户 步骤: 1.浏览器进入百度首页,点击登录按钮,输入相关信息(注意:暂时不要点击登录按钮) 2.进入fiddler,首先获取证书,Tools--> ...

  9. python自动登录代码

    公司有很多管理平台,账号有禁用机制,每个月至少登录一次,否则禁用.导致有时候想登录某个平台的时候,发现账号已经被禁用了,还得走流程解禁.因此用python实现了一下自动登录,每天定时任务运行一次.ps ...

随机推荐

  1. HDU 2037(贪心)

    “今年暑假不AC?” “是的.” “那你干什么呢?” “看世界杯呀,笨蛋!” “@#$%^&*%...” 确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了.  ...

  2. Solr搜索引擎基础

    搜索引擎是指一个庞大的互联网资源数据库,如网页,新闻组,程序,图像等.它有助于在万维网上定位信息. 用户可以通过以关键字或短语的形式将查询传递到搜索引擎中来搜索信息. 搜索引擎然后搜索其数据库并向用户 ...

  3. SpringBoot项目属性配置-第二章

    SpringBoot入门 1. 相信很多人选择Spring Boot主要是考虑到它既能兼顾Spring的强大功能,还能实现快速开发的便捷.我们在Spring Boot使用过程中,最直观的感受就是没有了 ...

  4. 使用vue技术应当使用的技术和兼容性选择

    假如你的前端框架使用了vue,那你可以大胆地使用以下技术,并忽略其他js和css的兼容性问题,因为 关于vue的兼容性 官方给出了规定 Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 ...

  5. SpringBoot:使用IDEA快速构建项目

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...

  6. Java 线程状态有哪些?

    线程状态有 5 种,新建,就绪,运行,阻塞,死亡.关系图如下: 1. 线程 start 方法执行后,并不表示该线程运行了,而是进入就绪状态,意思是随时准备运行,但是真正何时运行,是由操作系统决定的,代 ...

  7. Json ignore on class level

    Exclude all instances of a class from serialization in Newtonsoft.Json Every custom type can opt how ...

  8. HDU6030 Happy Necklace(推导+矩阵快速幂)

    HDU6030 Happy Necklace 推导或者可以找规律有公式:\(f[n] = f[n-1] + f[n-3]\) . 构造矩阵乘法: \[ \begin{pmatrix} f_i \\ f ...

  9. React Native商城项目实战15 - 首页购物中心

    1.公共的标题栏组件TitleCommonCell.js /** * 首页购物中心 */ import React, { Component } from 'react'; import { AppR ...

  10. WinForm实现最小化右下角

    首先,要在窗体里面加入这么两个控件,左边的是托盘控件,右边的是菜单控件. 然后设置窗体的FormClosing事件: if (e.CloseReason == CloseReason.UserClos ...