还在保存网址,手动输入账号密码,来做测试么?
不,我已经开始用脚步来自动登陆了。
测试代码示例
先看一段测试代码
def test(self):
driver.get("https://网址保密哈哈")
driver.maximize_window()
loginIdInput.sendKeys(123456)
submitButton.click()
userPhone.sendKeys('hahaha')
userPassword.sendKeys('123')
captcha.sendKeys('8888')
# self.manualCredential('123')
credential.click()
po(By.XPATH, '/html/body/div/div/section/header/div[3]/a/span').hover()
po(By.XPATH, '/html/body/div[2]/div/div/ul/li[1]/div').click()
现在看不懂没关系,先有个印象,接下来我逐步做讲解。
代码结构设计
只是做登陆,就设计了简易版的po模式。
po代码解析
__init__()
# 初始化
def __init__(self, by=None, value=None):
self.by = by
self.value = value
self.element = None
by value参考的原生find_element的参数:
def find_element(self, by=By.ID, value=None):
"""
Find an element given a By strategy and locator. Prefer the find_element_by_* methods when
possible.
:Usage:
element = driver.find_element(By.ID, 'foo')
:rtype: WebElement
"""
源码中也有By的解释:
class By(object):
"""
Set of supported locator strategies.
"""
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
于是,就可以这样来定义一个页面元素
loginIdInput = po(By.XPATH, '//*[@id="loginIdInput"]')
也可以这样来操作一个临时元素
po(By.XPATH, '/html/body/div[2]/div/div/ul/li[1]/div').click()
findElement() & isElementExist()
def findElement(self):
# 元素往往需等待加载,这里设置最多等待30s
self.element = WebDriverWait(driver, 30, 1).until(EC.presence_of_element_located((self.by, self.value)))
return self.element
def isElementExist(self, by, value):
# 判断元素是否存在,常用作断言
try:
driver.find_element(by, value)
return True
except:
return False
其他
def sendKeys(self, s):
# send_keys
self.findElement()
self.element.send_keys(s)
def click(self):
# click
self.findElement()
for i in range(5):
try:
self.element.click()
return
except: # 有可能出现加载遮罩无法点击
time.sleep(1)
continue
def getAttribute(self, t):
# get_attribute
self.findElement()
return self.element.get_attribute(t)
def hover(self):
# 鼠标悬浮
for i in range(30):
if self.findElement().is_displayed():
# action = ActionChains(driver)
action.move_to_element(self.element).perform()
return
time.sleep(1)
raise RuntimeError(f'hover找不到元素{self.value}')
聪明的你,一定发现了:
1、主要封装的是一些异常处理
2、命名统一采用了驼峰方式,比如send_keys sendKeys,个人习惯哈哈哈
loginBrowser.py
再看下之前的测试代码,是不是清晰了些许
def test(self):
driver.get("https://网址保密哈哈")
driver.maximize_window()
loginIdInput.sendKeys(123456)
submitButton.click()
userPhone.sendKeys('hahaha')
userPassword.sendKeys('123')
captcha.sendKeys('8888')
# self.manualCredential('123')
credential.click()
po(By.XPATH, '/html/body/div/div/section/header/div[3]/a/span').hover()
po(By.XPATH, '/html/body/div[2]/div/div/ul/li[1]/div').click()
driver是这样定义的:driver = webdriver.Firefox()
慢!这博客也写的太不走心了,还有注释代码?
# self.manualCredential('123')
其实不然,这个是这里的重点:验证码。
如果是由万能验证码的,captcha.sendKeys('8888')就搞定了。
如果没有呢,比如灰度环境、线上环境往往出于安全考虑不会设置。
有一个方法,就是图片破解,把验证码图片获取下来,进行识别。这个方法的弊端在于简单的图片是可以在网上搜代码来破解的,复杂点的就需要付费工具。而且公司的验证码我眼睛看着输都经常输错,破解的准确率就很不靠谱了。
那么,办法只有一个,就是传统的,手动!
上代码:
def manualCredential(self, pwd):
# 手动输验证码
while True:
if len(str(captcha.getAttribute('value'))) == 4:
credential.click()
if not po().isElementExist(By.XPATH, '//*[@id="credential"]/button'):
break
time.sleep(1)
if str(userPassword.getAttribute('value')) == "":
userPassword.sendKeys(pwd)
代码逻辑是这样的:
每隔1s轮询页面情况
当验证码输入框有4个字符,就点击登录
如果验证码正确,断言登录按钮消失,轮询结束
如果验证码错误(一般会清空密码),重新设置密码,继续轮询