滑块验证码自动登录的实现

滑块验证似乎很神秘,其实也简单,核心点在于如何模拟鼠标移动的轨迹更象人移动的轨迹,你模拟得越象就越容易成功。

主要步骤:

1)保存背景图片code.png

2)灰度code2.png、二值化code3.png、去噪code4.png背景图片

3)统计计算缺口的位置

4)模拟鼠标移动轨迹

5)拖动模块到指定位置

废话少说,直接上代码。

import time
import datetime
import random
import requests
import matplotlib.pyplot as plt
 
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.select import Select
from io import BytesIO
from PIL import Image
from collections import Counter
import pymongo
import os
import pandas as pd
path="默认下载保存路径"
 
# 获取JD登陆页面
url = "登录页面"
valid_url = "登录成功页面"
# 启动调试程序
browser = webdriver.Chrome(options=options,executable_path="d:\chromedriver.exe")

# 二值化,将所有的点位,全部换成0或255
def bi_value(w, h, image):
    tem = 0
    for x in range(w):
        for y in range(h):
            tem += image.getpixel((x, y))
    pixel_ave = tem / w / h * 0.7
    for x in range(w):
        for y in range(h):
            p = image.getpixel((x, y))
            if p < pixel_ave:
                image.putpixel((x, y), 0)
            else:
                image.putpixel((x, y), 255)
    return image

# 降噪处理
def reduce_noise(image):
    w, h = image.size
    for x in range(0, 40):  # 处理最左边
        for y in range(h):
            image2 = image.putpixel((x, y), 255)
    return image

# 处理图片,灰度化与二值化、降噪
def get_target_picture():
    im = Image.open("code.png")
    #print("缺口背景图片")
    im2 = im.convert("L")
    im2.save("code2.png")
    w, h = im2.size
    im3 = bi_value(w, h, im2)
    im3.save("code3.png")
    im4 = reduce_noise(im3)
    im4.save("code4.png")
    #print("二值化除噪图片")
    return im4

# 计算距离
def get_distance(image):
    w, h = image.size
    ls = []
    for i in range(31, w - 31):  # 图片最左边放置滑块,缺口坐标x不可能小于31
        for j in range(10, h):
            if image.getpixel((i, j)) < 100:
                count = 0
                for k in range(i, i + 31):
                    if image.getpixel((k, j)) < 100:
                        count += 1
                    else:
                        break
                if count > 27: ls.append(i)
    return Counter(ls).most_common(1)[0][0]
# 设计拖动轨迹
def get_tracks(distance):
        """
        根据偏移量获取移动轨迹
        这里把距离加长,拉过头
        :param distance: 偏移量
        :return: 移动轨迹
        """
        print("需要拖动距离:",distance)
        # 加长距离,拉过头
        distance += 6
        # 移动轨迹
        tracks = []
        # 当前位移
        current = 0
        # 变速阈值
        if distance > 100:
            mid1 = (distance * 1 / 3)
            mid2 = (distance * 7 / 8)
        else:
            mid1 = (distance * 1 / 2)
            mid2 = (distance * 5 / 6)
        
        # 间隔时间
        t = 0.3
        # 初速度
        v = 3
        while current < distance:
            if current < mid1:
                a = random.randint(3, 5)
            elif current < mid2:
                a = random.randint(0, 2)
            else:
                a = - random.randint(9, 12)
            v0 = v
            v = v0 + a * t
            move = v0 * t + 1 / 2 * a * t * t
            current += move
            tracks.append(round(move))
        bais = distance-sum(tracks)
        if bais!=0:
            tracks.append(bais)
        print("正向拖动轨迹:",tracks)
        return tracks

def drog_slider(tracks):  # 拖动滑块
    # 定位滑块
    ele = browser.find_element_by_xpath('.//div[@class="JDJRV-slide-inner JDJRV-slide-btn"]')
    # 设计拖动动作链(点击且不放)
    ActionChains(browser).move_to_element(ele).click_and_hold(ele).perform()
    # 根据设计的轨迹,实现滑块拖动
    for i in tracks:
        ActionChains(browser).move_by_offset(i, random.uniform(-5,5)).perform()
    # 睡眠0.25秒,伪装成人的判断过程
    time.sleep(1)
    for x in [-3, -2, -2, -1]:
            ActionChains(browser).move_by_offset(x, random.uniform(-5,5)).perform()
    # 释放滑块,类似于松开鼠标
    ActionChains(browser).release().perform()
    time.sleep(3)
    print("实际拖动距离:",sum(tracks)-6)
    
def login():
    username = ""
    password = ""
    browser.maximize_window()
    browser.get(url)
    time.sleep(2)
 
    # 找到账户登录并且点击
    login_ele = browser.find_element_by_xpath("//div[@class='login-tab login-tab-r']")
    login_ele.click()
    time.sleep(2)
 
    # 输入用户名和密码
    username_ele = browser.find_element_by_xpath("//input[@id='loginname']")
    password_ele = browser.find_element_by_xpath("//input[@id='nloginpwd']")
    time.sleep(1)
    username_ele.send_keys(username)
    time.sleep(1)
    password_ele.send_keys(password)
    time.sleep(1)
    # 点击提交,进入滑动验证码页面
    submit_btn = browser.find_element_by_xpath("//a[@id='loginsubmit']")
    submit_btn.click()
    time.sleep(1)
    
def save_bg_picture():
    # 通过修改JS隐藏滑块并截屏获取验证码图片,保存至当前目录,名为code.png
    js = 'document.getElementsByClassName("JDJRV-smallimg")[0].style.display="none"'
    browser.execute_script(js)
    code_path = 'code.png'
    browser.find_element_by_xpath('.//div[@class="JDJRV-bigimg"]').screenshot(code_path)
    time.sleep(1)
    # 停止1秒后恢复JS改动,回到页面最初状态
    js = 'document.getElementsByClassName("JDJRV-smallimg")[0].style.display="block"'
    browser.execute_script(js)
 
 
def try_drog_slider():  # 再次尝试
    print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),"尝试登录")
    save_bg_picture()
    image = get_target_picture()
    distance = get_distance(image)
    tracks = get_tracks(distance)
    drog_slider(tracks)
    
def try_login():
    print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),"尝试登录")
    login()
    save_bg_picture()
    image = get_target_picture()
    distance = get_distance(image)
    tracks = get_tracks(distance)
    drog_slider(tracks)
    succ = False
    try_times = 1
    while try_times<3:
        if browser.current_url == valid_url:
            succ = True
            print("尝试",try_times,"次登录成功!")
            break
        else:
            try_drog_slider()
            try_times+=1
            print(browser.current_url)
            if browser.current_url == valid_url:
                succ = True
                print("尝试",try_times,"次登录成功!")
                break
        
    if succ == False:
        print("尝试",try_times,"次登录失败!")
        browser.quit()
    return succ

if try_login() == True:
    print("可以开始干点正事了。")

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值