滑動驗證碼破解—python—以某東網站為例
阿新 • • 發佈:2018-12-02
目前很多網站的登入都需要採用驗證碼的方式進行登入,這一定程度上增大的爬蟲的難度。以極驗驗證碼為例,這家公司的驗證碼在國內的使用者很多,在業界也很出名。
出於好奇心和學術研究的目的,我嘗試了破解某東的驗證碼,也查了很多別人的部落格和資料,最後算是成功了吧。
一、破解過程分析
1. 首先我們到將使用者名稱和密碼輸入,點選登入
2.接下來就是重點了,網站會有機率彈出一個拼圖驗證碼,如果你頻繁的登入,就不會出現驗證碼。
3.接下來我們就要分析一下了,怎麼完成拼圖呢?
我選擇的方式是,先拿到缺口圖片和小塊圖片,進行拼接,得到小塊的位置,就可以確定滑塊的移動距離(實際上還需要檢視小塊圖片左側的距離),然後拖動滑塊,按照一定的軌跡進行移動,最後完成拼圖。這就是拼圖的過程。二、程式碼分析
1.獲取圖片,下載到本地
檢視網頁的程式碼
通過網頁原始碼我們發現,圖片是一base64的編碼方式顯示在網頁中的,當然其他的網站可能是圖片連結,這種情況我們需要先將其解碼,然後寫入檔案中就好了。
下載圖片的程式碼
def pic_download(url,type):
url = url
root = "../img_db/"
# path = root + str(time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()))+'.png'
path = root + type + '.png'
try:
if not os.path.exists(root):
os.mkdir(root)
if os.path.exists(path):
os.remove(path)
#如果圖片是url的格式
# r = requests.get(url)
# r.raise_for_status()
#如果圖片是base64編碼的
data=url.split(',')[1]
img=base64.b64decode( data)
# 使用with語句可以不用自己手動關閉已經開啟的檔案流
with open(path, "wb") as f: # 開始寫檔案,wb代表寫二進位制檔案
f.write(img)
print(f.name)
print("下載完成")
return f.name
except Exception as e:
print("獲取失敗!" + str(e))
2.合併圖片,找到位置
這裡我們使用了opencv的包,這個包在影象處理方便時非常強大的,可以做人臉識別等,功能十分強大,膜拜大牛。def get_distance(small_url, big_url):
# 引用上面的圖片下載
otemp = pic_download(small_url, 'small')
time.sleep(2)
# 引用上面的圖片下載
oblk = pic_download(big_url, 'big')
# # 計算拼圖還原距離
target = cv2.imread(otemp, 0)
template = cv2.imread(oblk, 0)
w, h = target.shape[::-1]
temp = 'temp.jpg'
targ = 'targ.jpg'
cv2.imwrite(temp, template)
cv2.imwrite(targ, target)
target = cv2.imread(targ)
target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
target = abs(255 - target)
cv2.imwrite(targ, target)
target = cv2.imread(targ)
template = cv2.imread(temp)
result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
x, y = np.unravel_index(result.argmax(), result.shape)
# 缺口位置
print((y, x, y + w, x + h))
# 呼叫PIL Image 做測試
image = Im.open(oblk)
xy = (y + 20, x + 20, y + w - 20, x + h - 20)
# 切割
imagecrop = image.crop(xy)
# 儲存切割的缺口
imagecrop.save("../img_db/new_image.png")
return y
這裡我們需要注意一點,我們計算出了缺口的位置,但是頁面顯示的圖片大小是通過css佈局的,所以和我們下載的圖片或寫入的圖片大寫是不一樣的,所以我們在移動的時候需要計算一個比例。
3.設計移動軌跡,移動滑塊
def move_mouse(browser,distance,element):
has_gone_dist=0
remaining_dist = distance
# distance += randint(-10, 10)
# 按下滑鼠左鍵
ActionChains(browser).click_and_hold(element).perform()
time.sleep(0.5)
while remaining_dist > 0:
ratio = remaining_dist / distance
if ratio < 0.1:
# 開始階段移動較慢
span = random.randint(3, 5)
elif ratio > 0.9:
# 結束階段移動較慢
span = random.randint(5, 8)
else:
# 中間部分移動快
span = random.randint(15, 20)
ActionChains(browser).move_by_offset(span, random.randint(-5, 5)).perform()
remaining_dist -= span
has_gone_dist += span
time.sleep(random.randint(5, 20) / 100)
ActionChains(browser).move_by_offset(remaining_dist, random.randint(-5, 5)).perform()
ActionChains(browser).release(on_element=element).perform()
極驗的驗證碼會識別我們拖動的過程,分析我們的移動軌跡,但是雖然我們的移動軌跡是模擬人,先緩慢後加速最後減速的過程。但是這樣還是不夠的,我們還需要多設計幾個移動軌跡,根據我的測試經驗得出的結論。
結語
下面是要導的包,還需要把對應瀏覽器的webdriver安裝的python直譯器的路徑裡,這裡就不細講了,有問題可以留言交流。import os
import random
import time
import base64
# import requests
import cv2
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import numpy as np
from PIL import Image as Im
完整的程式碼:https://github.com/onlyonedaniel/onlyone/blob/master/jd_test.py
轉載請標明出處,歡迎留言交流