【Python】自動化測試之識別驗證碼圖片方法
阿新 • • 發佈:2021-11-10
一、前提
經常會遇到登入系統時候需要輸入驗證碼的情況,但是自動化如何識別圖片然後登陸系統
需要用到pytesseract識別驗證碼圖片以及PIL影象處理方法
import pytesseract from PIL import Image, ImageEnhance
二、獲取驗證碼
1、思路
- 步驟①:定點陣圖片的元素,並且擷取當前瀏覽器的頁面圖片
- 步驟②:獲取驗證碼座標點,以及驗證碼圖片、瀏覽器、截圖的長和寬
- 步驟③:擷取截圖裡的驗證碼圖片,獲得的驗證碼圖片並儲存
- 步驟④:獲得驗證碼code
2、實踐方法
以下步驟都在getCodeImg方法裡面:
def getCodeImg(self):"""獲取驗證碼"""
1)步驟①
imgPath:瀏覽器截圖圖片路徑
savePath:儲存驗證碼圖片路徑
加了一個點選驗證碼圖片方法,目的是為了後面重新獲取驗證碼用的。
# 步驟①: basePath = Fun().upPath() + "/utils/img/" imgPath = basePath + "code.png" savePath = basePath + "saveCode.png" # 定點陣圖片元素 imgElement = self.webDriverWait(Loc.codeImg_loc)# 點選驗證碼圖片 imgElement.click() # 擷取當前頁面的圖並放到目錄裡 self.driver.save_screenshot(imgPath)
2)步驟②
獲取驗證碼座標是為了下面計算驗證碼佔據整個瀏覽器的百分比。
# 步驟②: # 獲取驗證碼x,y軸,x&y代表左上角的座標點 imgLocation = imgElement.location print(f"圖片座標點:{imgLocation}") # 獲取驗證碼長、寬 imgSize = imgElement.sizeprint(f"圖片長、寬:{imgSize}") # 獲取瀏覽器的長、寬 windowSize = self.driver.get_window_size() print(f"瀏覽器長、寬:{windowSize}") # 開啟截圖 openImg = Image.open(imgPath) # 獲取儲存截圖的長、寬(寬:2700, 高:1950) screenImgSize = openImg.size print(f"儲存截圖的長、寬:{screenImgSize}")
3)步驟③
計算圖片四個邊距在真實瀏覽器的百分比,用這個百分比乘以瀏覽器截圖的長和寬,得出截圖裡面的驗證碼大概位置,然後再自己進行調整截圖裡的邊距大小。
最後再把驗證碼圖片進行圖片處理,灰色度和增強對比度等等,提高獲取驗證碼圖片的識別率。
# 步驟③:擷取截圖的驗證碼圖片 # 圖片左邊距佔據整個瀏覽器的百分比 left = imgLocation['x']/windowSize['width'] # 圖片上邊距佔據整個瀏覽器的百分比 top = imgLocation['y']/windowSize['height'] # 圖片右邊距佔據整個瀏覽器的百分比 right = (imgLocation['x'] + imgSize['width'])/windowSize['width'] # 圖片下邊距佔據整個瀏覽器的百分比 bottom = (imgLocation['y'] + imgSize['height'])/windowSize['height'] # 需要擷取的座標 screenLocation = ( left * screenImgSize[0], top * screenImgSize[1]+150, right * screenImgSize[0], bottom * screenImgSize[1]+150 ) # 開啟截圖並擷取區域並儲存 img = openImg.crop(screenLocation) img = img.convert('L') # 轉換模式:L | RGB # 提高識別率(見下面) # enhancer = ImageEnhance.Color(img) # enhancer = enhancer.enhance(0) # enhancer = ImageEnhance.Brightness(enhancer) # enhancer = enhancer.enhance(2) # enhancer = ImageEnhance.Contrast(enhancer) # 增強對比度 # enhancer = enhancer.enhance(8) # enhancer = ImageEnhance.Sharpness(enhancer) # img = enhancer.enhance(20) img = ImageEnhance.Contrast(img) # 增強對比度 img = img.enhance(2.0) img.save(savePath)
不過識別率還是比較低的,下面有種可以提高識別率的方法,但是見仁見智,實測有時很快有時很慢。
參考文章:
《【python影象處理】影象的增強(ImageEnhance類詳解)》
4)步驟④
獲取的驗證碼可能不是我們想要的,會出現中間有大小空格、換行情況,需要替換掉
def remove(self,string): """字串去除空格或換行""" str = string.replace(" ", "") #大空格 str = str.replace("", "") #小空格 str = str.replace('\n', "") #換行符 return str def getCodeImg(self): """獲取驗證碼""" # 步驟④:獲得code驗證碼 code = pytesseract.image_to_string(img).strip() print(f"提取的驗證碼為:【{self.remove(code)}】") return self.remove(code)
三、獲取4位驗證碼
1、思路
- 因為實際效果我們要獲取4位驗證碼
- 雖然上一步驟獲取到了驗證碼,但是還是會出現不足4位或者超過4位的驗證碼
- 需要進行判斷篩選,只要4位的驗證碼
2、實踐方法
先判斷是否滿足4位,不滿足的話while迴圈重新獲取驗證碼,滿足4位跳出迴圈,並return出來
def getCode(self): """獲取4位數驗證碼""" # 迴圈前獲取code字數 code = self.getCodeImg() print(f"驗證碼位數:【{len(code)}】位") while len(code) != 4: # 重新獲取驗證碼 code = self.getCodeImg() print(f"驗證碼位數:【{len(code)}】位") if len(code) != 4: print("驗證碼不是4位數!") print(f"輸出4位驗證碼為:{code}") return code
四、輸入驗證碼
1、思路
- 雖然我們獲取了4位驗證碼,但是因為識別率的問題,獲取的驗證碼仍然不對,導致提示驗證碼錯誤
- 我們還得重新獲取一遍驗證碼,直到獲取成功能夠登陸為止
2、實踐方法
判斷頁面如果有錯誤提示,則重新獲取4位驗證碼
def checkCode(self): """判斷驗證碼是否正確""" try: errorMsg = self.get_text(Loc.errorMsg_loc) if errorMsg == "驗證碼錯誤": self.inputCodeAction() except: print("驗證碼正確,進入首頁!")
五、輸入驗證碼登入
1、思路
- 封裝一個Action方法,把之前的各種方法封裝在一起
- 實現輸入驗證碼登入
- 此封裝方法只是在獲取驗證碼的類裡,輸入使用者名稱和密碼的方法在另一個類裡
2、實踐方法
def inputCodeAction(self): """輸入驗證碼登入""" code = self.getCode() # 獲取4位驗證碼 self.el_clear_sendKeys(Loc.code_loc, code) # 清空驗證碼輸入框並輸入驗證碼 self.el_click(Loc.loginButton_loc) # 點選登入按鈕 self.checkCode() # 判斷驗證碼是否正確
六、登入頁面類
登入頁面類,封裝輸入使用者名稱、密碼、驗證碼、登入的操作方法
class LoginPage(BasePage): """登入頁面""" def login_action(self,username,password): """登入操作""" self.el_sendKeys(Loc.username_loc, username) # 輸入使用者名稱 self.el_sendKeys(Loc.password_loc, password) # 輸入密碼 GetCode(self.driver).inputCodeAction() # 輸入驗證碼並登入
七、完整的獲取驗證碼類程式碼
import pytesseract from PIL import Image, ImageEnhance from page_object.page.basePage import BasePage from page_object.utils.functions import Functions as Fun from page_object.locator.loginPageLoc import LoginPageLoc as Loc class GetCode(BasePage): def remove(self,string): """字串去除空格或換行""" str = string.replace(" ", "") str = str.replace("", "") str = str.replace('\n', "") return str def getCodeImg(self): """獲取驗證碼""" # 步驟①: basePath = Fun().upPath() + "/utils/img/" imgPath = basePath + "code.png" savePath = basePath + "saveCode.png" # 定點陣圖片元素 imgElement = self.webDriverWait(Loc.codeImg_loc) # 點選驗證碼圖片 imgElement.click() # print(f"點選【{next(iter(Fun()))}】次驗證碼圖片") # 擷取當前頁面的圖並放到目錄裡 self.driver.save_screenshot(imgPath) # 步驟②: # 獲取驗證碼x,y軸,x&y代表左上角的座標點 imgLocation = imgElement.location print(f"圖片座標點:{imgLocation}") # 獲取驗證碼長、寬 imgSize = imgElement.size print(f"圖片長、寬:{imgSize}") # 獲取瀏覽器的長、寬 windowSize = self.driver.get_window_size() print(f"瀏覽器長、寬:{windowSize}") # 開啟截圖 openImg = Image.open(imgPath) # 獲取儲存截圖的長、寬(寬:2700, 高:1950) screenImgSize = openImg.size print(f"儲存截圖的長、寬:{screenImgSize}") # 步驟③:擷取截圖的驗證碼圖片 # 圖片左邊距佔據整個瀏覽器的百分比 left = imgLocation['x']/windowSize['width'] # 圖片上邊距佔據整個瀏覽器的百分比 top = imgLocation['y']/windowSize['height'] # 圖片右邊距佔據整個瀏覽器的百分比 right = (imgLocation['x'] + imgSize['width'])/windowSize['width'] # 圖片下邊距佔據整個瀏覽器的百分比 bottom = (imgLocation['y'] + imgSize['height'])/windowSize['height'] # 需要擷取的座標 screenLocation = ( left * screenImgSize[0], top * screenImgSize[1]+150, right * screenImgSize[0], bottom * screenImgSize[1]+150 ) # 開啟截圖並擷取區域並儲存 img = openImg.crop(screenLocation) img = img.convert('L') # 轉換模式:L | RGB # enhancer = ImageEnhance.Color(img) # enhancer = enhancer.enhance(0) # enhancer = ImageEnhance.Brightness(enhancer) # enhancer = enhancer.enhance(2) # enhancer = ImageEnhance.Contrast(enhancer) # 增強對比度 # enhancer = enhancer.enhance(8) # enhancer = ImageEnhance.Sharpness(enhancer) # img = enhancer.enhance(20) img = ImageEnhance.Contrast(img) # 增強對比度 img = img.enhance(2.0) img.save(savePath) # 步驟④:獲得code驗證碼 code = pytesseract.image_to_string(img).strip() print(f"提取的驗證碼為:【{self.remove(code)}】") return self.remove(code) def getCode(self): """獲取4位數驗證碼""" # 迴圈前獲取code字數 code = self.getCodeImg() print(f"驗證碼位數:【{len(code)}】位") while len(code) != 4: # 重新獲取驗證碼 code = self.getCodeImg() print(f"驗證碼位數:【{len(code)}】位") if len(code) != 4: print("驗證碼不是4位數!") print(f"輸出4位驗證碼為:{code}") return code def checkCode(self): """判斷驗證碼是否正確""" try: errorMsg = self.get_text(Loc.errorMsg_loc) if errorMsg == "驗證碼錯誤": self.inputCodeAction() except: print("驗證碼正確,進入首頁!") def inputCodeAction(self): """輸入驗證碼登入""" code = self.getCode() self.el_clear_sendKeys(Loc.code_loc, code) self.el_click(Loc.loginButton_loc) self.checkCode()不積跬步,無以致千里;不集小流,無以成江海。 ; 如轉載本文,請還多關注一下我的部落格:Owen_ET,https://www.cnblogs.com/Owen-ET/