1. 程式人生 > 其它 >【Python】自動化測試之識別驗證碼圖片方法

【Python】自動化測試之識別驗證碼圖片方法

一、前提

經常會遇到登入系統時候需要輸入驗證碼的情況,但是自動化如何識別圖片然後登陸系統

需要用到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.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}")

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)

不過識別率還是比較低的,下面有種可以提高識別率的方法,但是見仁見智,實測有時很快有時很慢

參考文章:

pytesseract 識別率低提升方法

【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/