本篇文章主要講述的是如何自動獲取短信驗證碼和如何自動獲取圖片驗證碼,並寫入到對應的輸入框中(以下均使用微博的找回密碼作為示例)
獲取短信驗證碼的方法有三種,如下所示:
- 在手機的通知欄中獲取短信內容
- 通過監控手機日志獲取短信驗證碼
- 通過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()
以上內容有不正確的地方,歡迎大家提出來,謝謝!