1. 程式人生 > >滑動驗證碼破解—python—以某東網站為例

滑動驗證碼破解—python—以某東網站為例

目前很多網站的登入都需要採用驗證碼的方式進行登入,這一定程度上增大的爬蟲的難度。以極驗驗證碼為例,這家公司的驗證碼在國內的使用者很多,在業界也很出名。

在這裡插入圖片描述
出於好奇心和學術研究的目的,我嘗試了破解某東的驗證碼,也查了很多別人的部落格和資料,最後算是成功了吧。

一、破解過程分析

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
轉載請標明出處,歡迎留言交流