本篇文章主要讲述的是如何自动获取短信验证码和如何自动获取图片验证码,并写入到对应的输入框中(以下均使用微博的找回密码作为示例)
获取短信验证码的方法有三种,如下所示:
- 在手机的通知栏中获取短信内容
- 通过监控手机日志获取短信验证码
- 通过redis获取短信验证码
以下只写出第一种在通知栏中获取短信内容的方法,后续两种方法会在后面进行分享。
获取图片验证码的方法:
通过百度的OCR文字识别,进行识别获取图片中的字母、文字或数字验证码。
一、获取短信验证码
方法:发送短信验证码后,打开手机的通知栏,定位短信内容,将定位到的内容填入到验证码输入框中,核心代码为:
# 打开手机通知栏
self.driver.open_notifications()
# 获取定位短信内容(封装了元素定位,详细操作可见上一篇PO模式封装的博客)
message = self.find_element(self._message_content)
# 将短信内容转换为text文本
message_content = message.text
# 通过正则匹配短信内容中的验证码(使用r前缀可以自动转义,不需要手动转换字符串,6表示6位数字的验证码)
ver_code = re.findall(r'[\d]{6}', message_content)
# 关闭通知栏(下面方式为点击手机返回键来关闭通知栏)
self.driver.press_keycode(4)
# 自动填入验证码(将获取到的验证自动填入到验证码输入框中)
self.input_verification_code(ver_code)
注意:由于我的类中继承了BasePage类,而BasePage类中声明driver是属于WebDriver库(WebDriver库属于Selenium框架),而以上代码中调用的open_notifications()和press_keycode()方法是属于webdriver库(webdriver库属于appium框架),所以需要在该类中导入webdriver类,并在类中将driver声明为webdriver,否则会出现如下图所示错误:
导入和声明的方式如下:
# 导入webdriver
from appium import webdriver
from page.base_page import BasePage
class PhoneLoginPage(BasePage):
# 声明
driver: webdriver = None
二、申请百度OCR识别接口,下载对应语言的SDK文件
在调用百度OCR图片识别前,需要先申请百度通用文字识别接口,申请方法如下:
1.登录百度AI平台,申请百度通用文字识别接口,免费激活AI平台的使用权限
百度AI平台网址:https://ai.baidu.com/
进入开放能力→文字识别→通用文字识别,如下图:
点击立即使用:
创建应用:
创建成功后进入管理应用,能查看创建的应用AppID、API Key、Secret Key,如下图:
2. 查看适用不同平台/语言/功能的SDK
文字识别链接:https://ai.baidu.com/sdk#ocr
下载需要语言的SDK:
我使用的是python语言,所以下载的是对应的Python SDK(支持python版本:2.7.+,3.+),下载完成后,安装方式有两种:
①已经安装pip,打开命令提示符,输入以下命令即可
pip install baidu-aip
②已经安装setuptools,打开命令提示符,输入以下命令即可
python setup.py install
出现下图表示安装成功:
3.文字识别接口说明(参考文档)
文字识别接口说明链接:https://ai.baidu.com/ai-doc/OCR/7kibizyfm
或者可以通过上面图片(下载所需语言的SDK)→使用说明→接口说明进入(后续会使用到这篇文档,建议在写脚本前先阅读)
三、图片验证码识别
方法:在工程中自动创建一个存放图片的文件夹,再定位图片验证码的控件,截取图片验证码,将截取到的图片使用自动生成的规则的文件名,保存在创建的图片文件夹内,存储后通过百度的OCR文字识别,获取到保存的截图,进行文字识别,再将识别的结果输出到验证码输入框内
注意:
问:为什么要将图片有规则的命名?
答:方便后续查找核对
问:为什么截图保存不能保存在本地磁盘内,而是保存在本地工程目录下方?
答:如果保存图片时使用的是本地固定的磁盘,那别人使用你的代码时就需要修改保存的路径,如果保存在本地工程目录下方,别人就不需要手动创建文件夹,直接运行代码就能自动在工程目录下生成文件夹
1.screenshot.py — 验证码截图,并通过特定的规律保存在特定的文件夹中
import time
from common.image_recognition import ImageRecognition
from page.base_page import BasePage
class Screen(BasePage):
# 图片验证码输入框
_img_check_code = "/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout/android.webkit.WebView/android.webkit.WebView/android.widget.Image"
# 截取页面中特定区域的图片
def get_part_screen(self):
# 截图将图片保存至固定的位置
img_folder = 'E:\\study\\Fork\\Weibo_Demo\\Weibo\\image\\'
# 截图的文件名组成
times = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))
# 图片存储位置+文件名
screen_save_path = img_folder + times + '.png'
# 截取特定位置的图片,并保存在已定义的存储位置和规定的文件名
self.find_xpath(self._img_check_code).screenshot(screen_save_path)
# 实例化ImageRecognition,传入需要识别的图片位置
ir = ImageRecognition(screen_save_path)
a = ir.ocr()
return a
2.image_recognition.py — 调用百度OCR文字识别
from aip import AipOcr
class ImageRecognition:
# 初始化path,定义为字符类型
def __init__(self, path: ''):
self.path = path
# 你的 APPID AK SK
APP_ID = '123456'
API_KEY = 'fydhafbuebfuebiufwbiufe'
SECRET_KEY = 'difwebfubweufbweffefefefefefef'
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
# 配置参数,识别到图片内容时,需要输出的内容
def get_garameter(self):
options = {
# 识别语言类型,默认为CHN_ENG
"language_type": "ENG",
# 是否检测图像朝向,默认不检测,即:false
"detect_language": "true"
# 是否返回识别结果中每一行的置信度
# "probability": "true"
}
return options
# 打开文件
def get_file_content(self, file_path):
with open(file_path, 'rb') as fp:
return fp.read()
# 需要识别的图片的路径
def get_image(self):
return self.get_file_content(self.path)
# 调用百度ocr接口,进行精准识别
def ocr(self):
image_content = self.client.basicAccurate(self.get_image()), self.get_garameter()
return image_content
注意:在调用百度OCR识别需要在运行环境(工程)下安装baidu-aip,安装步骤如下:
打开Setting→Python Interpreter,点击+号
搜索输入:baidu-aip,点击搜索结果列表中第一个,点击install package
在Setting→Python Interpreter页面出现下图,表示安装成功
3.retrieve_password_page.py — 对获取到的图片验证码解析
from time import sleep
from selenium.webdriver.common.by import By
from common.screenshot import Screen
from page.base_page import BasePage
class RetrievePasswordPage(BasePage):
# 初始化,用于实例化Screen类
def __init__(self, driver):
super().__init__(driver)
self.screen = Screen(driver)
# 自动获取图片验证码中的内容
def auto_get_check_code(self, telephone):
self.input_telephone(telephone)
# 获取图片验证码,获取到的是元组
check_code_tuple = self.screen.get_part_screen()
print(check_code_tuple)
# 在元组中提取第一个数据(元组下标位置从0开始),获取到的数据为字典(字典是一组键值对)
check_code_list = check_code_tuple[0]
print(check_code_list)
# 在字典中提取第三个数据'words_result',获取到的数据为列表
word_result = check_code_list['words_result']
# 判断获取到的列表的值是否为空,为空则在列表中自定义一个字典“word_result”的值
if word_result:
print(word_result)
else:
word_result = [{'words': 'F3HA'}]
print(word_result)
# 在列表中提取一个数据,获取到的数据是字典
dic_words = word_result[0]
print(dic_words)
# 在字典中输出"words"
word = dic_words['words']
print(word)
self.input_image_check_code(word)
self.find_xpath(self._btn_confirm).click()
sleep(1)
说明:由于通过百度OCR识别到的内容是一个字典,如下:
({'log_id': 6483429546783692489, 'words_result_num': 1, 'words_result': [{'words': ' F3H'}]}, {'language_type': 'ENG', 'detect_language': 'true'})
通过处理,将以上内容转换为JSON格式,转换后如下图显示:
我们需要获取的是words,所以需要一层一层的获取元素,具体的获取方式是请查看python的字典、元组、列表,可参考菜鸟教程:https://www.runoob.com/python3/python3-dictionary.html
注意:经实验,该种方式对于比较奇葩的图片验证码识别概率低,识别中规中矩的图片验证码成功率较高
4.testcase.py — 测试用例
# 找回密码测试用例脚本
import pytest
from common.init import AppStart
class TestRetrievePassword:
def setup(self):
self.retrievepassword = AppStart.start().enter_retrieve_password()
# 自动获取图片验证码
def test_auto_get_check_code(self):
telephone = "18056120351"
self.retrievepassword.auto_get_check_code(telephone)
assert self.retrievepassword.get_phone_and_check_code_tips() == "请输入正确的验证码"
def teardown(self):
AppStart.quit()
以上内容有不正确的地方,欢迎大家提出来,谢谢!