1. 程式人生 > >Python selenium自動化識別驗證碼模擬登入操作(二)

Python selenium自動化識別驗證碼模擬登入操作(二)

首先故意輸入錯誤的賬號登陸,很快就會出現需要驗證碼了。


這裡可以看到圖片所在的標籤 和id,同時還有一個驗證碼地址,如下。該地址每次隨機生成一張圖片。

https://passport.baidu.com/cgi-bin/genimage?njGcb06e212fe8de27902311482de0178143145de06c70113b0

因為每次執行檢視url時,圖片又變化了,所以無法獲取到驗證碼的圖片與當前登入介面相對應起來。因此只能截圖,並用其他工具識別出圖片的字元。

再看看,在預設情況下,即不需要驗證碼登入的情況下,其實也是有一張圖片的,只是非常小,只有一個小點,圖片地址如下:

https://passport.baidu.com/passApi/img/small_blank.gif



因此,用兩個圖片地址部分作對比,可以判斷當前需不需要用到驗證碼:

imgsrc = driver.find_element_by_id("TANGRAM__PSP_3__verifyCodeImg").get_attribute('src')
if re.match(r'https://passport.baidu.com/cgi-bin/genimage.*', imgsrc):
	print("需要驗證碼")
else:
	print("不需要驗證碼")

如果需要驗證碼,則讀取圖片並輸入;如果不需要,則直接提交登入。

接下來最主要的就是圖片的擷取和讀取了。webdriver 是可以進行瀏覽器頁面截圖的,但是整個瀏覽器頁面太大,還需要定位到 驗證碼圖片的位置才行。驗證碼的標籤 id 為 TANGRAM__PSP_3__verifyCodeImg ,這樣就可以定位到該ID標籤所在的頁面畫素位置了。再獲取標籤大小,可確定標籤的寬高了。

	location = driver.find_element_by_id('TANGRAM__PSP_3__verifyCodeImg').location
	size = driver.find_element_by_id('TANGRAM__PSP_3__verifyCodeImg').size
	left = location['x']
	top =  location['y']
	right = location['x'] + size['width']
	bottom = location['y'] + size['height']

最終儲存的驗證碼圖片如下,位置稍微偏了,可以調整左右畫素。


接下來通過處理後,進行驗證碼的讀取。讀取使用 pytesseract ,安裝該模組之後,還需要安裝 tesseract-ocr 。

本次測試下載的是 tesseract-ocr-setup-4.00.00dev.exe ,這塊的過程遇到好幾個問題。

FileNotFoundError: [WinError 2] 系統找不到指定的檔案。

pytesseract.pytesseract.TesseractError: (2, 'Usage: python pytesseract.py [-l lang] input_file')

pytesseract.pytesseract.TesseractError: (1, 'Error opening data file \\Program Files (x86)\\Tesseract-OCR\\eng.traineddata')

這幾個問題主要是需要安裝配置Tesseract-OCR

1. 下載安裝tesseract-ocr,

2. 新增環境變數: TESSDATA_PREFIX = C:\Program Files (x86)\Tesseract-OCR

3. 編輯檔案 D:\Python35\Lib\site-packages\pytesseract\pytesseract.py

tesseract_cmd = 'tesseract' 

改為:

tesseract_cmd = 'C:/Program Files (x86)/Tesseract-OCR/tesseract'

指令碼如下:

#-*- coding: utf-8 -*-
# python 3.5.0

import re
import requests
import pytesseract
from selenium import webdriver
from PIL import Image,ImageEnhance

username = "xxxxxx"
password = "xxxxxx"

chromedriver = 'D:/Python35/selenium/webdriver/chromedriver/chromedriver.exe'
loginurl = 'https://passport.baidu.com/v2/?login'

#截圖或驗證碼圖片儲存地址
screenImg = "D:/Python35/selenium/webdriver/chromedriver/screenImg.png"

#開啟瀏覽器
driver = webdriver.Chrome(executable_path=chromedriver)
driver.get(loginurl)
driver.implicitly_wait(1)

#cookie= driver.get_cookies()
assert "登入百度帳號" in driver.title

#資料賬號&密碼(此處不提交)
driver.find_element_by_id("TANGRAM__PSP_3__userName").send_keys(username)
driver.find_element_by_id("TANGRAM__PSP_3__password").send_keys(password)

#用於測試,此處可提前提交,讓登入出錯,頁面出現驗證碼
#driver.find_element_by_id("TANGRAM__PSP_3__submit").click()

#獲取驗證碼URL地址
imgsrc = driver.find_element_by_id("TANGRAM__PSP_3__verifyCodeImg").get_attribute('src')

#如果匹配驗證碼路徑成功(說明有提示輸入驗證碼),則需讀取驗證碼!
if re.match(r'https://passport.baidu.com/cgi-bin/genimage.*', imgsrc):
	#瀏覽器頁面截圖
	driver.get_screenshot_as_file(screenImg)
	#定位驗證碼位置及大小
	location = driver.find_element_by_id('TANGRAM__PSP_3__verifyCodeImg').location
	size = driver.find_element_by_id('TANGRAM__PSP_3__verifyCodeImg').size
	left = location['x']
	top =  location['y']
	right = location['x'] + size['width']
	bottom = location['y'] + size['height']
	#從檔案讀取截圖,擷取驗證碼位置再次儲存
	img = Image.open(screenImg).crop((left,top,right,bottom))
	img = img.convert('L') 			#轉換模式:L | RGB
	img = ImageEnhance.Contrast(img)#增強對比度
	img = img.enhance(2.0) 			#增加飽和度
	img.save(screenImg)
	#再次讀取識別驗證碼
	img = Image.open(screenImg)
	code = pytesseract.image_to_string(img)
	#code= pytesser.image_file_to_string(screenImg)
	driver.find_element_by_id("TANGRAM__PSP_3__verifyCode").send_keys(code.strip())
	print(code.strip())

#提交登入
driver.find_element_by_id("TANGRAM__PSP_3__submit").click()	

#driver.implicitly_wait(10)
#driver.quit()

雖然可以識別驗證碼了,但是這工具識別很不準確,除非沒有什麼干擾的驗證圖片才好些。只能識別還是不那麼好啊。