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

#!/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)
====================下面看正文=========================
之前有個問題一直在困擾着我,如何獲取驗證碼的值
后來查詢大神們的文章得知:
用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()
四、附錄
感謝下面的參考文章:
①感謝作者:薛定諤的DBA的《Python selenium自動化識別驗證碼模擬登錄操作(二)》
②感謝作者:大王大大王的《python -使用pytesseract識別驗證碼中遇到的問題》
③感謝作者:瀟雨危欄的《Mac上tesseract-OCR的安裝配置》
④感謝作者:anno_ym雨 的《【Python】關於鍵盤鍵入值、str的與或非問題?【報錯:TypeError: unsupported operand type(s) for |: 'str' and 'str'】》
⑤感謝作者:github_39655029的《Python中的條件判斷、循環以及循環的終止》
⑥感謝作者:青燈夜游的《Python如何刪除字符串中所有空格》
⑦感謝作者:silencement的《python如何跳出while循環》
⑧感謝作者:d0main的《Python讀取圖片尺寸、圖片格式》
⑨感謝作者:奔跑的豆子_的《Python-獲取圖片的大小》
🔟感謝作者:地空神一 的《python selenium UI自動化解決驗證碼的4種方法》