zl程序教程

您现在的位置是:首页 >  其他

当前栏目

017:Opencv+Selenium模拟QQ邮箱滑块操作

2023-03-15 22:06:53 时间

之前发了一个国航的滑块模拟操作,没有计算滑块到缺口的位置。 本篇则是用opencv+selenium来对QQ邮箱的滑块进行模拟测试。

QQ邮箱链接: https://mail.qq.com/

QQ邮箱这个登录机制,需要我们输入一个错误的账号或密码会有机会弹出滑块验证码,所以我下面就一直用错误的账号进行测试。 其实部分账号,或者说异地登录的QQ账号也都需要滑动解锁验证码才能继续登录。所以这个测试以后可能用的上。

首先是用selenium登录:

访问过来以后,看到的是一个如下图所示的页面。我们需要点击账号密码登录才能进行我们的模拟操作。

刚开始我直接用selenium获取ID点击账号登录,发现没什么作用。 后来仔细一看这是一个iframe框,我们直接是不能点击到的。 要进行frame切换。 selenium中有这样的操作:

driver.switch_to.frame("login_frame")        # login_frame是该登录窗口iframe的id

这样才能点击到。以供我们接下来的操作。

    driver.get('https://mail.qq.com')
    time.sleep(2)
    driver.switch_to.frame("login_frame")        # 切换frame。login_frame是该登录窗口id
    time.sleep(1)
    driver.find_element_by_id('switcher_plogin').click()           #点击账号密码登录
    time.sleep(1)
    username = '1234567{}@qq.com'.format(random.randint(0,99))     #随机获取一个账号
    driver.find_element_by_id("u").send_keys(username)             #输入账号
    time.sleep(1)																					
    driver.find_element_by_id("p").send_keys('wwwwwwwwwwwww')      #输入一个密码
    time.sleep(1)
    driver.find_element_by_id("login_button").click()              #点击登录
    time.sleep(1)

如果出现了这么个玩意,没有出现滑块。那你就再试一次=。=

正常情况出现滑块后:

开始进行缺口位置识别:

我这里使用的方法,是通过selenium中的xpath把图片的src获取到,然后下载下来保存到本地。再通过opencv来进行图像缺口检测。

那我们先获取两个图片(滑块和验证图)的src:

    src_big = driver.find_element_by_xpath('//div[@id="slideBgWrap"]/img').get_attribute('src')
    src_small = driver.find_element_by_xpath('//div[@id="slideBlockWrap"]/img').get_attribute('src')

然后保存到本地:

    img_big = requests.get(src_big).content
    img_small = requests.get(src_small).content
    with open('yanzhengtu.jpg','wb') as f:
        f.write(img_big)
    with open('huakuai.png','wb') as f:
        f.write(img_small)

开始识别图片缺口位置: 写一个shibie函数:

def shibie():
    otemp = 'huakuai.png'               #滑块
    oblk =  'yanzhengtu.jpg'                   # 验证图
    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)   #获取一个/组int类型的索引值在一个多维数组中的位置
    # 展示圈出来的区域
    cv2.rectangle(template, (y, x), (y + w, x + h), (7, 249, 151), 3)    #通过对角线画矩形
    # print(y)
    # show(template)
    return y

然后调用我们写好的识别函数: 返回保存在本地的图片中0左标到缺口位置的距离:y

我们本地图片的宽是 680 像素 而QQ邮箱给的验证图的宽为 280 像素

那我们移动的距离是: y = y/(680/280) 但是在浏览器上面显示的滑块起始位置不是为0的。

所以我们移动的距离应该是: y = (y+22.5)/(680/280)+k 当然可能存在有些许误差k,需要我们再观察并补充。

我们就可以使用selenium中的ActionChains来进行鼠标移动操作。

huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')
            action = ActionChains(driver)
            action.click_and_hold(huakuai).perform()
            y = (y+20)/(680/280)-27
		    try:
		        action.move_by_offset(y,0).perform()
		        time.sleep(0.5)
		        action.release(on_element=huakuai).perform()    #松开鼠标左键,完成操作
		        time.sleep(1)
		    except:
		        pass

测试结果:

因为这里发不了视频。我用gif图来演示下:

图质量太烂了、不过不影响看结果。现在已经能识别并正确拖动到位置了。

完整代码:

from selenium import webdriver
import cv2,numpy as np,random,requests,time
from selenium.webdriver import ActionChains

'''识别缺口位置、计算偏移值'''
def shibie():
    otemp = 'huakuai.png'               #滑块
    oblk =  'yanzhengtu.jpg'                   # 验证图
    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)  #获取一个/组int类型的索引值在一个多维数组中的位置
    # 展示圈出来的区域
    cv2.rectangle(template, (y, x), (y + w, x + h), (7, 249, 151), 3) #通过对角线画矩形
    # print(y)
    # show(template)
    return y


'''Selenium模拟登陆 获取滑块'''
def main():
    driver = webdriver.Chrome(executable_path=r'C:UserslenovoDesktopchromedriver_win32chromedriver.exe')
    driver.get('https://mail.qq.com')
    # driver.find_element_by_xpath('//div[@calss="bottom hide"]/a[@class="link"]').click()
    time.sleep(2)
    driver.switch_to.frame("login_frame")        # 切换frame。login_frame是该登录窗口iframe的id
    time.sleep(1)
    driver.find_element_by_id('switcher_plogin').click()
    time.sleep(1)
    username = '1234567{}@qq.com'.format(random.randint(0,99))
    driver.find_element_by_id("u").send_keys(username)
    time.sleep(1)
    driver.find_element_by_id("p").send_keys('wwwwwwwwwwwww')
    time.sleep(1)
    driver.find_element_by_id("login_button").click()
    time.sleep(1)
    try:
        driver.switch_to.frame("tcaptcha_iframe")
        time.sleep(1)
        if driver.find_element_by_id('slideBgWrap'):
            time.sleep(0.5)
            src_big = driver.find_element_by_xpath('//div[@id="slideBgWrap"]/img').get_attribute('src')
            src_small = driver.find_element_by_xpath('//div[@id="slideBlockWrap"]/img').get_attribute('src')
            img_big = requests.get(src_big).content
            img_small = requests.get(src_small).content
            with open('yanzhengtu.jpg','wb') as f:
                f.write(img_big)
            with open('huakuai.png','wb') as f:
                f.write(img_small)
            time.sleep(3)
            y = shibie()
            time.sleep(1)
            # print(y)
            huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')
            action = ActionChains(driver)
            action.click_and_hold(huakuai).perform()
            y = (y+20)/(680/280)-27
            try:
                action.move_by_offset(y,0).perform()
                time.sleep(0.5)
                action.release(on_element=huakuai).perform()       #松开鼠标左键,完成操作
                time.sleep(1)
            except:
                pass
    except:
        time.sleep(1)
        driver.close()
        main()
main()