最近爬取一個網站時,遇到了驗證碼的狀況。驗證碼形式是計算題,10之內的數字(可能有少許十以上),加減乘計算。html
開始懶得搞,第一批須要的數據量並不大,想着直接平臺打碼。python
緣由是之前登陸新浪微博的時候也是直接打碼的,比較熟練,也簡便。但打碼成本比較高,後續需求量大,因此最好本身能識別。ide
看了幾篇識別驗證碼的文章,基本處理流程以下:字體
1.去掉顏色;灰度處理,二值化等網站
2.去掉干擾,降噪;噪點,線等的處理spa
3.切割字符,單獨識別code
4.訓練字體htm
5.自動識別blog
我須要識別的驗證碼形式以下:教程
通過反覆試驗,定了如下幾個步驟:
1.去除干擾,將圖片中的干擾點線等刪除
2.識別圖片,使用pytesseract識別圖片
3.計算結果,使用識別出來的字符數字計算結果
以上是代碼的流程,實際操做中還須要訓練字體,這裏留在最後說明。
使用這張圖片爲例,簡要介紹一下流程:
以上幾個步驟的基本操做思想:
1.去噪。一般的思想是根據像素點的相鄰關係等去除,我在識別的過程當中發現,這裏的圖片像素值比較單一,
噪點的顏色比數字的顏色要淺。簡單打印一下RGB值,能夠發現除了(255,255,255)表示的白色之外,大體顏色值有如下幾種:
(140,140,140)
(112,112,112)
(117,117,117)
因而,我經過判斷像素點的RGB值,把以上幾種點用白色替換(即去掉該點),示例圖片轉換後獲得圖像以下
能夠看到這個結果,基本上就能夠拿去識別了。這也是爲何我稱此次驗證碼識別爲簡單粗暴。
2.識別。識別使用的是tesseract直接識別,沒什麼好講的,貼幾個連接本身看。
關於數據訓練,也是直接照着教程作的,連文件名都沒改,所幸過程當中並未出錯。
from pytesseract import image_to_string im = Image.open("1_no_noise.png") str_img = image_to_string(im, lang='eng', config='-psm 6') print('識別爲:%s' % str_img)
使用原裝英文庫識別結果以下:
識別爲:7x3:?
使用訓練過的庫識別:
from pytesseract import image_to_string im = Image.open("1_no_noise.png") str_img = image_to_string(im, lang='fontyp', config='-psm 70') print('識別爲:%s' % str_img) # 識別爲:7x3=?
※在使用過程當中,嘗試修改config的配置,能夠幫助更準確地識別。
3.計算結果。計算結果就是拿識別出來的字符串,簡單拆分,分析操做符,作出對應計算,由於識別的時候沒有切圖,因此直接切割字符串。
在切割字符串以後的數字轉換作了簡單的矯正。
總體代碼以下:
# encoding=utf-8 __author__ = 'Masako' from PIL import Image from io import BytesIO from pytesseract import image_to_string NOISE_RGB_LIST = [117, 140, 112] # 噪點像素值列表 OPERATE_LIST = ['+', 'x', 'X', '-', '—']
# 去除噪點 def del_point(img): pix = img.load() width = img.size[0] height = img.size[1] for x in range(width): for y in range(height): r, g, b = pix[x, y] # print(r, g, b) if r in NOISE_RGB_LIST: pix[x, y] = 255, 255, 255 return img # 數字識別 def data_ident(data_str): num = None if data_str == 'q': num = 9 elif data_str == 'z' or data_str == 'Z': num = 2 elif data_str == 'G': num = 6 else: try: num = int(data_str) except Exception as e: print("can't identify:" + data_str) return num # 計算結果 def deal_img_str(img_str): # str_list = img_str.split(' ') # print(str_list) calculate_result = None try: data_str = img_str[:img_str.rindex('=')] except Exception as e: print(img_str) return # print(data_str) for operate in OPERATE_LIST: if operate in data_str: # 判斷操做符 data_list = data_str.split(operate) if len(data_list) == 2: # 正確分割時的處理 data_left = data_ident(data_list[0]) data_right = data_ident(data_list[1]) if data_left and data_right: if operate == '+': calculate_result = data_left + data_right elif operate == 'x' or operate == 'X': calculate_result = data_left * data_right else: calculate_result = data_left - data_right if calculate_result != None: break return calculate_result def img_to_captcha_code(img_content): image_data = BytesIO(img_content) im = Image.open(image_data) im = del_point(im) str_img = image_to_string(im, lang='fontyp', config='-psm 70') result = deal_img_str(str_img) return result if __name__ == "__main__": im = Image.open("a.jpg") im = del_point(im) im.save('a_no.jpg') str_img = image_to_string(im, lang='fontyp', config='-psm 70') print('識別爲:%s' % str_img)
參考文章連接:
https://www.cnblogs.com/qqandfqr/p/7866650.html
http://www.cnblogs.com/cnlian/p/5765871.html