JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

jb發表於2018-06-09

前言

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
先來看看,目前遇到的驗證碼種類有哪些?

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

2)滑動驗證碼

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

3)點觸驗證碼

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

1 圖形驗證碼

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

某乎連結:https://www.zhihu.com/signup?next=%2F
開啟後預設是在註冊頁面,點選下登陸按鈕,如果還是沒有驗證碼,重新整理幾次網頁就行了;

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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;

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

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

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

pip3 install tesserocr install
複製程式碼

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

conda install -c simonflueckiger tesserocr
複製程式碼

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

最終就安裝上tesserocr啦~

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

對了,如果有同學不知道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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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)
複製程式碼

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
OK,看到是有資料了,不過輸出的是MEEE,跟驗證碼的ME8E還是有點不一樣;

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

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

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

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

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
結果也跟上面的一樣,但網上不建議這麼用,原因是據說這種識別效果不如上一種的好;

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

tesseract 圖片路徑 output 
複製程式碼

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
leptonica 在解析時沒有檢測到任何dpi;

5 驗證碼處理

網上找了下資訊,比如這張驗證碼:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

又比如微博這張:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
可能是字型位置,跟圖案等因素干擾了圖示的識別;

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

轉灰度處理: 利用Image物件的convert()方法引數傳入L,即可將圖片轉成為灰度影像:

from PIL import Image

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
圖片成功轉灰了;此時我們再校驗一下,發現校驗還是MEEE,失敗;

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

import tesserocr
from PIL import Image

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
這個一看,比上面更模糊了,理所當然的,校驗結果會錯的更加離譜:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

二值化的閾值是可以指定的,上面的方法採用的是預設閾值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是白色,這樣做,就可以把一個灰度圖完全轉換二值化圖;
可能還是懵逼,直接貼圖:
原圖

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

灰度圖:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

二值圖:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

而校驗結果:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB換了個驗證碼:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

校驗結果:

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
結果校驗的時候,基本上都空,只有在138的時候會有一點點識別效果,但是壓根不搭邊;

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr
能別識別的,是實心,而不能被識別的,是空心;
實心的好處在於,影像處理後,黑白分明,但是空心在影像處理後,由於線條本來就很細,處理後可能都識別不出來了;

6 中文情況如何?

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

先上圖~

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

直接上程式碼:

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就是簡體中文了;

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

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

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

7 小結

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

8 疑難雜症

實際發現,tesserocr僅能解決實心的驗證碼,對於空心的驗證碼,依然束手無策,那怎麼辦呢?
既然影像識別存在誤差,那我們就放棄這條路,而是通過其他的方式來獲取這個驗證碼;

比如直接找到生成這驗證碼的程式碼二次轉化獲取驗證碼,深度學習訓練機器識別;

下章預告:
如何獲取驗證碼的生成程式碼二次處理獲取驗證碼

18.6.11更新 上面的話題,留到下下章處理,下章介紹下收費的OCR~

謝謝大家~

JB的Python之旅-爬蟲篇-圖形驗證碼(1)-- tesserocr

相關文章