【Mac + Python + Selenium】之獲取驗證碼圖片code並進行登錄


 初稿代碼,可以忽略不計(自己留着看)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/01/15 13:27
# @Author  : zc
# @File    : 115test.py



from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance
import pytesseract

imgPath1 = "/Users/zhangc/zh/111/test/img/識別失敗圖片.png"
imgPath = "/Users/zhangc/zh/111/test/img/img.png"
driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")

def remove(string):
    return string.replace(" ","")


def open(code):
    url = 'http://192.168.2.213:9100'

    driver.get(url)
    driver.maximize_window()
    login(code)


def login(code):
    if (code == "") | (len(remove(code)) != 4):
        getCodeImg()
    else:
        # 輸入用戶名
        telephone = driver.find_element(By.NAME,"telephone")
        telephone.clear()
        telephone.send_keys("13642040631")
        # 輸入密碼
        password = driver.find_element(By.NAME,"password")
        password.clear()
        password.send_keys("123456")
        # 輸入驗證碼
        code_loc = driver.find_element(By.NAME,"code")
        code_loc.clear()
        code_loc.send_keys(code)
        # 點擊登錄按鈕
        button = driver.find_element(By.XPATH,"//button[@type='button']")
        button.click()
        try:
            # 后台獲取驗證碼校驗內容
            text1 = driver.find_element(By.CSS_SELECTOR, ".el-message__content").text
            print(text1)
            while text1 == "":
                button.click()
                text1
            # 前台獲取驗證碼校驗內容
            text2 = driver.find_element(By.CSS_SELECTOR, ".el-el-form-item__error").text
            print(text2)

            if text1 == "驗證碼不正確":
                print("驗證碼不正確")
                driver.find_element(By.XPATH, "//div[@class='divIdentifyingCode']/img").click()
                getCodeImg()
                code2 = test()
                login(code2)
            elif text2 == "請輸入正確的驗證碼":
                print("請輸入正確的驗證碼")
                driver.find_element(By.XPATH, "//div[@class='divIdentifyingCode']/img").click()
                getCodeImg()
                code2 = test()
                login(code2)
            else:
                print("登陸成功!")
        except:
            print("進入首頁!!!!")
            pass


def getCodeImg():
    '''獲取code圖片'''
    size2 = driver.get_window_size()
    print("頁面的總size:"+str(size2))
    img_el = driver.find_element(By.XPATH,"//div[@class='divIdentifyingCode']/img")
    # 獲取圖片的坐標
    location = img_el.location
    print("頁面坐標點的size:"+str(location))
    # 獲取圖片的大小
    size = img_el.size
    print("驗證碼的size:"+str(size))
    left = location['x']/size2['width']
    top = location['y']/size2['height']
    right = (location['x'] + size['width'])/size2['width']
    bottom = (location['y'] + size['height'])/size2['height']
    print(left,top,right,bottom)

    # 截圖操作
    driver.get_screenshot_as_file(imgPath)
    imgSize = Image.open(imgPath).size
    print("截圖的size:"+str(imgSize))

    sleep(2)

    img = Image.open(imgPath).crop((left*imgSize[0],
                                    top*imgSize[1]+100,
                                    right*imgSize[0]+20,
                                    bottom*imgSize[1]+150))
    img = img.convert('L')             #轉換模式:L | RGB
    img = ImageEnhance.Contrast(img)#增強對比度
    img = img.enhance(2.0)             #增加飽和度
    img.save(imgPath)




def test():

    img2 = Image.open(imgPath)
    code = pytesseract.image_to_string(img2).strip()
    print("=============輸出的驗證碼為:"+remove(code))
    while (code == "") | (len(remove(code)) != 4):

        # 重新獲取驗證碼
        driver.find_element(By.XPATH, "//div[@class='divIdentifyingCode']/img").click()
        getCodeImg()
        img2 = Image.open(imgPath)
        code = pytesseract.image_to_string(img2).strip()

        if code == "":
            print("code獲取為空值=================")
            continue
        elif len(remove(code)) != 4:
            print("code獲取不是4位數字=============")
            continue
        else:
            print("識別成功!")
            # break
        break
    print("=============輸出的驗證碼為:" + remove(code))
    return remove(code)


if __name__ == '__main__':
    code = ""
    open(code)
    code1 = test()
    login(code1)






# 頁面的總size:{'width': 1206, 'height': 1129}
# 頁面坐標點的size:{'x': 961, 'y': 518}
# 驗證碼的size:{'height': 28, 'width': 70}
# 0.796849087893864 0.4588131089459699 0.8548922056384743 0.48361381753764393
# 截圖的size:(2412, 1950)
View Code

====================下面看正文=========================

之前有個問題一直在困擾着我,如何獲取驗證碼的值

后來查詢大神們的文章得知:

用pytesseract庫來讀取圖片的文字。

先安裝兩個庫:

# python有着更加優雅的方式調用系統的tesseract工具,首先安裝pytesseract模塊;pytesseract是對tesseract的封裝,要和PIL聯合使用

# 安裝pytesseract
sudo pip install pytesseract

# 安裝圖片處理器PIL
pip install pillow

好了接下來看看我是怎么一步一步實現的吧

第一步、保存驗證碼圖片

 

核心代碼:

getCodeImg()方法

import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance

class LoginCode(object):

    # 用戶名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密碼框元素
    password_loc = (By.NAME,"password")
    # 驗證碼框元素
    code_loc = (By.NAME,"code")
    # 登錄按鈕元素
    button_loc = (By.XPATH,"//button[@type='button']")
    # 驗證碼圖片元素
    img_el_loc = (By.XPATH, "//div[@class='divIdentifyingCode']/img")
    # 驗證碼錯誤提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")

    def find_element(self,*loc):
        # 實驗得知方法中的參數loc↑加上*,定位會更穩定
        '''定位單個元素'''

        return self.driver.find_element(*loc)

   # 核心代碼↓
def getCodeImg(self): '''獲取驗證碼圖片''' # 驗證碼圖片的元素定位 img_el = self.find_element(*self.img_el_loc) # 獲取整個瀏覽器的size chromeSize = self.driver.get_window_size() print("頁面的總size:"+str(chromeSize))
# 頁面的總size:{'width': 1202, 'height': 1129} # 獲取圖片的坐標 self.location = img_el.location print("頁面坐標點的size:"+str(self.location))
     # 頁面坐標點的size:{'x': 959, 'y': 518} x:指的圖片左邊距;y:指的圖片上邊距
# 獲取圖片的大小 imgSize = img_el.size print("驗證碼的size:"+str(imgSize))
   # 驗證碼的size:{'height': 28, 'width': 70}
     # 左邊距占整個瀏覽器的百分比
     left = self.location['x']/chromeSize['width']
     # 上邊距占整個瀏覽器的百分比
        top = self.location['y']/chromeSize['height']                           

     # 右邊距占整個瀏覽器的百分比 right = (self.location['x'] + imgSize['width'])/chromeSize['width']

     # 下邊距占整個瀏覽器的百分比 bottom = (self.location['y'] + imgSize['height'])/chromeSize['height']

    print(left,top,right,bottom)
     # 0.7978369384359401 0.4588131089459699 0.8560732113144759 0.48361381753764393 # 瀏覽器截屏操作 self.driver.get_screenshot_as_file(self.imgPath) screenshotImgSize = Image.open(self.imgPath).size print("截圖的size:"+str(screenshotImgSize))
     # 截圖的size:(2404, 1950) 寬:2404,高:1950 sleep(2) # 從文件讀取截圖,截取驗證碼位置再次保存 img = Image.open(self.imgPath).crop(( # left*screenshotImgSize[0], # top*screenshotImgSize[1]+100, # right*screenshotImgSize[0]+20, # bottom*screenshotImgSize[1]+150
       # 左邊距百分比*截圖的高≈截圖左邊距,再加上微調的距離+350
            left * screenshotImgSize[1]+350,                
       # 上邊距百分比*截圖的高≈截圖左邊距,再加上微調的距離-100 top * screenshotImgSize[0]-100,
       # 右邊距百分比*截圖的寬≈截圖上邊距,再加上微調的距離+400 right * screenshotImgSize[1]+400,
       # 下邊距百分比*截圖的高≈截圖右邊距,再加上微調的距離-50 bottom * screenshotImgSize[0]-50 )) img = img.convert('L') # 轉換模式:L | RGB img = ImageEnhance.Contrast(img) # 增強對比度 img = img.enhance(2.0) # 增加飽和度 img.save(self.imgPath) # 再次保存圖片

獲取頁面中驗證碼圖片的截圖:

第二步、循環獲取驗證碼截圖的code

為什么要循環獲取呢,一次獲取不就可以了嗎,原因是圖片識別文字不准確,經常會識別為空或者不是4位數的值

所以要循環做判斷,下面上代碼:

 

核心方法是:

①getCode():先獲取圖片code值

②loopGetCode():如果獲取的code值不符合條件,循環判斷獲取正確的圖片code值

import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance



class LoginCode(object):

    # 用戶名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密碼框元素
    password_loc = (By.NAME,"password")
    # 驗證碼框元素
    code_loc = (By.NAME,"code")
    # 登錄按鈕元素
    button_loc = (By.XPATH,"//button[@type='button']")
    # 驗證碼圖片元素
    img_el_loc = (By.XPATH, "//div[@class='divIdentifyingCode']/img")
    # 驗證碼錯誤提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")


    def remove(self,string):
        '''字符串去除空格'''

        return string.replace(" ","")


    def find_element(self,*loc):
        # 實驗得知方法中的參數loc↑加上*,定位會更穩定
        '''定位單個元素'''

        return self.driver.find_element(*loc)

   # 核心代碼↓
def getCode(self): '''獲取圖片的code''' # 再次讀取識別驗證碼 img = Image.open(self.imgPath) code = pytesseract.image_to_string(img).strip() print("=============輸出的驗證碼為:" + self.remove(code)) return code
   # 核心代碼↓
def loopGetCode(self): '''循環判斷獲取正確的圖片code''' code = self.remove(self.getCode()) # 循環前獲取code字數 codeNumBf = len(code) # 如果獲取圖片的code值為空或者不滿足4位數進行循環 while (code == "") | (codeNumBf != 4): # 重新獲取驗證碼 self.find_element(*self.img_el_loc).click() self.getCodeImg() # 獲取驗證碼圖片 code = self.remove(self.getCode()) # 循環后獲取code字數 codeNumAf = len(code) if code == "": print("code獲取為空值=================") continue elif codeNumAf != 4: print("code獲取不是4位數字=============") continue else: print("識別成功!") # 識別成功退出循環 break print("=============輸出的驗證碼為:" + code) # 輸出滿足條件的code return code

三、進行登錄操作並判斷驗證碼正確性

為什么登陸操作時還要判斷驗證碼正確性呢,因為還是圖片識別文字不准確雖然識別出4位數但是並不是驗證碼圖片中的值,所以需要再次判斷,如果驗證碼錯誤就重新獲取驗證碼的值。

 

核心代碼:

login():登錄操作

import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance



class LoginCode(object):

    # 用戶名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密碼框元素
    password_loc = (By.NAME,"password")
    # 驗證碼框元素
    code_loc = (By.NAME,"code")
    # 登錄按鈕元素
    button_loc = (By.XPATH,"//button[@type='button']")
    # 驗證碼圖片元素
    img_el_loc = (By.XPATH, "//div[@class='divIdentifyingCode']/img")
    # 驗證碼錯誤提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")


    def open(self):
        '''打開瀏覽器'''

        url = 'http://192.168.2.213:9100'
        self.driver.get(url)
        self.driver.maximize_window()
        self.driver.implicitly_wait(10)
        # 獲取驗證碼圖片
        self.getCodeImg()

   # 核心代碼↓ def login(self,code):
        '''進行登錄操作'''

        # 輸入用戶名
        telephone = self.find_element(*self.telephone_loc)
        telephone.clear()
        telephone.send_keys("13642040631")
        # 輸入密碼
        password = self.find_element(*self.password_loc)
        password.clear()
        password.send_keys("123456")
        # 輸入驗證碼
        code_loc = self.find_element(*self.code_loc)
        code_loc.clear()
        code_loc.send_keys(code)
        # 點擊登錄按鈕
        button = self.find_element(*self.button_loc)
        button.click()
        sleep(0.5)
        try:
            # 后台獲取驗證碼校驗內容
            codeErrMsg = self.find_element(*self.codeErrMsg_loc).text
            print("打印后台:"+codeErrMsg)
            if codeErrMsg == "驗證碼不正確":
                print("驗證碼不正確111")
                self.find_element(*self.img_el_loc).click()
                self.getCodeImg()
                self.loopGetCode_action()
            else:
                print("登陸成功!")
        except:
            print("進入首頁!!!!")
            pass

   # 核心相關代碼↓
    def loopGetCode_action(self):
        '''循環驗證code的正確性'''

        resultCode = self.loopGetCode()
        self.login(resultCode)

   # 核心相關代碼↓ def login_action(self):
        '''執行驗證碼登錄操作'''

        # 打開瀏覽器並獲取驗證碼圖片
        self.open()
        self.loopGetCode_action()

以上三步就是完整獲取圖片文字的方法了,雖然有點多但是都是必不可少的步驟。

==========================================================

注:需要安裝tesseract,不然會提示:

# CHANGE THIS IF TESSERACT IS NOT IN YOUR PATH, OR IS NAMED DIFFERENTLY
pytesseract.pytesseract.TesseractNotFoundError: tesseract is not installed or it's not in your path

未找到tesseract的路徑,需要進入pytesseract.py文件

 

# Mac安裝tesseract
brew install --with-training-tools tesseract

# 查看版本
tesseract -v

tesseract 4.0.0
 leptonica-1.77.0
  libgif 5.1.4 : libjpeg 9c : libpng 1.6.36 : libtiff 4.0.10 : zlib 1.2.11 : libwebp 1.0.2 : libopenjp2 2.3.0
 Found AVX2
 Found AVX
 Found SSE

# 查看安裝路徑
which tesseract
/usr/local/bin/tesseract

 ==========================================================

下面上完整代碼:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/01/15 13:27
# @Author  : zc
# @File    : 115test.py


import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance



class LoginCode(object):

    # 用戶名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密碼框元素
    password_loc = (By.NAME,"password")
    # 驗證碼框元素
    code_loc = (By.NAME,"code")
    # 登錄按鈕元素
    button_loc = (By.XPATH,"//button[@type='button']")
    # 驗證碼圖片元素
    img_el_loc = (By.XPATH, "//div[@class='divIdentifyingCode']/img")
    # 驗證碼錯誤提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")


    def remove(self,string):
        '''字符串去除空格'''

        return string.replace(" ","")


    def find_element(self,*loc):
        # 實驗得知方法中的參數loc↑加上*,定位會更穩定
        '''定位單個元素'''

        return self.driver.find_element(*loc)


    def open(self):
        '''打開瀏覽器'''

        url = 'http://192.168.2.213:9100'
        self.driver.get(url)
        self.driver.maximize_window()
        self.driver.implicitly_wait(10)
        # 獲取驗證碼圖片
        self.getCodeImg()


    def getCodeImg(self):
        '''獲取驗證碼圖片'''

        # 驗證碼圖片的元素定位
        img_el = self.find_element(*self.img_el_loc)
        # 獲取整個瀏覽器的size
        chromeSize = self.driver.get_window_size()
        print("頁面的總size:"+str(chromeSize))               
        # 頁面的總size:{'width': 1202, 'height': 1129}
        
        # 獲取圖片的坐標
        self.location = img_el.location
        print("頁面坐標點的size:"+str(self.location))         
        # 頁面坐標點的size:{'x': 959, 'y': 518} x:指的圖片左邊距;y:指的圖片上邊距
        
        # 獲取圖片的大小
        imgSize = img_el.size
        print("驗證碼的size:"+str(imgSize))                  
        # 驗證碼的size:{'height': 28, 'width': 70}
        
        # 左邊距占整個瀏覽器的百分比
        left = self.location['x']/chromeSize['width']
        # 上邊距占整個瀏覽器的百分比
        top = self.location['y']/chromeSize['height']
        # 右邊距占整個瀏覽器的百分比
        right = (self.location['x'] + imgSize['width'])/chromeSize['width']
        # 下邊距占整個瀏覽器的百分比
        bottom = (self.location['y'] + imgSize['height'])/chromeSize['height']  
        print(left,top,right,bottom)                        
        # 0.7978369384359401 0.4588131089459699 0.8560732113144759 0.48361381753764393

        # 瀏覽器截屏操作
        self.driver.get_screenshot_as_file(self.imgPath)
        screenshotImgSize = Image.open(self.imgPath).size
        print("截圖的size:"+str(screenshotImgSize))          
        # 截圖的size:(2404, 1950)    寬:2404,高:1950

        sleep(2)
        # 從文件讀取截圖,截取驗證碼位置再次保存
        img = Image.open(self.imgPath).crop((
            # left*screenshotImgSize[0],
            # top*screenshotImgSize[1]+100,
            # right*screenshotImgSize[0]+20,
            # bottom*screenshotImgSize[1]+150

            # 左邊距百分比*截圖的高≈截圖左邊距,再加上微調的距離+350
            left * screenshotImgSize[1]+350,
            # 上邊距百分比*截圖的寬≈截圖上邊距,再加上微調的距離-100
            top * screenshotImgSize[0]-100,
            # 右邊距百分比*截圖的高≈截圖右邊距,再加上微調的距離+400
            right * screenshotImgSize[1]+400,
            # 上邊距百分比*截圖的寬≈截圖下邊距,再加上微調的距離-50
            bottom * screenshotImgSize[0]-50                
        ))
        img = img.convert('L')                              # 轉換模式:L | RGB
        img = ImageEnhance.Contrast(img)                    # 增強對比度
        img = img.enhance(2.0)                              # 增加飽和度
        img.save(self.imgPath)                              # 再次保存圖片


    def getCode(self):
        '''獲取圖片的code'''

        # 再次讀取識別驗證碼
        img = Image.open(self.imgPath)
        code = pytesseract.image_to_string(img).strip()
        print("=============輸出的驗證碼為:" + self.remove(code))
        return code


    def loopGetCode(self):
        '''循環判斷獲取正確的圖片code'''

        code = self.remove(self.getCode())
        # 循環前獲取code字數
        codeNumBf = len(code)

        # 如果獲取圖片的code值為空或者不滿足4位數進行循環
        while (code == "") | (codeNumBf != 4):

            # 重新獲取驗證碼
            self.find_element(*self.img_el_loc).click()
            self.getCodeImg()       # 獲取驗證碼圖片
            code = self.remove(self.getCode())
            # 循環后獲取code字數
            codeNumAf = len(code)
            if code == "":
                print("code獲取為空值=================")
                continue
            elif codeNumAf != 4:
                print("code獲取不是4位數字=============")
                continue
            else:
                print("識別成功!")
            # 識別成功退出循環
            break
        print("=============輸出的驗證碼為:" + code)
        # 輸出滿足條件的code
        return code


    def login(self,code):
        '''進行登錄操作'''

        # 輸入用戶名
        telephone = self.find_element(*self.telephone_loc)
        telephone.clear()
        telephone.send_keys("13642040631")
        # 輸入密碼
        password = self.find_element(*self.password_loc)
        password.clear()
        password.send_keys("123456")
        # 輸入驗證碼
        code_loc = self.find_element(*self.code_loc)
        code_loc.clear()
        code_loc.send_keys(code)
        # 點擊登錄按鈕
        button = self.find_element(*self.button_loc)
        button.click()
        sleep(0.5)
        try:
            # 后台獲取驗證碼校驗內容
            codeErrMsg = self.find_element(*self.codeErrMsg_loc).text
            print("打印后台:"+codeErrMsg)
            if codeErrMsg == "驗證碼不正確":
                print("驗證碼不正確111")
                self.find_element(*self.img_el_loc).click()
                self.getCodeImg()
                self.loopGetCode_action()
            else:
                print("登陸成功!")
        except:
            print("進入首頁!!!!")
            pass


    def loopGetCode_action(self):
        '''循環驗證code的正確性'''

        resultCode = self.loopGetCode()
        self.login(resultCode)


    def login_action(self):
        '''執行驗證碼登錄操作'''

        # 打開瀏覽器並獲取驗證碼圖片
        self.open()
        self.loopGetCode_action()



if __name__ == '__main__':
    LoginCode().login_action()

 

 

四、附錄

感謝下面的參考文章:

①感謝作者:的《Python selenium自動化識別驗證碼模擬登錄操作(二)

②感謝作者:的《python -使用pytesseract識別驗證碼中遇到的問題

③感謝作者:瀟雨危欄的《Mac上tesseract-OCR的安裝配置

④感謝作者:anno_ym雨 的《【Python】關於鍵盤鍵入值、str的與或非問題?【報錯:TypeError: unsupported operand type(s) for |: 'str' and 'str'】

⑤感謝作者:的《Python中的條件判斷、循環以及循環的終止

⑥感謝作者:青燈夜游的《Python如何刪除字符串中所有空格

⑦感謝作者:silencement的《python如何跳出while循環

⑧感謝作者:d0main的《Python讀取圖片尺寸、圖片格式

⑨感謝作者:的《Python-獲取圖片的大小

🔟感謝作者:地空神一 的《python selenium UI自動化解決驗證碼的4種方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM