1. 程式人生 > >這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

近期在跟進新專案的時候,整體的業務線非常之長,會一直重複登入退出不同賬號的這個流程,所以想從登入開始實現部分的自動化。因為是B/S的架構,所以採用的是selenium的框架來實現。大致實現步驟如下:

學習Python中有不明白推薦加入交流群
                號:960410445
                群裡有志同道合的小夥伴,互幫互助,
                群裡有不錯的視訊學習教程和PDF!

1.環境準備

2.驗證碼爬取

3.識別方案選擇

4.影象處理和識別

5.自動化實現

一、環境準備

系統:macOS

軟體:Pycharm

語言:Python 2.7

瀏覽器:Chrome 70.0.35

依賴庫:selenium 3.141、xlrd 1.1、aip 1.0.0.5、pytesser、pytesseract 0.2.5、opencv-python 3.4.3、urllib3 1.24.1、Pillow-PIL 0.1

驅動安裝與配置環境:

① 下載chromedriver:http://chromedriver.storage.googleapis.com/index.html(需代理)、http://npm.taobao.org/mirrors/chromedriver/(無需代理)
②具體瀏覽器與驅動版本對映表可參考 https://blog.csdn.net/huilan_same/article/details/51896672
③解壓後放置在 /urs/bin/目錄下
④加入環境變數:export PATH=$PATH:/usr/local/bin/ChromeDriver

二、驗證碼爬取

對於驗證碼而言,目前各式網站出現的驗證碼型別基本有:圖形驗證碼(數字、計算題、中文、英文、問答題)、滑塊驗證碼、語音驗證碼、圖片驗證碼(正倒序、同類型)。自身專案的驗證碼為數字+英文圖形驗證碼,針對這一塊的內容,首先我們先來爬取一些驗證碼到指定資料夾中,來著重分析一下特點。程式碼如下:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

 1 #-*- coding:utf-8 -*-
 2 from selenium import webdriver
 3 import time
 4 import urllib
 5 import os
 6 import sys
 7 
 8 
 9 req_url = "https://專案網址/#/"
10 
11 
12 def download_code(num):
13 for i in range(int(num)):
14 browser.refresh()
15 time.sleep(3)
16 # 尋找登入按鈕,查詢登入classname
17 browser.find_elements_by_css_selector("[class='ant-btn logining-btn ant-btn-primary ant-btn-lg ant-btn-background-ghost']")[0].click()
18 time.sleep(3)
19 #獲取驗證碼url連結
20 src=browser.find_elements_by_css_selector("[class='picturecode-img']")[0].get_attribute("src")
21 time.sleep(1)
22 
23 local = '/Users/funny/PycharmProjects/auto_cloud/code_pic/' + str(i) + '.png'
24 print local
25 urllib.urlretrieve(src,local)
26 time.sleep(1)
27 
28 if __name__=="__main__":
29 browser = webdriver.Chrome()
30 browser.get(req_url)
31 download_code(sys.argv[1])
32 browser.close()

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

大致講解一下上面出現的一些函式用法和實現過程中存在的問題。

1.使用classname定位,執行時報錯

A:一般來說,使用classname來定位還是比較精準的,但是此專案的classname包含了多個tag,如上述的登入按鈕class='ant-btn logining-btn ant-btn-primary ant-btn-lg ant-btn-background-ghost',這時候使用 find_elements_by_class_name方法定位,會無法定位並報錯。所以需要使用find_elements_by_css_selector,大家可以根據各自專案來選擇方法。

2.urllib.urlretrieve(src,local)

urllib模組提供的urlretrieve()函式,urlretrieve()方法直接將遠端資料下載到本地,傳入下載的連結。

3.命令列獲取引數

為了指定我們想要下載的驗證碼數量,要在源程式裡面修改嗎?不用。sys.argv[]是一個從程式外部獲取引數的橋樑,所獲得的是一個列表(list),文中的sys.argv[1]則是代表獲取列表中的下標為1的內容,在終端我們執行的方法是:python catch_code.py 10 ,這樣sys.argv[1]取到的的值則為10,num的值亦為10,迴圈10次下載驗證碼。

三、識別方案選擇

上節中爬取下來了100張驗證碼,如下圖:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

基本特性是:橫向排列、數字與英文字母組合、字母間粘連佔比約30%、背景干擾較少。閱讀已有的一些ocr識別技術,基本有以下三個方向:

① pytesser

② pytesseract

③ 百度文字識別 AipOcr

為了對比這三者識別技術的識別率,對應實現來展示效果,所以樣本選擇為0.png、4.png、11.png(字母粘連、純字母、字母+數字)

pytesser:谷歌OCR開源專案的一個模組,在python中匯入這個模組即可將圖片中的文字轉換成文字。pytesser下載連結:http://code.google.com/p/pytesser/ ,實現程式碼如下:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

1 #-*- coding:utf-8 -*-
2 from PIL import Image
3 import pytesser.pytesser as pytesser
4 
5 image = Image.open('code_pic/test_pic/0.png')
6 print pytesser.image_file_to_string('code_pic/test_pic/0.png')
7 print pytesser.image_to_string(image)

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

image_file_to_string()函式可以實現簡單的英文字母識別,如果影象是不相容的,會先轉換成相容的格式,然後再提取圖片中的文字資訊。

image_to_string()函式亦可實現英文字母識別,讀取圖片時,將記憶體中的影象檔案儲存為bmp,再使用tesseract處理。

執行結果如下:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

順序識別0,4,11圖片後均無法識別結果,識別概率為0%

pytesseract:Google的Tesseract-OCR引擎包裝器

1 print pytesseract.image_to_string(Image.open('code_pic/test_pic/11.png'),lang="eng")

順序識別0,4,11圖片後均無法識別結果,識別概率為0%

AipOcr:一款百度提供的OCR識別服務,支援多種圖片格式,介面免費呼叫50000次/日,具體請參考官方文件:https://ai.baidu.com/docs#/OCR-API/top ,在實現之前,我們需要建立一款產品,來獲得AppID、API Key、Secret Key的值。如下圖:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

獲取到以上三個引數後,繼續上程式碼:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

 1 from aip import AipOcr
 2 
 3 # 你的 APPID AK SK
 4 APP_ID = '1*****'
 5 API_KEY = 'sHzo*******'
 6 SECRET_KEY = 'V******'
 7 
 8 client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
 9 # 讀取圖片
10 def get_file_content(filePath):
11 with open(filePath, 'rb') as fp:
12 return fp.read()
13 
14 image = get_file_content('/Users/funny/PycharmProjects/auto_cloud/code_pic/test_pic/11.png')
15 # 呼叫通用文字識別, 圖片引數為本地圖片
16 result = client.general(image)
17 
18 # 定義引數變數
19 options = {
20 # 定義影象方向
21 'detect_direction' : 'true',
22 # 識別語言型別,預設為'CHN_ENG'中英文混合
23 'language_type' : 'CHN_ENG',
24 
25 
26 }
27 
28 # 呼叫通用文字識別介面
29 result = client.general(image,options)
30 print(result)
31 for word in result['words_result']:
32 print(word['words'])

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

順序識別0,4,11圖片後,圖片11識別出了一半,提取到了"2F",概率為16%

四、影象處理和識別

在上節看來,未經過處理的圖片進行識別,識別概率都非常之低。所以我們換一個角度來思考,通過對圖片進行一些處理,使得特徵更加明顯,再通過上述的三種識別庫來識別,提高識別的概率。步驟大致如下:1)灰度二值化 2)線降噪 3)開運算

1)灰度二值化

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

im = cv2.imread('/Users/funny/PycharmProjects/auto_cloud/code_pic/0.png')
im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) 
# 二值化
th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)
edges = cv2.Canny(th1, 30, 70)
cv2.imshow('二值化',th1)
cv2.waitKey(0)
cv2.destroyAllWindows()

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

處理的影象如下:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

2)線降噪

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

#二值化圖片,並且線降噪
img = cv2.imread('/Users/funny/PycharmProjects/auto_cloud/code_pic/11.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #灰值化
h, w = img.shape[:2]
# opencv矩陣點是反的
# img[1,2] 1:圖片的高度,2:圖片的寬度
for y in range(1, w - 1):
 for x in range(1, h - 1):
 count = 0
 if img[x, y - 1] > 245:
 count = count + 1
 if img[x, y + 1] > 245:
 count = count + 1
 if img[x - 1, y] > 245:
 count = count + 1
 if img[x + 1, y] > 245:
 count = count + 1
 if count > 2:
 img[x, y] = 255
cv2.imshow('線降噪',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

處理的影象如下:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

3)閉運算

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

img = cv2.imread('/Users/funny/PycharmProjects/auto_cloud/code_pic/11.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 3)) # 定義結構元素
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 開運算
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow('閉運算',closing)
cv2.waitKey(0)
cv2.destroyAllWindows()

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

處理的影象如下:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

影象處理到現在基本上我們已經將已有的背景干擾及色彩去除完畢,接下來我們針對這些處理的影象進行三種識別方案的識別,識別結果如下表:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

我們來分析一下這個表,在最開始的二值化,AipOcr至少識別出來了一些內容。縱觀三種影象處理後的識別效果,明顯閉運算已經能識別出大致的內容了,圖片4.png三種識別方式都是可以識別出來,對於0.png這種粘連字母,識別效果基本為0%,而11.png“j”的底部表現不出來,所以識別不出來,但後面的內容亦識別成功。所以我們可以總結三點:①識別方式精準度 :AipOcr>pytesser>pytesseract。 ②處理後效果:閉運算>線降噪>二值化。③粘連性、帶噪點圖片識別效果非常差(當前準確值是基於我選取的樣本集)。

五、自動化實現

從上節的處理和識別中的總結內容中,本專案我們選擇將AipOcr作為識別,若識別結果不正確(如粘連、噪點過多、部分裁剪圖片),將獲取新的驗證碼,以此類推。將上述部分程式碼封裝,方便呼叫,最終完整程式碼如下:

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

 1 #-*- coding:utf-8 -*-
 2 from selenium import webdriver
 3 from time import sleep
 4 import xlrd
 5 import os
 6 import time
 7 import urllib
 8 import cv2
 9 from aip import AipOcr
 10 #define
 11 req_url = "網址"
 12 local = '/Users/funny/PycharmProjects/auto_cloud/code_pic/code.png'
 13 APP_ID = '1****2'
 14 API_KEY = 's*****'
 15 SECRET_KEY = 'V******Hw'
 16 xlsname="user_tab.xlsx"
 17 
 18 #excel讀取
 19 def Load_excel():
 20 excel = xlrd.open_workbook(xlsname)
 21 shxrange = range(excel.nsheets)
 22 try:
 23 sh = excel.sheet_by_name("Sheet1")
 24 except:
 25 print "no sheet in %s named Sheet1" % xlsname
 26 nrows = sh.nrows
 27 ncols = sh.ncols
 28 #print "nrows %d, ncols %d" % (nrows, ncols)
 29 # 獲取第一行第一列資料
 30 cell_value = sh.cell_value(1, 1)
 31 # print cell_value
 32 row_list = []
 33 # 獲取各行資料
 34 for i in range(1, nrows):
 35 row_data = sh.row_values(i)
 36 row_list.append(row_data)
 37 return row_list
 38 
 39 def change_catch():
 40 img = cv2.imread('/Users/funny/PycharmProjects/auto_cloud/code_pic/code.png')
 41 img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 42 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 3)) # 定義結構元素
 43 closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
 44 cv2.imwrite('/Users/funny/PycharmProjects/auto_cloud/code_pic/code-close.png',closing)
 45 
 46 def code_detect():
 47 client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
 48 f=open('/Users/funny/PycharmProjects/auto_cloud/code_pic/code-close.png','rb')
 49 image =f.read()
 50 # 呼叫通用文字識別, 圖片引數為本地圖片
 51 result = client.general(image)
 52 # 定義引數變數
 53 options = {
 54 # 定義影象方向
 55 'detect_direction': 'true',
 56 # 識別語言型別,預設為'CHN_ENG'中英文混合
 57 'language_type': 'CHN_ENG',
 58 }
 59 # 呼叫通用文字識別介面
 60 result = client.general(image, options)
 61 print result
 62 print str(result['words_result'][0]['words'])
 63 return str(result['words_result'][0]['words'])
 64 
 65 
 66 
 67 
 68 
 69 
 70 if __name__ == '__main__':
 71 
 72 flag=False
 73 row_list=Load_excel()
 74 print row_list
 75 browser = webdriver.Chrome()
 76 browser.get(req_url)
 77 time.sleep(4)
 78 #尋找登入按鈕,查詢登入classname
 79 browser.find_elements_by_css_selector("[class='ant-btn logining-btn ant-btn-primary ant-btn-lg ant-btn-background-ghost']")[0].click()
 80 time.sleep(2)
 81 #獲取驗證碼url
 82 src = browser.find_elements_by_css_selector("[class='picturecode-img']")[0].get_attribute("src")
 83 urllib.urlretrieve(src, local)
 84 print "下載驗證碼中。。。"
 85 change_catch()
 86 word=code_detect()
 87 print word
 88 time.sleep(1)
 89 browser.find_element_by_id("loginName").send_keys(row_list[0][1])
 90 browser.find_element_by_id("password").send_keys(row_list[0][2])
 91 browser.find_element_by_id("imgValidCode").send_keys(word)
 92 browser.find_elements_by_css_selector("[class='ant-btn ant-btn-primary ant-btn-lg ant-btn-block']")[0].click()
 93 time.sleep(1)
 94 
 95 while browser.current_url=="網址":
 96 time.sleep(2)
 97 src = browser.find_elements_by_css_selector("[class='picturecode-img']")[0].get_attribute("src")
 98 urllib.urlretrieve(src, local)
 99 print "下載驗證碼中。。。"
100 change_catch()
101 word = code_detect()
102 time.sleep(2)
103 browser.find_element_by_id("imgValidCode").send_keys(word)
104 browser.find_elements_by_css_selector("[class='ant-btn ant-btn-primary ant-btn-lg ant-btn-block']")[0].click()
105 
106 print "登入成功"

這個人好囂張,python破解驗證碼就算了,然後還批量註冊、登入!

 

對於粘連性及部分被切割的驗證碼,還需要再研究一番~

另,因為驗證碼識別率還不能達到100%,且後期可能因為版本迭代的原因,更換不同方式的驗證碼型別,所以這裡只是提供一個影象預處理思路給到大家,實現登入自動化還有其他方式,如白名單控制、關閉驗證碼校驗等。