很長一段時間沒寫文章了,今天來一篇,聊聊滑塊驗證碼。之前一段時間在研究下滑塊驗證碼相關的東西,拿騰訊的驗證碼來玩,使用Selenium來模擬滑動,這裏也就先不介紹Selenium 的基本用法來,主要來聊聊怎麼實現滑塊驗證碼的識別問題。
滑塊驗證碼可以說是目前使用最多,體驗相對比較好的驗證方式來,在反爬蟲上面也確實有比較好的效果,但爬蟲和反爬蟲,本身就是一對冤家,相互促進項目影響。廢話不多說,直接上滑塊驗證碼的乾貨吧。
一、目標
就拿騰訊的滑塊驗證碼來說吧,其他滑塊也比較類似,就這個:
先大概梳理一下這個特徵,點擊驗證,彈出這個滑塊驗證碼,用鼠標拖動到缺口陰影位置鬆手即可實現驗證。
邏輯比較簡單,目前要處理的核心問題就是怎麼找到這個陰影位置,因爲可能有不同的圖片而且圖片中缺口陰影的位置也不確定。
問題可以簡化爲:如何找到背景圖中缺口的準確位置
二、查找缺口陰影位置
定下了解決問題的目標,下一步就是查找當前的已知條件,看看已知條件能否找到突破口,目前我們可以確定的是,如果要用滑塊驗證碼,至少要有兩樣東西:
- 滑動的滑塊圖形,就是這個:
- 滑動要拼出的背景圖,就是這個:
這兩個傢伙是每個滑塊都有的東西,先從這兩個上面入手:
先試着處理下背景圖,這裏用python
來寫了:
from PIL import Image
if __name__ == "__main__":
Image.open('hycdn_1_1585354975542067968_0.jpeg').convert('L').save('cap4.jpg')
我們將這個背景圖片置成灰色圖片看看,現在是這個樣子:
現在這個背景圖沒有其他雜色了,再看這個缺口位置,顏色要更深一點,那接下來就處理下滑塊了,讓它儘量和這個缺口相似:
def convert(imgName, saveName):
im = Image.open(imgName)
im = im.convert('RGBA')
width = im.size[0]
height = im.size[1]
for h in range(0, height):
for w in range(0, width):
pixel = im.getpixel((w, h))
if pixel[0] > 0 and pixel[1] > 0 and pixel[2] > 0 and pixel[3] > 0:
im.putpixel((w, h), (0,0,0, 220))
elif pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0:
im.putpixel((w, h), (0, 0, 0, 220))
else:
pass
im.save(saveName)
convert('hycdn_2_1585354975542067968_0.png','cap2.png')
將整張滑塊圖進行像素調節,這個調節值是反覆試出來的,出來的效果是這樣:
這樣處理後,我們要做的其實就剩下最後一步了:從這個背景圖中找出和這個滑塊最相似的圖形並標記出來
這裏使用了一個開源庫aircv
,Github上地址是https://github.com/NetEaseGame/aircv
,大概使用方式是這個:
import aircv as ac
imsrc = ac.imread('youimage.png') # 原始圖像
imsch = ac.imread('searched.png') # 帶查找的部分
ac.find_template(imsrc, imsch)
#返回值
#{'confidence': 0.5522063970565796, 'result': (557, 214), 'rectangle': ((489, 146), (489, 282), (625, 146), (625, 282))}
# result: 查找到的點
# rectangle: 目標圖像周圍四個點的座標
# confidence: 查找圖片匹配成功的特徵點 除以 總的特徵點
從圖形中查找相似部分,詳細使用可以查看Github。
我們這樣處理一下:
imsrc = ac.imread('cap4.jpg')
imobj = ac.imread('cap2.png')
# find the match position
pos = ac.find_template(imsrc, imobj)
print pos
# {'confidence': 0.5522063970565796, 'result': (557, 214), 'rectangle': ((489, 146), (489, 282), (625, 146), (625, 282))}
color = (0, 255, 0)
line_width = 10
draw_rectangle(imsrc, pos['rectangle'][0], pos['rectangle'][-1], color, line_width)
用python-opencv2
繪製一下區域看看:
import cv2
def draw_rectangle(img, pos1, pos2, color, line_width):
cv2.rectangle(img, pos1, pos2, color, line_width)
cv2.imshow('objDetect', imsrc)
cv2.waitKey(0)
cv2.destroyAllWindows()
好啦,我們看下效果:
再試幾個看看: