selenium+opencv实现模拟登陆(滑块验证码)

很多网站登录登陆时都要用到滑块验证码,在某些场景例如使用爬虫爬取信息时常常受到阻碍,想着用opencv的模板匹配试试能不能实现模拟登陆。本来觉得网上资料多应该还蛮容易,但实际上手还是搞了蛮久,在这里记录一下整个流程,网站无所谓主要是要有滑动验证码:

环境

python 3.9, selenium和Opencv相关依赖,用于抓取图片的requests包,具体安装这里不多讲了,其中selenium用的火狐版本。

selenium登录网站

整体流程就是这个样子:访问网站->点击登录->输入账号密码->搞定滑块验证->登录网站,其中最大的难点是滑块验证码,但在此之前我们当然要先让selenium自动打开网站把账号密码输好,我们通过find_element()方法定位输入框之后执行操作,元素的各个属性F12就可以找到:

代码如下:

options = webdriver.FirefoxOptions()
driver = webdriver.Firefox(options=options)
driver.get('网址')
driver.find_element("link text", "登录").click()
name = driver.find_element("id", "name-input")
name.send_keys("账号######") # 输入账号
pw = driver.find_element("id", "password-input")
pw.send_keys("密码#########") # 输入密码
driver.find_element("id", "submit").click() # 提交

requests抓取验证码图片

为了做后续处理我们需要把滑块验证码相关图片抓到本地,网上关于滑块验证码这块很多都是用原图和有缺口的图对比来确定缺口位置的,但是我并没有找到原图,这里用到的是有缺口的背景图和滑块图,如下:

滑块图:

 有缺口的背景图:

这里爬图是selenium定位之后用requests包爬的,注意验证码和登陆界面不在一个iframe里,selenium记得切到对应iframe才能定位到图片,代码如下:

driver.switch_to.frame('tcaptcha_iframe')
 # 切换iframe
img = driver.find_element("id", "slideBg").get_attribute('src')
headers = {
    'Accept': "application/json, text/plain, */*",
    'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
} # 请求头
r = requests.get(img, headers=headers)
with open('img.png', 'wb') as f:
    f.write(r.content)
block = driver.find_element("id", "slideBlock").get_attribute('src')
r = requests.get(block, headers=headers)
with open('block.png', 'wb') as f:
    f.write(r.content)

 OpenCV识别缺口位置

接下来就是重点,如何确定缺口位置来定位滑动验证码该往哪滑。这里主要用到OpenCV的模板匹配。 首先对滑块也就是稍后匹配时用到的模板进行处理,这里主要就是把形状轮廓提取出来然后去掉多余的东西,先把原图变成灰度图:

tpl_gray = cv2.cvtColor(tpl, cv2.COLOR_BGR2GRAY)

可以看到边缘有一圈阴影部分,我们需要把周围这圈去掉,遍历找到黑色像素点把它变成和周围一样。

width, height = tpl_gray.shape
    for h in range(height):
        for w in range(width):
            if tpl_gray[w, h] == 0:
                tpl_gray[w, h] = 96

处理后变成了这样,然后把中间主体部分涂黑,也就是将图片二值化。

binary = cv2.inRange(tpl_gray, 96, 96)  # 二值化
kernel = np.ones((8, 8), np.uint8)
template = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # 去白色噪点

处理完毕得到理想的模板图:

 接下来对带有缺口的背景图进行处理,这个过程稍微麻烦一点,不过思路还是比较清晰的,还是先转化成灰度图再二值化,这里有一个问题,不同验证码图片之间差距很大,有的颜色很显眼,有的却很清淡,比如下面这两差别太大了,这就导致在二值化的过程中很难有一个固定的参数。

 这里我根据图片的平均灰度值设定了几个区间,对不同区间的验证码图片传入不同参数进行二值化:

def avg_mean(img):
    mean_val, _, _, _ = cv2.mean(img)
    print("平均灰度:", mean_val)
    return mean_val

def match(img):
    gauss = cv2.GaussianBlur(img, [5, 5], 0)
    img_gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY)
    cv2.imshow("111", img_gray)
    if avg_mean(img) > 140: # 二值化
        ret, target = cv2.threshold(img_gray, 105, 255, cv2.THRESH_BINARY)
    elif avg_mean(img) > 102:
        ret, target = cv2.threshold(img_gray, 95, 255, cv2.THRESH_BINARY) 
    else:
        ret, target = cv2.threshold(img_gray, 85, 255, cv2.THRESH_BINARY)

处理过的结果大概像这样:

 效果还是不错的,清晰的凸显了缺口位置,最后把背景图和模板传入opencv的模板匹配方法,记录下匹配到的坐标即可。

result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
left_up = max_loc
print(left_up)
right_down = (left_up[0]   height, left_up[1]   width)
cv2.rectangle(img, left_up, right_down, (0, 0, 255), 2)
cv2.imshow('res', img)

这里框出来看看效果:

 模拟拖动滑块

识别出位置之后就要算出滑块移动了多少距离,我们可以看到滑块初始状态距离边缘有26个像素:

 同时抓下来的图片相比在网页中放大了一倍,所以真实滑动距离是:

(left_up – 26*2)/2

于是用selenium的actionchains模拟拖动滑块:

def drag_block(l):
    drag = driver.find_element("id", "tcaptcha_drag_button")
    ActionChains(driver).click_and_hold(on_element=drag).perform()
    ActionChains(driver).move_to_element_with_offset(to_element=drag, xoffset=l, yoffset=0).perform()
    ActionChains(driver).release().perform()

这样整个流程就搞定了,理论上这样简单粗暴的自动拖过去在很多时候会不奏效,还需要模拟人手动拖动,不过因为我做测试的时候直接就成功了,所以没写下去,整体思路大概是加速减速停几秒或者中间触发几个mouse_up(),mouse_down()事件。

脚本示例:

下面是测试时用到的脚本,selenium部分和主函数,拿某个CTF靶场做的测试,仅供参考,根据实际网站不同肯定得改改:

import time
import requests

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains

import block_loc


def drag_block(l):
    drag = driver.find_element("id", "tcaptcha_drag_button")
    ActionChains(driver).click_and_hold(on_element=drag).perform()
    ActionChains(driver).move_to_element_with_offset(to_element=drag, xoffset=l, yoffset=0).perform()
    ActionChains(driver).release().perform()


def login_in(username, password):
    headers = {
        'Accept': "application/json, text/plain, */*",
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
    }
    driver.get('网址')
    driver.find_element("link text", "登录").click()
    name = driver.find_element("id", "name-input")
    name.send_keys(username)
    pw = driver.find_element("id", "password-input")
    pw.send_keys(password)
    driver.find_element("id", "submit").click()
    time.sleep(2)
    driver.switch_to.frame('tcaptcha_iframe')
    img = driver.find_element("id", "slideBg").get_attribute('src')
    r = requests.get(img, headers=headers)
    with open('img.png', 'wb') as f:
        f.write(r.content)
    block = driver.find_element("id", "slideBlock").get_attribute('src')
    r = requests.get(block, headers=headers)
    with open('block.png', 'wb') as f:
        f.write(r.content)


if __name__ == '__main__':
    options = webdriver.FirefoxOptions()
    driver = webdriver.Firefox(options=options)
    user = "##########"
    pw = "############"
    login_in(user, pw)
    image = "img.png"
    tpl = "block.png"
    length = block_loc.match(image, tpl)
    print(length)
    drag_block(length)

 Opencv部分:

import cv2
import numpy as np


def avg_mean(img):
    mean_val, _, _, _ = cv2.mean(img)
    print("平均灰度:", mean_val)
    return mean_val


def match(image, temp):
    img = cv2.imread(image)
    tpl = cv2.imread(temp)
    tpl_gray = cv2.cvtColor(tpl, cv2.COLOR_BGR2GRAY)
    # cv2.imshow("111", tpl_gray)
    width, height = tpl_gray.shape
    for h in range(height):
        for w in range(width):
            if tpl_gray[w, h] == 0:
                tpl_gray[w, h] = 96
    binary = cv2.inRange(tpl_gray, 96, 96)
    kernel = np.ones((8, 8), np.uint8)
    template = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
    # cv2.imshow('tpl', template)
    print(img.shape)
    gauss = cv2.GaussianBlur(img, [5, 5], 0)
    img_gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY)
    # cv2.imshow("111", img_gray)
    if avg_mean(img) > 140:
        ret, target = cv2.threshold(img_gray, 105, 255, cv2.THRESH_BINARY) # 二值化
    elif avg_mean(img) > 102:
        ret, target = cv2.threshold(img_gray, 95, 255, cv2.THRESH_BINARY)  # 二值化
    else:
        ret, target = cv2.threshold(img_gray, 80, 255, cv2.THRESH_BINARY)
    # cv2.imshow('target', target)
    result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    left_up = max_loc
    print(left_up)
    right_down = (left_up[0] + height, left_up[1] + width)
    cv2.rectangle(img, left_up, right_down, (0, 0, 255), 2)
    # cv2.imshow('res', img)
    length = (left_up[0] - 26*2)/2
    return length
公告:
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299

资源库 - 资源分享下载网 » selenium+opencv实现模拟登陆(滑块验证码)

常见问题FAQ

关于资源售价和售后服务的说明?
本站所有资源的标价均为本站收集资源的辛苦费,不代表资源本身的价值。软件是高智慧高价值的商品,不可能是白菜价。本站资源标价只是赞助费用,收取的赞助费仅用来维持本站的日常运营!毕竟收集整理资料需要投入云计算资源和站长大量的精力。
代码有没有售后服务和技术支持?
由于代码的运行具有不可预见性,本站不保证代码完整可运行,不提供技术支持和售后服务。 本站原创代码都是站长自己开发的,可以有偿提供技术支持服务。 网站里标明【亲测】的代码都是站长亲测过的,其他的代码由于精力有限,没有一一测试,不能保证代码就一定能够使用,更没有技术支持服务,下载前请自行斟酌。
有没有搭建服务?
由于搭建服务比较费时费力,所以本站除了原创代码外均不提供搭建服务。本站分享代码纯属兴趣爱好,不以盈利为目的,请勿咨询有没有搭建服务,谢谢理解。
链接地址失效了怎么办?
请带上资源链接地址联系客服,工作时间内我们看到后将第一时间回复。
关于解压密码
本站资源一般都没有加密,如果发现需要解压密码的,那么就输入 hao.35dc.com 试试。

资源库,由老程序员细心甄别、精心筛选,只为提供优质的源码资源

关于我们 联系我们