1. 程式人生 > >爬蟲驗證碼很難嗎?自動識別驗證碼程式瞭解一下?

爬蟲驗證碼很難嗎?自動識別驗證碼程式瞭解一下?

首先,我對驗證碼做了初步的觀察分析。總結如下:

驗證碼中的字元位數始終為6位,並且是灰度影象;

字元之間的間隔看起來始終保持相同的間隔;

每個字元都是完全定義的;

影象有許多雜散的暗畫素,以及穿過影象的線條

我決定下載一個圖片驗證碼,並藉助 這款工具 以二進位制視覺化影象(0表示黑色,1表示白色畫素)。

我的觀察是正確的 – 影象尺寸為45×180,每個字元被分配一個30畫素的空間來擬合,從而使它們均勻間隔。

我將其包裝在一個迴圈中,寫了一個簡單的指令碼,從該站點獲取500個驗證碼影象,並將所有裁剪後的字元儲存到一個資料夾中。

第三次觀察 – 每個字元都有明確的定義。為了“清理”影象中的裁剪字元(刪除不必要的線和點),我使用了以下方法。

字元中的所有畫素都是純黑色(0)。我用了一個簡單的邏輯 – 如果它不是完全黑色的,就視為白色。因此,對於值大於0的每個畫素,將其重新分配為255。使用load()函式將影象轉換為45×180矩陣,然後對其進行處理。

pixel_matrix = cropped_image.load()
for col in range(0, cropped_image.height):
 for row in range(0, cropped_image.width):
 if pixel_matrix[row, col] != 0:
 pixel_matrix[row, col] = 255
image.save("thresholded_image.png"
)

為了更加清晰,我將程式碼應用至原始影象上。

原圖:

處理後:

可以看到處理後的影象中的非純黑畫素都已被移除,其中包括穿插影象的線條。

直到專案完成後,我才知道上述方法被稱為影象處理中的閾值處理。

第四次觀察 – 影象中有許多雜散畫素。

迴圈遍歷影象矩陣,如果相鄰畫素為白色,與相鄰畫素相對的畫素也為白色,且中心畫素為黑色的,則使中心畫素為白色。

for column in range(1, image.height - 1):
 for row in range(1, image.width - 1):
 if pixel_matrix[row, column] == 0 \
 and pixel_matrix[row
, column - 1] == 255 and pixel_matrix[row, column + 1] == 255 : pixel_matrix[row, column] = 255 if pixel_matrix[row, column] == 0 \ and pixel_matrix[row - 1, column] == 255 and pixel_matrix[row + 1, column] == 255: pixel_matrix[row, column] = 255

一個將按照字元排序的相似影象分組(約束條件:暗畫素數量,相似度>= 90 – 95 %)

一個從每個分組字元中獲得最佳影象

因此現在已生成了庫影象。將它們轉換為畫素矩陣,並將“點陣圖”儲存為JSON檔案。

最後,這是解決任何新的驗證碼影象的演算法。

使用相同的演算法減少新影象中不必要的干擾

對於新驗證碼影象中的每個字元,通過我生成的JSON點陣圖強制執行。根據對應的暗畫素匹配來計算相似度。

這意味著,如果一個畫素為暗畫素,在影象中的位置為(4,8),並且如果該畫素在我們的骨架影象/點陣圖中的相同位置處為暗畫素,則計數值會遞增1。

該計數與骨架影象中暗畫素的數量相比,用於計算百分比匹配。

選擇匹配率最高的字元。

import json
 characters = "123456789abcdefghijklmnpqrstuvwxyz"
 captcha = ""
 with open("bitmaps.json", "r") as f:
 bitmap = json.load(f)
 for j in range(image.width/6, image.width + 1, image.width/6):
 character_image = image.crop((j - 30, 12, j, 44))
 character_matrix = character_image.load()
 matches = {}
 for char in characters:
 match = 0
 black = 0
 bitmap_matrix = bitmap[char]
 for y in range(0, 32):
 for x in range(0, 30):
 if character_matrix[x, y] == bitmap_matrix[y][x] and bitmap_matrix[y][x] == 0:
 match += 1
 if bitmap_matrix[y][x] == 0:
 black += 1
 perc = float(match) / float(black)
 matches.update({perc: char[0].upper()})
 try:
 captcha += matches[max(matches.keys())]
 except ValueError:
 print("failed captcha")
 captcha += "0"
 print captcha

最終得到的結果如下:

可以看到驗證碼被成功識別為Z5M3MQ!

總結

這個專案對於我本人而言,也是一次非常好的學習經歷。我還開發了一個 Chrome外掛,目前有1800+的使用者,歡迎大家安裝使用!此外,如果你有任何的意見和建議也歡迎向我提出。以上的程式碼我已託管在GitHub,你可以 在這裡找到 。

歡迎加入我的千人交流答疑群:125240963