爬虫学习笔记(十七)—— 字符验证码
文章目錄
- 一、認識驗證碼
- 1.1、概念
- 1.2、作用
- 1.3、類別
- 二、Pillow庫
- 2.1、PIL庫和Pillow庫
- 2.1.1、Pillow庫安裝
- 2.1.2、PIL與Pillow使用注意
- 2.2、圖形基本概念
- 2.2.1、尺寸
- 2.2.2、坐標系統
- 2.2.3、通道
- 2.3、圖像獲取
- 2.4、獲取圖像通道
- 三、簡單驗證碼處理
- 3.1、灰度化
- 3.1.1、最大值法
- 3.1.2、平均值法
- 3.2、二值化
- 3.3、降噪
- 四、Tesseract識別
- 4.1、OCR識別概念
- 4.2、Tesseract-OCR
- 4.3、Pytesser3
一、認識驗證碼
1.1、概念
驗證碼(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自動區分計算機和人類的圖靈測試)的縮寫,是一種用來區分用戶是計算機還是人的公共全自動程序。
1.2、作用
認證碼是一種人機識別手段,最終目的是區分正常用戶和機器的操作。
可以防止:惡意破解密碼、注冊、刷票、論壇灌水,防止黑客對用戶的密碼進行暴力破解。
一般是提出一個問題,這個問題可以由計算機生成并評判,但是必須只有人類才能解答。由于計算機無法解答這個的問題,所以回答出問題的用戶就可以被認為是人類。
1.3、類別
圖形驗證碼:
這類驗證碼大多是計算機隨機產生一個字符串,在把字符串增加噪點、干擾線、變形、重疊、不同顏色、扭曲組成一張圖片來增加識別難度。
滑動驗證碼:
也叫行為驗證碼,比較流行的一種驗證碼,通過用戶的操作行為來完成驗證,其中最出名的就是極驗。滑動驗證碼的原理就是使用機器學習中的深度學習技術,根據一些特征來區分是否為正常用戶。通過記錄用戶的滑動速度,還有每一小段時間的瞬時速度,用戶鼠標點擊情況,以及滑動后的匹配程度來識別。而且,不是說滑動到正確位置就是驗證通過,而是根據特征識別來區分是否為真用戶,滑到正確位置只是一個必要條件。
點觸驗證碼:
點擊類驗證碼都是給出一張包含文字的圖片,通過文字提醒用戶點擊圖中相同字的位置進行驗證。
二、Pillow庫
2.1、PIL庫和Pillow庫
PIL庫
PIL (Python Image Library) 已經算是 Python 處理圖片的標準庫了,兼具強大的功能和簡潔的 API,但是PIL庫的更新非常緩慢, 并且它只支持到python2.7,不支python3。
Pillow庫
由于PIL庫更新太慢了,于是一群志愿者在PIL庫的基礎上創建的分支版本,命名為Pillow.
Pillow目前最新支持到python3.6,它的維護和開發十分活躍,兼容PIL庫的絕大多數語法,并且增加了許多新的特性,推薦直接使用Pillow
2.1.1、Pillow庫安裝
命令:
pip install pillow2.1.2、PIL與Pillow使用注意
Pillow和PIL不能共存在一個環境中,如果你之前安裝了PIL的話,需要刪除掉才能在安裝Pillow
由于是繼承自PIL的分支, 所以Pillow庫的導入是這樣的:
2.2、圖形基本概念
2.2.1、尺寸
圖片尺寸(size)指的是圖片的寬度和高度,通過size屬性可以獲取圖片的尺寸,它的返回值是一個元組,元組里面有兩個值,分別是水平和垂直方向上的像素個數。
代碼示例:
from PIL import Image img = Image.open('xxx.png') #參數:圖片位置 print(img.size) #(xxx,xxx)2.2.2、坐標系統
使用笛卡爾像素坐標系,x軸從左到右,y軸從上到下增長
2.2.3、通道
圖片均是由一個或者多個數據通道構成。
RGB圖像:每張圖片都是由三個數據通道疊加構成,分別為R 、G 、B。
PNG圖像:有RGBA四個通道,A代表透明度。
灰度圖像(沒有色彩的圖片, RGB色彩分量全部相等):只有一個通道。
灰度指的是黑白圖像中點的顏色深度,范圍一般是0到255, 白色為255,黑色為0。
2.3、圖像獲取
例:
from PIL import Image img = Image.open('dog2.png') #open參數: 圖片的位置例:
img =Image.new("RGB",(200,100),"red")注意:這里的最后一個參數可以用ImageColor里面的colormap來獲得更多初始化的顏色。
函數:
Image.crop(left, up, right, below)參數:
① left:與左邊界的距離
② up:與上邊界的距離
③ right:還是與左邊界的距離
④ below:還是與上邊界的距離
例:
from PIL import Imageimg = Image.open('dog2.png') w,h = img.size# 準備將圖片切割成9張小圖片 weight = int(w // 3) height = int(h // 3) # 切割后的小圖的寬度和高度 print(weight, height)for j in range(3):for i in range(3):box = (weight * i, height * j, weight * (i + 1), height * (j + 1))region = img.crop(box)region.save('imgs/{}{}.png'.format(j, i))結果:
2.4、獲取圖像通道
函數:getbands()
例:
from PIL import Imageimg = Image.open('dog2.png') print(img.getbands()) # ('R', 'G', 'B')三、簡單驗證碼處理
3.1、灰度化
灰度圖像上每個像素的顏色值又稱為灰度,指黑白圖像中點的顏色深度,范圍一般從0到255,白色為255,黑色為0。所謂灰度值是指色彩的濃淡程度,灰度直方圖是指一幅數字圖像中,對應每一個灰度值統計出具有該灰度值的象素數。
灰度就是沒有色彩,RGB色彩分量全部相等。如果是一個二值灰度圖象,它的象素值只能為0或1,我們說它的灰度級為2。用個例子來說明吧:一個256級灰度的圖象,如果RGB三個量相同時,如:RGB(100,100,100)就代表灰度為100,RGB(50,50,50)代表灰度為50。
現在大部分的彩色圖像都是采用RGB顏色模式,處理圖像的時候,要分別對RGB三種分量進行處理,實際上RGB并不能反映圖像的形態特征,只是從光學的原理上進行顏色的調配。
圖像灰度化處理可以作為圖像處理的預處理步驟,為之后的圖像分割、圖像識別和圖像分析等上層操作做準備。
目的: 為二值化做準備
彩色變黑白,三通道變成一個通道
圖片的灰度化,就是讓像素點矩陣中的每一個像素點滿足 R=G=B,此時這個值叫做灰度值,白色為255,黑色為0
灰度轉化一般公式為:
R=G=B = 處理前的 RX0.3 + GX0.59 + B*0.11這種灰度轉化方法被稱為加權平均法。
根據重要性及其它指標,將三個分量以不同的權值進行加權平均。由于人眼對綠色的敏感最高,對藍色敏感最低,因此,對RGB三分量進行加權平均能得到較合理的灰度圖像。除了這種灰度轉化方法另外還有兩種方法,大家稍作了解:
3.1.1、最大值法
將彩色圖像中的三分量亮度的最大值作為灰度圖的灰度值。
3.1.2、平均值法
將彩色圖像中的三分量亮度求平均得到一個灰度值。
函數:im = img.convert('L')
例:
from PIL import Imageimg = Image.open('code.jpeg') img.show() im = img.convert('L') #轉為灰度圖 print(im.getbands()) #('L',) im.show()結果 (左:原圖,右:灰度圖):
3.2、二值化
圖像的二值化,就是將圖像的像素點矩陣中的每個像素點的灰度值設置為0(黑色)或255(白色),從而實現二值化,將整個圖像呈現出明顯的只有黑和白的視覺效果。
二值化原理是利用設定的一個閾值來判斷圖像像素是0還是255, 一般小于閾值的像素點變為0, 大于的變成255,這個臨界灰度值就被稱為閾值,閾值的設置很重要,閾值過大或過小都會對圖片造成損壞,選擇閾值的原則是:既要盡可能保存圖片信息,又要盡可能減少背景和噪聲的干擾。
常用閾值選擇的方法是:
- 灰度平均值值法: 取127 (0~255的中數, (0+255)/2 = 127)
- 平均值法:
計算像素點矩陣中的所有像素點的灰度值的平均值avg - 迭代法:
選擇一個近似閾值作為估計值的初始值(比如全圖像的平均灰度),然后進行分割圖像,產生兩組像素,一組大于初始灰度值,另一組小于初始灰度值,根據產生的子圖像的特征來選取新的閾值,在利用新的閾值分割圖像,經過多次循環,使得錯誤分割的圖像像素點降到最小。
代碼(迭代法):
def ImgBinaryzation(img_gray): #灰度圖二值化 傳入的圖片為灰度圖w,h=img_gray.sizetemp = 0for i in range(w):for j in range(h):temp += img_gray.getpixel((i,j))# 閾值avg_pixel = temp /(i*j)#像素點和閾值比較for x in range(w):for y in range(h):img_pixel = img_gray.getpixel((x,y))if img_pixel < avg_pixel: #小于像素點 像素點設為0img_gray.putpixel((x,y),0)else: #不小于像素點 像素點設為255img_gray.putpixel((x,y),255) return img_gray示例:
from PIL import Imageimg = Image.open('code.jpeg') img_gray = img.convert('L')def ImgBinaryzation(img_gray): #灰度圖二值化w,h=img_gray.sizetemp = 0for i in range(w):for j in range(h):temp += img_gray.getpixel((i,j))# 閾值 如果二值化效果不好,可以再根據結果乘以百分比avg_pixel = temp /(i*j)#像素點和閾值比較for x in range(w):for y in range(h):img_pixel = img_gray.getpixel((x,y))if img_pixel < avg_pixel: #小于像素點 像素點設為0img_gray.putpixel((x,y),0)else: #不小于像素點 像素點設為255img_gray.putpixel((x,y),255) return img_graypic = img_binaryzation(img_gray) pic.show()結果 (左:原圖,右:二值化結果):
3.3、降噪
目的:清除干擾點,讓圖片更清晰,讓計算機更利于識別。
降噪原理:
孤立的噪點,他的周圍應該都是白色,或者大多數點都是白色的,所以在判斷的時候條件應該放寬,一個點是黑色并且相鄰的點為白色的點的個數大于一個固定的值,那么這個點就是噪點。
注:這里只是比較簡單的講一下最基本的圖像降噪原理,實際上對圖像的降噪有很多種,比如高斯濾波、統計中值濾波、雙邊濾波等等,這些就要涉及比較深入的圖像處理了。
代碼:
def GetPointList(x,y,prange): #獲取像素點周圍的坐標for i in range(x-prange,x+prange+1):for j in range(y-prange,y+prange+1):if x==i and y == j:continueyield i,jdef reduceNoise(img_binary): #二值化后再進行降噪w,h = img_binary.sizeprange = 3 #到邊界的范圍 自己根據降噪效果進行調試bound_rate = 0.14 #設置邊界比例 自己根據降噪效果進行調試count_rate = 0.56 #設置像素點周圍灰度值為255的比例 自己根據降噪效果進行調試for i in range(w):for j in range(h):# 處理邊界 變白if i<bound_rate*w or i>w*(1 - bound_rate) or j<bound_rate*h or j>h*(1 - bound_rate):img_binary.putpixel((i,j),255)continueimg_pixel = img_binary.getpixel((i,j))if img_pixel < 200: #二值圖像素點只有0和255,隨便取個中間的值就行count = 0for x,y in GetPointList(i,j,prange):if img_binary.getpixel((x,y)) >200: #計算該像素點周圍灰度值為255的個數count += 1if count > count_rate * ((prange*2+1)**2 - 2): #像素點周圍灰度值為255的個數是否超過一定比例來判斷是否是噪點img_binary.putpixel((i,j),255)return img_binary示例:
from PIL import Imageimg = Image.open('code.jpeg') img_gray = img.convert('L')def ImgBinaryzation(img_gray): #灰度圖二值化w,h=img_gray.sizetemp = 0for i in range(w):for j in range(h):temp += img_gray.getpixel((i,j))# 閾值avg_pixel = temp /(i*j)#像素點和閾值比較for x in range(w):for y in range(h):img_pixel = img_gray.getpixel((x,y))if img_pixel < avg_pixel: #小于像素點 像素點設為0img_gray.putpixel((x,y),0)else: #不小于像素點 像素點設為255img_gray.putpixel((x,y),255)return img_graydef GetPointList(x,y,prange): #獲取像素點周圍的坐標for i in range(x-prange,x+prange+1):for j in range(y-prange,y+prange+1):if x==i and y == j:continueyield i,jdef reduceNoise(img_binary): #二值化后再進行降噪w,h = img_binary.sizeprange = 3 #到邊界的范圍 自己根據降噪效果進行調試bound_rate = 0.14 #設置邊界比例 自己根據降噪效果進行調試count_rate = 0.56 #設置像素點周圍灰度值為255的比例 自己根據降噪效果進行調試for i in range(w):for j in range(h):img_pixel = img_binary.getpixel((i,j))if img_pixel < 200: #二值圖像素點只有0和255,隨便取個中間的值就行count = 0for x,y in GetPointList(i,j,prange):if img_binary.getpixel((x,y)) >200: #計算該像素點周圍灰度值為255的個數count += 1if count > count_rate * ((prange*2+1)**2 - 2): #像素點周圍灰度值為255的個數是否超過一定比例來判斷是否是噪點img_binary.putpixel((i,j),255)return img_binarypic = ImgBinaryzation(img_gray.copy()) for i in range(2): #可能第一遍降噪效果不大會,進行多次處理pic = reduceNoise(pic.copy())pic.show()結果 (左:原圖,右:降噪結果):
四、Tesseract識別
4.1、OCR識別概念
OCR (Optical Character Recognition)光學字符識別, 指的是對文本資料的圖像文件進行分析識別處理,獲取文集及版面信息的過程
4.2、Tesseract-OCR
一個開源的字符識別引擎,我們可以用他來識別一些簡單的驗證碼。
Windows下安裝:
https://digi.bib.uni-mannheim.de/tesseract/ 可自行下載,點擊下一步即可;
Linux安裝:
sudo apt-get install tesseract-ocr sudo apt-get install libtesseract-devMac安裝:
brew install tesseract4.3、Pytesser3
是一個在Python內使用Tesseract-Ocr的庫,
Pytesseract文檔:https://pypi.org/project/pytesseract/
安裝:pip install Pytesseract
需要配置:
方法一:將pytesseract包下面__init__文件內tesseract_exe_name的值設置為你的tesseract.exe的路徑。
方法二:在代碼中指定
pytesseract.pytesseract.tesseract_cmd = r'X:\xxx\tesseract.exe'示例:
import pytesseract from PIL import Imagepic = Image.open('reduceNoise.png') #圖片為上面降噪結果圖 print(pytesseract.image_to_string(pic)) # 結果:7364注意:
Pytesseract識別效果不佳,如果想提高識別率,可以使用jTessBoxEditor對Tesseract進行簡單的訓練。OCR是一個專門的圖像處理的領域,高精度的識別需要依靠深度學習、神經網絡等技術。
總結
以上是生活随笔為你收集整理的爬虫学习笔记(十七)—— 字符验证码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫学习笔记(十六)—— Seleniu
- 下一篇: 爬虫学习笔记(十九)—— 滑动验证码