Python驗證碼識別初探(tesserocr庫)

轉載自:https://juejin.im/post/5b1b3cd26fb9a01e700ffe5b

前言

寫爬蟲有一個繞不過去的問題,那就是驗證碼,比如像某乎,如果不先登陸,連裏面的內容數據都爬不到,而驗證碼就是網站進行發爬蟲的一種措施,隨着技術的發展,驗證碼越來越複雜,爬蟲的工作越來越艱苦,所以這次就來講解,怎麼來識別驗證碼;(聽上去口氣很大的感覺)

[圖片上傳失敗...(image-481fc8-1552112841682)]

<figcaption></figcaption>

先來看看,目前遇到的驗證碼種類有哪些?

1)圖形驗證碼
圖形驗證碼應該是最簡單的一種驗證碼,這種驗證碼是最早出現,也是目前最常見的,一般組成規則是4個字母或數字或混合組成;

[圖片上傳失敗...(image-631d4b-1552112841682)]

<figcaption></figcaption>

2)滑動驗證碼

[圖片上傳失敗...(image-50e2f6-1552112841682)]

<figcaption></figcaption>

3)點觸驗證碼

[圖片上傳失敗...(image-f5e571-1552112841682)]

<figcaption></figcaption>

[圖片上傳失敗...(image-b119ee-1552112841682)]

<figcaption></figcaption>

Ok,上面這3種驗證碼方式,應該是目前PC上比較常見的驗證碼種類的,當然手機app上還會有手勢驗證,宮格驗證,語音驗證等等,這裏就不介紹,主要針對上面常見的3種介紹;

1 圖形驗證碼

某乎的驗證碼有2種,一種是圖形驗證碼,一種是點觸驗證碼,經過測試發現,一開始是顯示圖形驗證碼,但當登陸退出次數逐漸增多,就會變成點觸驗證碼,這種驗證碼的切換機制,也算是防爬蟲的一種手段,閒話不多說,先喵喵:

某乎鏈接:https://www.zhihu.com/signup?next=%2F
打開後默認是在註冊頁面,點擊下登陸按鈕,如果還是沒有驗證碼,刷新幾次網頁就行了;

[圖片上傳失敗...(image-a00e41-1552112841682)]

<figcaption></figcaption>

下面這種,下2篇文章會介紹;

[圖片上傳失敗...(image-3c41e6-1552112841682)]

<figcaption></figcaption>

2 信息介紹

識別圖形驗證碼需要安裝tesserocr這個庫,下面介紹下tesserocr;
tesserocr是Python的一個OCR識別庫,但其實是對tesseract做了一層Python Api的封裝,
核心還是tesseract,所以在安裝tesserocr之前,需要先安裝tesseract;

等下,懵逼中,tesserocr這個能看明白,是一個庫,但OCR是什麼?tesseract又是什麼?

OCR
OCR,全稱叫 Optical Character Recognition,中文翻譯叫光學字符識別,是指通過掃描字符,通過其形狀將其翻譯成電子文本的過程;

舉例:
當有一個圖形驗證碼,先使用OCR技術將其轉化成電子文本,然後爬蟲將識別的結果提交到服務器,便達到自動識別驗證碼的過程;

tesseract
tesseract是google開源的OCR

OK,貌似對概念有所理解了,還有個疑問,之前有在圖形識別領域,還有個opencv的玩意,那這兩者有什麼區別?
opencv專注機器視覺
tesseract專注字符識別

所以從領域來說,opencv更廣,而圖形驗證碼,opencv也可以做,但殺雞焉用牛刀~

3 環境準備

windows下的安裝

在Windows下,要先下載tesseract,它爲tesserocr提供了支持;
tesseract下載地址:https://digi.bib.uni-mannheim.de/tesseract/
打開後,可以看到各種exe的列表,可以隨便挑選;
其中文件名中帶有dev的爲開發版本,不帶dev則爲穩定版本,例如jb是下載 tesseract-ocr-setup-3.05.01.exe;

[圖片上傳失敗...(image-24f3a4-1552112841682)]

<figcaption></figcaption>

下載後雙擊,一路點擊,直到出現下面這個頁面

[圖片上傳失敗...(image-450403-1552112841682)]

<figcaption></figcaption>

這裏需要勾選紅框裏的Additional language data(download),這個選項是安裝OCR識別支持的語言包,這樣OCR就可以識別多國語言,然後再一路點擊NEXT即可,因爲要下載語言包,所以需要點時間,大概10-20分鐘左右,跟網速有關,如果不需要支持多國語言的話,也可以不勾選,自由選擇
需要說明:默認包含英文字庫
如果,覺得一次下載那麼多語言佔空間,又或者覺得網速慢,也可以選擇單獨安裝中文字庫;
字庫下載地址:https://github.com/tesseract-ocr/tessdata
打開後,直接搜索chi_sim.traineddata,這個代表的就是中文,下載下來;
然後找到剛剛tesseract安裝目錄,裏面會有一個叫tessdata的目錄,直接把剛下載的語言包放到這個目錄下即可;

[圖片上傳失敗...(image-2f0ccc-1552112841682)]

<figcaption></figcaption>

如何驗證tesseract是否安裝成功?直接cmd下輸入tesseract即可;
成功會直接顯示信息;

[圖片上傳失敗...(image-e4152d-1552112841682)]

<figcaption></figcaption>

如果提示'tesseract' 不是內部或外部命令,則是因爲沒有配置環境變量,手動把tesseract根目錄配置到path參數下即可,這塊不詳細說明;

到此爲止,tesseract安裝成功啦~

接下來就安裝tesserocr,直接pip命令即可:

pip3 install tesserocr install
複製代碼

但jb在安裝的時候,直接報錯:

[圖片上傳失敗...(image-9bb5ad-1552112841682)]

<figcaption></figcaption>

試過很多種方式,就算使用conda install tesserocr,也一樣報錯。

[圖片上傳失敗...(image-b2ed56-1552112841682)]

<figcaption></figcaption>

經歷千辛萬苦,終於找到一條可行的命令:

conda install -c simonflueckiger tesserocr
複製代碼

[圖片上傳失敗...(image-b0883e-1552112841682)]

<figcaption></figcaption>

最終就安裝上tesserocr啦~

如何驗證是否真的安裝了?很簡單,直接import tesserocr,不報錯就說明安裝好了;

[圖片上傳失敗...(image-6101ac-1552112841682)]

<figcaption></figcaption>

對了,如果有同學不知道conda這條命令的話,請訪問下面的鏈接,直接搜索scrapy安裝,會有介紹conda:
https://juejin.im/post/5afcb91251882565bd257097|

OK,windows下的tesserocr跟tesseract的環境已經安裝好了;

彆着急,順便介紹下Linux跟Mac,但以下方式均未經過jb驗證,信息來源於網上,僅供參考:

Linux下的安裝
對於Liunx來說,不同系統已經有了不同的發行包了,它可能叫做tesseract-ocr或者tesseract,直接用對應的命令安裝即可;

  • Ubuntu、Debian和Deepin
    在Ubuntu、Debian和Deepin系統下,安裝命令如下:

      sudo apt-get install-y tesseract-ocr libtesseract-dev libleptioica-dev
    複製代碼
    
  • CentOS、Red Hat 在CentOS和Red Hat系統下,安裝命令如下:

      yum install -y tesseract
    複製代碼
    

在不同發行版本運行如上命令,即可完成tesseract的安裝;
安裝完成後,便可以調用tesseract命令;
默認也是指安裝英文語言,如果需要安裝其他語言,請看下上面Windows的介紹,一樣的處理方案,這裏不重複說明;

接下來就是安裝tesserocr,直接使用pip安裝:

pip3 install tesserocr pillow
複製代碼

Mac下的安裝
在Mac下,首先使用Homebrew 安裝ImageMagick 和tesseract庫:

brew install imagemagick
brew install tesseract --all-languages
複製代碼

接下來再安裝tesserocr即可:

brew install tesserocr pillow
複製代碼

4 識別測試

爲了方便測試,需要把驗證碼的圖片保存到本地;
打開weibo.com,隨便輸入賬號密碼,會提示輸入驗證碼,打開開發者工具,找到驗證碼元素,它的src屬性就是一個鏈接,copy出來直接打開,會看到一個驗證碼,而且刷新的驗證碼會變化,由此推斷這是個驗證碼的接口,右鍵保存驗證碼即可,就得到一張驗證碼;
驗證碼鏈接:
https://login.sina.com.cn/cgi/pin.php?r=9967937&s=0&p=gz-d0dc363f6a4523cbd602a5a10f00c59b4784

[圖片上傳失敗...(image-f3a7fe-1552112841681)]

<figcaption></figcaption>

[圖片上傳失敗...(image-afd087-1552112841681)]

<figcaption></figcaption>

ok,完事具備,那就開始吧,新建項目,把驗證碼放到項目根目錄下;
用tesserocr庫來識別驗證碼:

import tesserocr
from PIL import Image

#新建Image對象
image = Image.open("3.jpg")
#調用tesserocr的image_to_text()方法,傳入image對象完成識別
result = tesserocr.image_to_text(image)
print(result)
複製代碼

[圖片上傳失敗...(image-467ae7-1552112841681)]

<figcaption></figcaption>

結果,運行後,啥都沒有???
接下來jb陷入了困擾,包括調試,找各種文檔,最終,把上面調試的驗證碼換了一個:

[圖片上傳失敗...(image-4c4e95-1552112841681)]

<figcaption></figcaption>

替換下圖片,再執行一次代碼:

[圖片上傳失敗...(image-9bb8b6-1552112841681)]

<figcaption></figcaption>

OK,看到是有數據了,不過輸出的是MEEE,跟驗證碼的ME8E還是有點不一樣;

目前兩個問題:
1)微博的驗證碼識別失敗,輸出空
2)第二章驗證碼部分詞識別有誤

心想,這庫是網上都推薦用的,是Google開源的,理論上沒問題,而且人家也都這麼用,爲什麼這裏就有問題?難道還需要額外的處理?

懷着疑問跟夢想,繼續學習;

題外話: tesserocr還有一個更加簡單的方法,這個方法可直接將圖片文件轉換成字符串,代碼如下:

import tesserocr
print(tesserocr.file_to_text("1.jpg"))
複製代碼

[圖片上傳失敗...(image-47278c-1552112841681)]

<figcaption></figcaption>

結果也跟上面的一樣,但網上不建議這麼用,原因是據說這種識別效果不如上一種的好;

關於微博驗證碼爲空,使用tesseract輸出下原因:

tesseract 圖片路徑 output 
複製代碼

[圖片上傳失敗...(image-e8ce79-1552112841681)]

<figcaption></figcaption>

leptonica 在解析時沒有檢測到任何dpi;

5 驗證碼處理

網上找了下信息,比如這張驗證碼:

[圖片上傳失敗...(image-8e7a15-1552112841681)]

<figcaption></figcaption>

可能是驗證碼內的多餘線條幹擾了圖片的識別;

又比如微博這張:

[圖片上傳失敗...(image-858d87-1552112841681)]

<figcaption></figcaption>

可能是字體位置,跟圖案等因素干擾了圖標的識別;

解決方案還是有的,需要對圖片進行額外的處理,如轉灰度,二值化等操作;

轉灰度處理: 利用Image對象的convert()方法參數傳入L,即可將圖片轉成爲灰度圖像:

from PIL import Image

image = Image.open("1.jpg")
image = image.convert('L')
image.show()
複製代碼

[圖片上傳失敗...(image-f22f8e-1552112841681)]

<figcaption></figcaption>

圖片成功轉灰了;此時我們再校驗一下,發現校驗還是MEEE,失敗;[圖片上傳失敗...(image-c3c54a-1552112841681)]

<figcaption></figcaption>

傳入1的後,即可將圖片進行二值化處理:
(二值化是指將圖像上的像素點的灰度值設置爲0或255,也就是將整個圖片呈現出明顯的只有黑和百的視覺效果)

import tesserocr
from PIL import Image

image = Image.open("1.jpg")
image = image.convert('1')
image.show()
複製代碼

[圖片上傳失敗...(image-6a2b17-1552112841681)]

<figcaption></figcaption>

這個一看,比上面更模糊了,理所當然的,校驗結果會錯的更加離譜:[圖片上傳失敗...(image-b4154e-1552112841681)]

<figcaption></figcaption>

二值化的閾值是可以指定的,上面的方法採用的是默認閾值127;但一般很少直接轉換原圖,原因如上可看到,錯誤的更加離譜了;

一般是先將原圖轉爲灰度圖像,然後再指定二值化的閾值,代碼如下:

import tesserocr
from PIL import Image

#新建Image對象
image = Image.open("1.jpg")
#進行置灰處理
image = image.convert('L')
#這個是二值化閾值
threshold = 150   
table = []

for i in  range(256):
    if i < threshold:
        table.append(0)
    else:
        table.append(1)
#通過表格轉換成二進制圖片,1的作用是白色,不然就全部黑色了
image = image.point(table,"1")
image.show()
result = tesserocr.image_to_text(image)
print(result)
複製代碼

這裏說明下,可能有同學對256不明白,這是什麼?
首先,我們是把圖片置灰處理,灰度圖像是一種具有從黑到白256級灰度色階或等級的單色圖像;
對於灰度圖像利用閾值得到二值化的圖像, 也就是說,我們設定了一個閾值,從0到256,如果灰度圖像少於閾值則設置0,大於閾值則設置1,0是黑色,1是白色,這樣做,就可以把一個灰度圖完全轉換二值化圖;
可能還是懵逼,直接貼圖:
原圖

[圖片上傳失敗...(image-136781-1552112841680)]

<figcaption></figcaption>

灰度圖:

[圖片上傳失敗...(image-d250a7-1552112841680)]

<figcaption></figcaption>

二值圖:

[圖片上傳失敗...(image-9065a-1552112841680)]

<figcaption></figcaption>

在灰度圖上,部分色彩是介於白色跟黑色之間,所以通過設置閾值的方法,把這些中間色彩全部轉換成黑色跟白色;

ok,扯遠了,上面把驗證碼二值圖後是長這樣的:

[圖片上傳失敗...(image-61abbe-1552112841680)]

<figcaption></figcaption>

而校驗結果:

[圖片上傳失敗...(image-4b528-1552112841680)]

<figcaption></figcaption>

good,有所變化, 至少不是MEEE了,那我們繼續調,調到一個合適的值;
調了半天,jb放棄了,原因是這個8,不管怎麼調都調不到一個合適的值,一直在S、R、B之間徘徊;

JB換了個驗證碼:

[圖片上傳失敗...(image-458247-1552112841680)]

<figcaption></figcaption>

上面同樣的代碼,無修改,二值圖如下:

[圖片上傳失敗...(image-7e83e0-1552112841680)]

<figcaption></figcaption>

校驗結果:

[圖片上傳失敗...(image-94537a-1552112841680)]

<figcaption></figcaption>

oh year,這個能校驗出來了~

還記得我們一開始那個微博驗證碼嗎?我們也來試試,處理後的驗證碼是這樣的~

[圖片上傳失敗...(image-be6724-1552112841680)]

<figcaption></figcaption>

結果校驗的時候,基本上都空,只有在138的時候會有一點點識別效果,但是壓根不搭邊;[圖片上傳失敗...(image-74a09c-1552112841680)]

<figcaption></figcaption>

對比了下,微博驗證碼跟上面能識別的驗證碼:

[圖片上傳失敗...(image-f677e4-1552112841680)]

<figcaption></figcaption>

[圖片上傳失敗...(image-27e8d9-1552112841680)]

<figcaption></figcaption>

能別識別的,是實心,而不能被識別的,是空心;
實心的好處在於,圖像處理後,黑白分明,但是空心在圖像處理後,由於線條本來就很細,處理後可能都識別不出來了;

6 中文情況如何?

更新於18.6.11
突然想起,上面安裝的時候有提及到安裝不同語言包,那如果要看看其他語言,怎麼搞?因此就補充這點了~

先上圖~

[圖片上傳失敗...(image-6609fb-1552112841680)]

<figcaption></figcaption>

直接上代碼:

import tesserocr
from PIL import Image

image = Image.open("juejin.jpg")
result = tesserocr.image_to_text(image, lang='chi_sim')
print(result)
複製代碼

因爲默認是英文,所以英文不需要指定lang,但中文就需要啦,chi_sim就是簡體中文了;

[圖片上傳失敗...(image-f74b26-1552112841680)]

<figcaption></figcaption>

從輸出的結果來看,小冊那估計有個sale,不然估計開源庫也能匹配出來~
但依然可以看出,中文也不是很精準~

這裏說明下,中午不需要置灰跟二值哈,不然顏色加深了,估計更難辨別了~

7 小結

本章學習了tesserocr及tesseract的環境搭建,以及如何對圖形驗證碼進行噪音處理,並且講解灰色圖跟二值圖的概念;

作者:jb
鏈接:https://juejin.im/post/5b1b3cd26fb9a01e700ffe5b
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章