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.shapefor 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_valdef 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 requestsfrom selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChainsimport block_locdef 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 npdef avg_mean(img):mean_val, _, _, _ = cv2.mean(img)print("平均灰度:", mean_val)return mean_valdef 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.shapefor h in range(height):for w in range(width):if tpl_gray[w, h] == 0:tpl_gray[w, h] = 96binary = 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_locprint(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)/2return length
相关文章:

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

辽宁申请互联网医院牌照流程
辽宁申请互联网医院牌照流程|沈阳市|大连市|鞍山市|抚顺市|本溪市|丹东市|锦州市|营口市|阜新市|辽阳市|盘锦市|铁岭市|朝阳市|葫芦岛市 很多的人对互联网医院都不是很了解,也不太清楚互联网医院牌照怎么申请,其实牌照申请每个地区都不太一样&#x…...

java实现布隆过滤器
什么是布隆过滤器 布隆过滤器(Bloom Filter)是1970年由布隆提出来的。 它实际上是由一个很长的二进制数组一系列hash算法映射函数,用于判断一个元素是否存在于集合中。 布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和…...

gitlab部署及整合Jenkins持续构建(三)nexus私服的安装及实战、linux安装mysql
文章目录敏捷持续集成是什么?linux安装jdk和maven安装jdk安装mavenlinux安装nexus3.xnexus私服的使用编译安装mysql可能遇到的问题使用cmake时报错敏捷持续集成是什么? 持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作&#x…...

一、Java基础(2)
本章概要 异常的分类及处理 异常的概念异常的分类处理异常的方式 反射机制 动态语言的概念反射机制的概念反射的作用Java 的反射 API反射的过程创建对象的两种方式Method 的 invoke 方法 1.2 异常的分类及处理 1.2.1 异常的概念 异常指在方法不能按正常方式完成时…...

软件设计师重要知识点——第一章——计算机组成与体系结构
目录 1.1数据的表示 1.2数值表示范围 1.3浮点的运算 1.4计算机结构 1.5计算机体系结构分类——Flynn 1.6指令的基本概念 1.7寻址方式 1.8CISC与RISC 1.9流水线 1.10层次化存储结构 1.11Cache 1.12主存——编址与计算 1.13总线 1.14串联系统与并联系统 1.15N模混…...
编程学习心得
我来写一些,我关于编程的简单认识吧。 我觉得编程是一门艺术,也是一项技能,需要不断地学习和练习。无论是初学者还是有经验的开发人员,都需要耐心和恒心,才能够成为一名优秀的程序员。以下是一些关于编程学习的心得和…...
web获取媒体流
1. 下面例子演示了录屏和截图功能: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport"…...

代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些、01背包问题,你该了解这些 滚动数组、 416. 分割等和子集
打卡第42天,搞搞01背包。 今日任务 01背包问题,你该了解这些!01背包问题,你该了解这些! 滚动数组416.分割等和子集 背包问题1.0 :0-1 背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weig…...
【Android】JNI静态与动态注册介绍
JNI的两种注册机制:静态注册和动态注册. 一、JNI介绍 JNI(Java Native Interface),即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C机型交互. 方式: 静态注册动态注册:需要提供Java中…...

【算法题解】22. 接雨水
这是一道 困难 题 题目来自: https://leetcode.cn/problems/trapping-rain-water/ 题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,…...
集合详解之(四)集合的遍历
文章目录🐒个人主页🏅JavaSE系列专栏📖前言:🎀ArrayList集合forEach()方法遍历🎀for循环遍历(针对List集合)🪅增强for循环(也支持Set集合)&#x…...

【I2C】通用驱动i2c-dev分析
文章目录1. 前言2. i2c-dev驱动的注册过程3. open_i2c_dev函数分析4. set_slave_addr函数分析5. i2c_read_bytes函数分析1. 前言 前面分析i2c-tool测试工具就是基于drivers/i2c/i2c-dev.c驱动来实现的。i2c-dev驱动在加载时会遍历所有的I2C总线(i2c_bus_type)上所有注册的adap…...

用GPT-4写代码不用翻墙了?Cursor告诉你:可以~~
目录 一、介绍 二、使用方法 三、其他实例 1.正则表达式 2.自动化测试脚本 3.聊聊技术 一、介绍 Cursor主要功能是根据用户的描述写代码或者进行对话,对话的范围仅限技术方面。优点是不用翻墙、不需要账号。Cursor基于GPT模型,具体什么版本不祥&#…...

硬件语言Verilog HDL牛客刷题day03 时序逻辑部分
1.VL21 根据状态转移表实现时序电路 1.题目: 某同步时序电路转换表如下,请使用D触发器和必要的逻辑门实现此同步时序电路,用Verilog语言描述。 2.解题思路 2.1 首先同步时序电路 , 时钟上升沿触发, 复位信号rst 低电…...
day31 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和
● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和 在本次的题目中,我们使用了贪心算法来解决三个问题:分发饼干、摆动序列、最大子序和。这三个问题都可以使用贪心算法来解决,而且贪心算法的时间复杂度相对较低,能够在较短的…...

MobTech 秒验|本机号码一键登录会泄露隐私吗
本机号码一键登录是一种新型的应用登录方式,它可以利用运营商的数据网关认证能力,实现手机号免密登录,提高用户体验和转化率,降低验证成本和流失率。本机号码一键登录支持三大运营商号码认证,3秒内完成手机号验证&…...

2023年供销合作社研究报告
第一章 行业概况 1.1 供销合作社概述 中华全国供销合作总社,是中华人民共和国全国供销合作社的联合组织。中华全国供销合作总社的前身可以追溯到1949年11月成立的中央合作事业管理局。在新中国成立初期,供销合作社就基本形成了自上而下、覆盖全国的组织…...

【ansible】实施任务控制
目录 实施任务控制 一,循环(迭代)--- loop 1,利用loop----item循环迭代任务 2,item---loop循环案例 1,定义item循环列表 2,通过变量应用列表格式 3,字典列表(迭代嵌套子…...

49天精通Java,第11天,java接口和抽象类的异同,default关键字
目录一、什么是接口二、接口的特点三、接口和类的区别四、接口和抽象类的区别五、接口的声明方式六、default默认方法大家好,我是哪吒。 一、什么是接口 Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...