selenium模擬登錄京東滑塊驗證碼


由於京東的滑塊驗證碼只提供缺口圖片,所以我通過不斷刷新驗證碼發現其圖片庫總共只有10張,然后我提前將不同的缺口圖片進行合成已獲得完整的參照圖片並保存在指定的文件夾中以備用。之后的具體步驟為:

首先用selenium打開京東登錄頁面並點擊賬號密碼登錄方式,自動填充帳號密碼點擊登錄出現驗證碼,獲取驗證碼缺口圖片,相關代碼為:

url = 'https://passport.jd.com/new/login.aspx?'
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
browser = webdriver.Chrome(options=options, executable_path='chromedriver.exe')
wait = WebDriverWait(browser, 10)
browser.maximize_window()
browser.get(url)
time.sleep(2)
browser.find_element_by_class_name('login-tab-r').click()
time.sleep(1)
browser.find_element_by_id('loginname').send_keys(username)
browser.find_element_by_id('nloginpwd').send_keys(password)
browser.find_element_by_class_name('login-btn').click()
time.sleep(1)
img_url = browser.find_element_by_class_name('JDJRV-bigimg').find_element_by_css_selector('img').get_attribute('src')
image1_bytes = base64.urlsafe_b64decode(img_url.split(',')[-1])
image1 = Image.open(io.BytesIO(image1_bytes)).convert("RGB")

將缺口圖片與完整圖片集對比取得對應的完整圖片,簡單判斷方法為定義一個值表示兩張圖片的像素點rgb數值之差的絕對值的總和,值越小相似性越高,如下:

for j in range(image.size[1]):
    for i in range(image.size[0]):
        delta = abs(pixel1[i, j][0] - pixel2[i, j][0]) + abs(pixel1[i, j][1] - pixel2[i, j][1]) + abs(
            pixel1[i, j][2] - pixel2[i, j][2])
        diff += delta

之后比較兩張圖片計算出缺口的位置,並拖動滑塊到缺口處完成驗證,這里比較困難的主要是軌跡方程,我用先加速后減速的方法試了好幾個,但是都沒什么效果,成功率超級低

完整代碼如下:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from PIL import Image
import time
import base64
import os
import io
import random


class Jingdong():
    def __init__(self, username, password):
        self.username = username
        self.password = password
        self.url = 'https://passport.jd.com/new/login.aspx?'
        self.options = webdriver.ChromeOptions()
        self.options.add_experimental_option('excludeSwitches', ['enable-automation'])
        self.browser = webdriver.Chrome(options=self.options, executable_path='D:\Program Files (x86)\chromedriver.exe')
        self.wait = WebDriverWait(self.browser, 10)
        self.browser.maximize_window()

    def open_browser(self):
        self.browser.get(self.url)
        time.sleep(2)
        self.browser.find_element_by_class_name('login-tab-r').click()
        time.sleep(1)
        self.browser.find_element_by_id('loginname').send_keys(self.username)
        self.browser.find_element_by_id('nloginpwd').send_keys(self.password)
        self.browser.find_element_by_class_name('login-btn').click()
        time.sleep(1)

    def get_img_url(self):
        # 獲取驗證碼缺口圖片的地址
        img_url = self.browser.find_element_by_class_name('JDJRV-bigimg').find_element_by_css_selector(
            'img').get_attribute('src')
        return img_url

    @staticmethod
    def get_image(image1):
        # 將驗證碼的缺口圖片與已有文件夾中的完整圖片進行比較以取得其對應的完整圖片
        difference = 0
        image_ = image1
        size = image1.size
        images = os.listdir('./img2')
        pixel1 = image1.load()
        for image in images:
            image = Image.open(f'./img2/{image}')
            pixel2 = image.load()
            diff = 0
            for j in range(size[1]):
                for i in range(size[0]):
                    delta = abs(pixel1[i, j][0] - pixel2[i, j][0]) + abs(pixel1[i, j][1] - pixel2[i, j][1]) + abs(
                        pixel1[i, j][2] - pixel2[i, j][2])
                    diff += delta
            if difference == 0:
                difference = diff
                image_ = image
            elif difference > diff:
                difference = diff
                image_ = image
        return image_

    @staticmethod
    def is_pixel_equal(image1, image2, x, y):
        # 判斷兩張圖片相同坐標的rgb數值是否近似
        pixel1 = image1.load()[x, y]
        pixel2 = image2.load()[x, y]
        threshold = 5
        if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
                pixel1[2] - pixel2[2]) < threshold:
            return True
        else:
            return False

    def get_gap(self):
        # 返回驗證碼缺口的距離
        left = 60
        img_url = self.get_img_url()
        image1_bytes = base64.urlsafe_b64decode(img_url.split(',')[-1])
        image1 = Image.open(io.BytesIO(image1_bytes)).convert("RGB")
        image2 = self.get_image(image1)
        if not image2:
            self.browser.find_element_by_class_name('JDJRV-img-refresh').click()
            time.sleep(1)
            self.get_gap()
        else:
            for i in range(left, image1.size[0]):
                for j in range(image1.size[1]):
                    if not self.is_pixel_equal(image1, image2, i, j):
                        return i
        return left

    @staticmethod
    def get_track(distance):
        # 軌跡生成
        track = []
        track_ = []
        delta_t = 0.1
        for i in range(1, 21):
            delta_dis = 1 / 12 * distance * (delta_t * i) ** 3 - 1 / 12 * distance * (delta_t * (i - 1)) ** 3
            track.append(round(delta_dis))
        for i in range(1, 10):
            delta_dis = 1 / 3 * distance * (i * delta_t) ** 3 - 1 / 3 * distance * ((i - 1) * delta_t) ** 3
            track_.append(round(delta_dis))
        track.append(0)
        while len(track_) > 0:
            track.append(track_.pop())
        track[20] = distance - sum(track)
        return track

    def verify(self):
        # 滑動滑塊進行驗證
        distince = self.get_gap()
        if distince > 180:
            distince = distince - abs(180-distince)/180*40 - 40
        else:
            distince = distince + abs(180-distince)/180*40 - 40
        tracks = self.get_track(distince)
        slider = self.browser.find_element_by_class_name('JDJRV-slide-btn')
        ActionChains(self.browser).click_and_hold(slider).perform()
        for axis in tracks:
            yoffset = random.randint(-2, 2)
            ActionChains(self.browser).move_by_offset(xoffset=axis, yoffset=yoffset).perform()
        time.sleep(0.5)
        ActionChains(self.browser).release().perform()
        time.sleep(3)
        if self.browser.current_url != self.url:
            print("登錄成功")
            time.sleep(3)
            self.browser.close()
        else:
            self.verify()

    def main(self):
        self.open_browser()
        time.sleep(1)
        self.verify()

if __name__ == '__main__':
    jingdong = Jingdong('username', 'password')
    jingdong.main()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM