web拼图滑块验证

在这里插入图片描述

整体思路:
思路一:找到拼图的原图和有缺口的图片进行对比(无原图不能用此方法)
思路二:找到带缺口的图片和滑块 进行边界匹配(pip install opencv-python)(本次用的思路二解决问题)
在这里插入图片描述
background_img.png
在这里插入图片描述
slide_pic.png
在这里插入图片描述

from selenium import webdriver
import os
import re
from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
from six import BytesIO
import time
from selenium.webdriver import ActionChains
import requests
import cv2

baodian_url = "https://XXXXXXX"
name = "XXXX"
passworld = "XXXX"
n = 4  ##1力学院
moudle = 9 #模块
count = 74 #总数
progectPath = os.path.split(os.path.split(__file__)[0])[0]
print (progectPath)

def login(url,name,password):
    driver = webdriver.Chrome()
    driver.get(url)
    driver.refresh()
    driver.maximize_window()
    time.sleep(2)
    driver.find_element_by_id("username").send_keys(name)
    time.sleep(2)
    passwordInput = driver.find_elements_by_xpath("//*[@id='encryptPassword']")
    passwordInput[0].send_keys(password)
    path_image = "//*[@id='verifyCode']"
    path_slide = "captcha_sncaptcha_button"
    check1 = is_element_exit(driver, "//*[@id='imgCode']", 'xpath')  #图片验证
    check2 = is_element_exit(driver,path_slide,'id') #滑块验证
    if check1:
        """  图片验证 """
        print("输入图片验证码:")
        img = input("input:")   #也可以下载图片进行解析,这里为了简洁用手动输入方式
        print("code:", img)
        driver.find_element_by_xpath(path_image).send_keys(img)
        passwordInput = driver.find_elements_by_xpath("//*[@id='encryptPassword']")
        passwordInput[0].send_keys(password)
        login = driver.find_elements_by_xpath("//*[@id='Logon']/div[4]/input")
        login[0].click()
    elif check2:
        print ("图片滑块拼图")
        driver.find_element_by_id("captcha_sncaptcha_button").click()
        driver = slipe_main(driver)   #调用滑块验证主方法1
        time.sleep(2)
        driver.find_element_by_css_selector(".submit-btn-able").click()
    else:
        print ("请补充登陆验证场景")
        return driver
    return  driver

方法1:调用滑块验证

def  slipe_main(driver):
    path= "E:\\autofile\\picture"
    slice_img_label = driver.find_element_by_css_selector('div.tobe-obfuscate-image-wrap-box') #找到拼图
    time.sleep(1)
    src = driver.find_element_by_css_selector('img.tobe-obfuscate-image-fragment').get_attribute('src') #找到滑块src原图
    slide_pic = requests.get(src)
    request_image_save(slide_pic,path,'slide_pic.png') #调用request下载滑块图片后保存到文件方法2
    time.sleep(1)
    driver.execute_script("document.getElementsByClassName('tobe-obfuscate-image-fragment')[0].style['display'] = 'none'") #将滑块隐藏
    position =get_location(slice_img_label) #获取拼图对角线的位置,视口位置,即图片在整个浏览器中的左顶点位置和右下角的位置见方法3
    screenshot = get_screenshot(driver) #截取整个浏览器图片见方法4
    position_scale = get_position_scale(driver, screenshot) #获取截取图片的宽高,和浏览器宽高的比例 见方法5
    background_img = get_slideimg_screenshot(screenshot, position, position_scale)  # 截取有缺口的滑动验证图片 见方法6
    Image_save(background_img,path,"background_img.png") #保存截取的图片 见方法7
    path_slide_pic = "E:\\autofile\\picture\\slide_pic.png"
    path_background_img = "E:\\autofile\\picture\\background_img.png"
    location = detect_displacement(path_slide_pic,path_background_img) #找缺口坐标见方法8
    driver.execute_script("document.getElementsByClassName('tobe-obfuscate-image-fragment')[0].style['display'] = 'block'")  # 将拼图小块展示
    slider = driver.find_element_by_css_selector('img.slider-icon')
    top_left = int(location[0])
    tracks = get_track(top_left)  #模拟滑块距离见方法9
    driver = move_to_gap(driver,slider,tracks)#滑动滑块见方法10
    return driver

方法2:调用requests下载图片后保存到文件

def request_image_save(respond,path,name):
    pic_path = os.path.join(path,name)
    with open(pic_path,'wb') as f:
        f.write(respond.content)

方法3:获取拼图对角线的位置,视口位置,即图片在整个浏览器中的左顶点位置和右下角的位置

def get_location(img_lable):
    location = img_lable.location  #获取的是视口坐标即相对于浏览器的左顶点为原点
    size = img_lable.size  #返回图片的宽和高
    top,bottom,left,right = location['y'],location['y']+size['height'],location['x'],location['x']+size['width']
    print("top:{},bottom:{},left:{},right:{}".format(top,bottom,left,right))
    return (left,top,right,bottom)

方法4:截取整个浏览器图片

def get_screenshot(driver):
    """获取整个浏览器的截图,并从内存中进行读取"""
    screenshot=driver.get_screenshot_as_png()
    print("浏览器size",driver.get_window_size())
    print("screenshot",type(screenshot))
    f = BytesIO()  #用于读写内存,通过二进制,str格式的  要用StringIO方法
    f.write(screenshot)
    screenshot = Image.open(f)
    print ("获取浏览器图片screenshot",screenshot.size)
    return screenshot

方法5:获取截取图片的宽高,和浏览器宽高的比例

def get_position_scale(driver, screen_shot):
    """通过对比截图和浏览器宽高的大小,算出换算比例。由于截图是有浏览器的边缘的拖拽条,所以浏览器的宽度+17px"""
    height = driver.execute_script('return document.documentElement.clientHeight')
    width = driver.execute_script('return document.documentElement.clientWidth')
    x_scale = screen_shot.size[0] / (width + 17)
    y_scale = screen_shot.size[1] / (height)
    return (x_scale, y_scale)

方法6:截取有缺口的滑动验证图片

def get_slideimg_screenshot(screenshot, position, scale):
    x_scale, y_scale = scale
    position = [position[0] * x_scale, position[1] * y_scale, position[2] * x_scale, position[3] * y_scale]
    return  screenshot.crop(position)

方法7:保存截取的图片

def Image_save (image,path,name):
    path = os.path.join(path, name)
    image.save(path)

方法8:找缺口坐标

def detect_displacement(path_slide_pic,path_background_img):
    slide = cv2.imread(path_slide_pic,0)  #0灰度模式读取图片
    bacground = cv2.imread(path_background_img,0) #0灰度模式读取图片
    res = cv2.matchTemplate(_tran_canny(slide),_tran_canny(bacground),cv2.TM_CCOEFF_NORMED) #寻找最佳匹配
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) #最小值,最大值,并得到最小值, 最大值的索引
    print("min_val, max_val, min_loc, max_loc",(min_val, max_val, min_loc, max_loc))
    top_left = max_loc[0]  # 横坐标
    print ("top_left")
    # 展示圈出来的区域
    x, y = max_loc  # 获取x,y位置坐标
    print ("x,y",(x,y))
    w, h = slide.shape[::-1]  # 宽高
    cv2.rectangle(bacground, (x, y), (x + w, y + h), (7, 249, 151), 2)
    show(bacground)
    return max_loc

方法9:模拟滑块距离

def get_track(distance):
   """
   根据偏移量获取移动轨迹
   :param distance: 偏移量
   :return: 移动轨迹
   """
   # 移动轨迹
   track = []
   # 当前位移
   current = 0
   # 减速阈值
   mid = distance * 4 / 5
   # 计算间隔
   t = 0.2
   # 初速度
   v = 0

   while current < distance:
       if current < mid:
           # 加速度为正 2
           a = 4
       else:
           # 加速度为负 3
           a = -3
       # 初速度 v0
       v0 = v
       # 当前速度 v = v0 + at
       v = v0 + a * t
       # 移动距离 x = v0t + 1/2 * a * t^2
       move = v0 * t + 1 / 2 * a * t * t
       # 当前位移
       current += move
       # 加入轨迹
       track.append(round(move))
   return track

方法10:滑动滑块

def move_to_gap(driver,slider, tracks):
   """
   拖动滑块到缺口处
   :param slider: 滑块
   :param tracks: 轨迹
   :return:
   """
   ActionChains(driver).click_and_hold(slider).perform()
   for x in tracks:
       ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()
   time.sleep(0.5)
   ActionChains(driver).release().perform()
   return  driver

其他调用方法

def show(name):
    """展示图片"""
    cv2.imshow('show',name)  #展示图片,第一个参数图片窗口名称,第二个参数为图片
    cv2.waitKey(0)  #等待键盘输入0为无限等地
    cv2.destroyAllWindows()  #销毁所有窗口

def _tran_canny(image):
    image =cv2.GaussianBlur(image,(1,1),0)  #对图片进行降噪模糊平滑处理
    show(image)
    return cv2.Canny(image,10,100)  #边缘检测

def is_element_exit(driver, path,menthod):
        print("**********************开始检测元素在不在*****************")
        print(menthod)
        try:
                if menthod == 'xpath':
                        print("xpath")
                        driver.find_element_by_xpath(path)
                        print ("元素存在")
                        return True
                elif menthod == 'id':
                        print("id")
                        driver.find_element_by_id(path)
                        print("元素存在")
                        return True

        except Exception as e:
                print(e)
                print ("元素不存在返回False")
                return False
        else:
                return True

def ques(driver,N,moudle):
    driver.find_elements_by_xpath("//*[@id='app']/div/div/div[2]/div/img")[0].click()
    time.sleep(2)
    route = ("//*[@id='app']/div/div/div[3]/ul/li[%s]" % N)
    print(route)
    driver.find_elements_by_xpath(route)[0].click()  
    time.sleep(2)
    driver.find_elements_by_xpath("*//div[3]/article/div[1]/div[2]/div[1]/img")[0].click()
    moudle_route = ("//*[@id='app']/div/div[2]/div/span[%s]" % moudle)
    print (moudle_route)
    time.sleep(2)
    driver.find_elements_by_xpath(moudle_route)[0].click()  
    name = driver.find_elements_by_xpath(x_path())[0].text
    type(name)
    name = re.search(r'[\u4E00-\u9FA5]+',name).group()
    print(name)
    file = filep(progectPath,name)
    driver.find_elements_by_xpath(x_path())[0].click() 
    time.sleep(1)
    driver.find_elements_by_xpath("//*[@id='examType3']/div[4]/a[2]/span")[0].click() #进入背题模式
    for i in range (0,count):
        title =driver.find_elements_by_xpath("//*[@id='examQuestions']/pre")[0].text
        print (title)
        file.write(title)
        answer = driver.find_elements_by_xpath("//*[@id='examQuestions']/div[3]/div/p")[0].text
        file.write(answer)
        file.write('\n')
        print (answer)
        time.sleep(1)
        driver.find_elements_by_xpath("//*[@id='examType3']/div[6]/div[4]")[0].click()
        time.sleep(1)


def x_path():
    route = "*//div/div[5]/div[9]/ul/li/div[2]" 
    return route

def filep(ospath,name,type):
    print (ospath)
    reportpath = os.path.join(ospath, 'report')
    print (reportpath)
    if type == "image":
        return reportpath
    elif type == "txt":
        name = ("%s.txt" % name)
        print (name)
        titlename = os.path.join(reportpath,name)
        print (titlename)
        file = open(titlename,'w+')
        return file

driver = login(baodian_url,name,passworld)
ques(driver,n,moudle)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值