寫爬蟲有一個繞不過去的問題就是驗證碼漾根,現(xiàn)在驗證碼分類大概有4種:
圖像類
滑動類
點擊類
語音類
今天先來看看圖像類,這類驗證碼大多是數(shù)字鲫竞、字母的組合辐怕,國內(nèi)也有使用漢字的。在這個基礎(chǔ)上增加噪點从绘、干擾線寄疏、變形、重疊僵井、不同字體顏色等方法來增加識別難度陕截。
相應(yīng)的,驗證碼識別大體可以分為下面幾個步驟:
灰度處理
增加對比度(可選)
二值化
降噪
傾斜校正分割字符
建立訓(xùn)練庫
識別
由于是實驗性質(zhì)的批什,文中用到的驗證碼均為程序生成而不是批量下載真實的網(wǎng)站驗證碼农曲,這樣做的好處就是可以有大量的知道明確結(jié)果的數(shù)據(jù)集。
當需要真實環(huán)境下需要獲取數(shù)據(jù)時驻债,可以使用結(jié)合各個大碼平臺來建立數(shù)據(jù)集進行訓(xùn)練乳规。
生成驗證碼這里我使用Claptcha(本地下載)這個庫,當然Captcha(本地下載)這個庫也是個不錯的選擇合呐。
為了生成最簡單的純數(shù)字暮的、無干擾的驗證碼,首先需要將claptcha.py的285行_drawLine做一些修改淌实,我直接讓這個函數(shù)返回None冻辩,然后開始生成驗證碼:
from? claptcha? import? Claptcha
c =Claptcha("8069","/usr/share/fonts/truetype/freefont/FreeMono.ttf")
t,_ =c.write('1.png')
這里需要注意ubuntu的字體路徑,也可以在網(wǎng)上下載其他字體使用翩伪。生成驗證碼如下:
可以看出微猖,驗證碼有形變。對于這類最簡單的驗證碼缘屹,可以直接使用谷歌開源的tesserocr來識別凛剥。
首先安裝:
apt-get? install? tesseract-ocr libtesseract-dev libleptonica-dev
pip installtesserocr
然后開始識別:
from? PIL? import? Image
import tesserocr
p1 =Image.open('1.png')
tesserocr.image_to_text(p1)
'8069\n\n'
可以看出,對于這種簡單的驗證碼轻姿,基本什么都不做識別率就已經(jīng)很高了犁珠。有興趣的小伙伴可以用更多的數(shù)據(jù)來測試逻炊,這里我就不展開了。
接下來犁享,在驗證碼背景添加噪點來看看:
c =Claptcha("8069","/usr/share/fonts/truetype/freefont/FreeMono.ttf",noise=0.4)
t,_ =c.write('2.png')
生成驗證碼如下:
識別:
p2 =Image.open('2.png')
tesserocr.image_to_text(p2)
'8069\n\n'
效果還可以余素。接下來生成一個字母數(shù)字組合的:
c2 =Claptcha("A4oO0zZ2","/usr/share/fonts/truetype/freefont/FreeMono.ttf")
t,_ =c2.write('3.png')
生成驗證碼如下:
第3個為小寫字母o,第4個為大寫字母O炊昆,第5個為數(shù)字0桨吊,第6個為小寫字母z,第7個為大寫字母Z凤巨,最后一個是數(shù)字2视乐。人眼已經(jīng)跪了有木有!但現(xiàn)在一般驗證碼對大小寫是不做嚴格區(qū)分的敢茁,看自動識別什么樣吧:
p3 =Image.open('3.png')
tesserocr.image_to_text(p3)
'AMOOZW\n\n'
人眼都跪的計算機當然也廢了佑淀。但是么鹤,對于一些干擾小院塞、形變不嚴重的米同,使用tesserocr還是十分簡單方便的蟆沫。然后將修改的claptcha.py的285行_drawLine還原,看添加干擾線的情況柴信。
p4 =Image.open('4.png')
tesserocr.image_to_text(p4)
加了條干擾線就完全識別不出來了茉唉,那么有沒有什么辦法去除干擾線呢岸夯?
雖然圖片看上去是黑白的瓶堕,但還需要進行灰度處理隘道,否則使用load()函數(shù)得到的是某個像素點的RGB元組而不是單一值了症歇。處理如下:
def? ?binarizing(img,threshold):
?"""傳入image對象進行灰度郎笆、二值處理"""
?img =img.convert("L") # 轉(zhuǎn)灰度
?pixdata =img.load()
?w, h =img.size
?# 遍歷所有像素,大于閾值的為黑色
?fory inrange(h):
??forx inrange(w):
???ifpixdata[x, y] < threshold:
????pixdata[x, y] =0
???else:
????pixdata[x, y] =255
?return? img
處理后的圖片如下:
可以看出處理后圖片銳化了很多忘晤,接下來嘗試去除干擾線宛蚓,常見的4鄰域、8鄰域算法设塔。所謂的X鄰域算法凄吏,可以參考手機九宮格輸入法,按鍵5為要判斷的像素點闰蛔,4鄰域就是判斷上下左右痕钢,8鄰域就是判斷周圍8個像素點。如果這4或8個點中255的個數(shù)大于某個閾值則判斷這個點為噪音序六,閾值可以根據(jù)實際情況修改任连。
def? depoint(img):
?"""傳入二值化后的圖片進行降噪"""
?pixdata =img.load()
?w,h =img.size
?fory inrange(1,h-1):
??forx inrange(1,w-1):
???count =0
???ifpixdata[x,y-1] > 245:#上
????count =count +1
???ifpixdata[x,y+1] > 245:#下
????count =count +1
???ifpixdata[x-1,y] > 245:#左
????count =count +1
???ifpixdata[x+1,y] > 245:#右
????count =count +1
???ifpixdata[x-1,y-1] > 245:#左上
????count =count +1
???ifpixdata[x-1,y+1] > 245:#左下
????count =count +1
???ifpixdata[x+1,y-1] > 245:#右上
????count =count +1
???ifpixdata[x+1,y+1] > 245:#右下
????count =count +1
???ifcount > 4:
????pixdata[x,y] =255
?return? img
處理后的圖片如下:
好像……根本沒卵用啊例诀?随抠!確實是這樣的裁着,因為示例中的圖片干擾線的寬度和數(shù)字是一樣的。對于干擾線和數(shù)據(jù)像素不同的拱她,比如Captcha生成的驗證碼:
從左到右依次是原圖二驰、二值化、去除干擾線的情況秉沼,總體降噪的效果還是比較明顯的桶雀。另外降噪可以多次執(zhí)行,比如我對上面的降噪后結(jié)果再進行依次降噪唬复,可以得到下面的效果:
再進行識別得到了結(jié)果:
p7 =Image.open('7.png')
tesserocr.image_to_text(p7)
'8069 ,,\n\n'
另外背犯,從圖片來看,實際數(shù)據(jù)顏色明顯和噪點干擾線不同盅抚,根據(jù)這一點可以直接把噪點全部去除漠魏,這里就不展開說了。
第一篇文章妄均,先記錄如何將圖片進行灰度處理柱锹、二值化、降噪丰包,并結(jié)合tesserocr來識別簡單的驗證碼禁熏,剩下的部分在下一篇文章中和大家一起分享。