用selenium解决滑块验证码的实现步骤
作者:骑着青蛙一起二 发布时间:2021-06-02 01:44:39
前言
因为种种原因没能实现愿景的目标,在这里记录一下中间结果,也算是一个收场吧。这篇博客主要是用selenium解决滑块验证码的个别案列。
思路:
用selenium打开浏览器指定网站
将残缺块图片和背景图片下载到本地
对比两张图片的相似地方,计算要滑动的距离
规划路线,移动滑块
实现步骤
1. 用selenium打开浏览器浏览指定网站
1.1 找到chromedriver.exe的路径
点击开始找到谷歌图标==》右键更多==》打开文件位置==》右键谷歌快捷方式==》属性 ==》打开文件所在的位置 ==》复制路径
1.2 代码
from selenium import webdriver
# chrome_path要改成你自己的路径
chrome_path = r"C:\Users\11248\AppData\Local\Google\Chrome\Application\chromedriver.exe"
url = 'https://icas.jnu.edu.cn/cas/login'
driver = webdriver.Chrome(chrome_path)
driver.get(url)
2.将残缺块图片和背景图片下载到本地
2.1 找到图片位置
打开网页进入开发者工具,找到图片位置
2.2 代码
import time
import requests
from PIL import Image
from selenium.webdriver.common.by import By
from io import BytesIO
time.sleep(5)# 进入页面要停留几秒钟,等页面加载完
target_link = driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src')
template_link = driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src')
target_img = Image.open(BytesIO(requests.get(target_link).content))
template_img = Image.open(BytesIO(requests.get(template_link).content))
target_img.save('target.jpg')
template_img.save('template.png')
3. 对比两张图片的相似地方,计算要滑动的距离
3.1 用matchTemplate获取移动距离
因为背景图片中的残缺块位置和原始残缺图的亮度有所差异,直接对比两张图片相似的地方,往往得不到令人满意的结果,在此要对两张图片进行一定的处理,为了避免这种亮度的干扰,笔者这里将两张图片先进行灰度处理,再对图像进行高斯处理,最后进行边缘检测。
def handel_img(img):
imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) # 转灰度图
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) # 高斯模糊
imgCanny = cv2.Canny(imgBlur, 60, 60) # Canny算子边缘检测
return imgCanny
为增加工作量(放屁,统一代码好看点) 将JPG图像转变为4通道(RGBA)
def add_alpha_channel(img):
""" 为jpg图像添加alpha通道 """
r_channel, g_channel, b_channel = cv2.split(img) # 剥离jpg图像通道
alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道
img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel)) # 融合通道
return img_new
3.2 代码
import cv2
# 读取图像
def match(img_jpg_path, img_png_path):
# 读取图像
img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
# 判断jpg图像是否已经为4通道
if img_jpg.shape[2] == 3:
img_jpg = add_alpha_channel(img_jpg)
img = handel_img(img_jpg)
small_img = handel_img(img_png)
res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3)
value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)
value = value[3][0] # 获取到移动距离
return value
3.3 检验效果
为了验证思路和方法是否得当,这里将滑块图片与背景图片进行拼接,为后面埋下一个小坑。
def merge_img(jpg_img, png_img, y1, y2, x1, x2):
""" 将png透明图像与jpg图像叠加
y1,y2,x1,x2为叠加位置坐标值
"""
# 判断jpg图像是否已经为4通道
if jpg_img.shape[2] == 3:
jpg_img = add_alpha_channel(jpg_img)
# 获取要覆盖图像的alpha值,将像素值除以255,使值保持在0-1之间
alpha_png = png_img[yy1:yy2, xx1:xx2, 3] / 255.0
alpha_jpg = 1 - alpha_png
# 开始叠加
for c in range(0, 3):
jpg_img[y1:y2, x1:x2, c] = ((alpha_jpg * jpg_img[y1:y2, x1:x2, c]) + (alpha_png * png_img[yy1:yy2, xx1:xx2, c]))
return jpg_img
img_jpg_path = 'target.jpg' # 读者可自行修改文件路径
img_png_path = 'template.png' # 读者可自行修改文件路径
x1 = match(img_jpg_path, img_png_path)
y1 = 0
x2 = x1 + img_png.shape[1]
y2 = y1 + img_png.shape[0]
# 开始叠加
res_img = merge_img(img_jpg, img_png, y1, y2, x1, x2)
cv2.imshow("res_img ", res_img)
cv2.waitKey(0)
4. 规划路线,移动滑块
4.1 点击滑块移动
用第3节已经获取到的距离,点击滑块进行移动
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver import ActionChains
def crack_slider(distance):
wait = WebDriverWait(driver, 20)
slider = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))
ActionChains(self.driver).click_and_hold(slider).perform()
ActionChains(self.driver).move_by_offset(xoffset=distance, yoffset=0).perform()
time.sleep(2)
ActionChains(self.driver).release().perform()
return 0
神奇的事情是,坑来了,没有匹配成功。
4.2 匹配失败原因
这里有以下两点原因:
图片尺寸发生了变化,距离要进行转换。
滑块滑动时,滑块和残缺块的相对位置有变动
首先解决图片尺寸变化问题,找到网页中图片大小:345x172.500
下载到本地图片大小:480x240
所以要对距离进行以下处理:
distance = distance / 480 * 345
关于第二个问题,这里没有找到很好的测量工具测量出来,好在验证码对位置精确度要求不高,就一个个试数吧。
distance = distance /480 * 345 + 12
5 运行演示
补充
在对极验验证码进行学习中,有的网站对移动轨迹进行了验证,如果滑动太快,也会被识别出机器操作,为了模拟人工操作,出色的程序员写出了一个魔幻移动轨迹,举个例子:我们可以先超过目标,再往回移动。
def get_tracks(distance):
distance += 20
v = 0
t = 0.2
forward_tracks = []
current = 0
mid = distance * 3 / 5
while current < distance:
if current < mid:
a = 2
else:
a = -3
s = v * t + 0.5 * a * (t ** 2)
v = v + a * t
current += s
forward_tracks.append(round(s))
back_tracks = [-3, -3, -2, -2, -2, -2, -2, -1, -1, -1]
return {'forward_tracks': forward_tracks, 'back_tracks': back_tracks}
def crack_slider(tracks):
wait = WebDriverWait(driver, 20)
slider = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))
ActionChains(driver).click_and_hold(slider).perform() # 模拟按住鼠标左键
for track in tracks['forward_tracks']:
ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()
time.sleep(0.5)
for back_tracks in tracks['back_tracks']:
ActionChains(driver).move_by_offset(xoffset=back_tracks, yoffset=0).perform()
ActionChains(driver).move_by_offset(xoffset=-4, yoffset=0).perform()
ActionChains(driver).move_by_offset(xoffset=4, yoffset=0).perform()
time.sleep(0.5)
ActionChains(driver).release().perform()# 释放左键
return 0
完整代码
# coding=utf-8
import re
import requests
import time
from io import BytesIO
import cv2
import numpy as np
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
class CrackSlider():
# 通过浏览器截图,识别验证码中缺口位置,获取需要滑动距离,并破解滑动验证码
def __init__(self):
super(CrackSlider, self).__init__()
self.opts = webdriver.ChromeOptions()
self.opts.add_experimental_option('excludeSwitches', ['enable-logging'])
# self.driver = webdriver.Chrome(ChromeDriverManager().install(), options=self.opts)
chrome_path = r"C:\Users\11248\AppData\Local\Google\Chrome\Application\chromedriver.exe"
self.driver = webdriver.Chrome(chrome_path, options=self.opts)
self.url = 'https://icas.jnu.edu.cn/cas/login'
self.wait = WebDriverWait(self.driver, 10)
def get_pic(self):
self.driver.get(self.url)
time.sleep(5)
target_link = self.driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src')
template_link = self.driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src')
target_img = Image.open(BytesIO(requests.get(target_link).content))
template_img = Image.open(BytesIO(requests.get(template_link).content))
target_img.save('target.jpg')
template_img.save('template.png')
def crack_slider(self, distance):
slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))
ActionChains(self.driver).click_and_hold(slider).perform()
ActionChains(self.driver).move_by_offset(xoffset=distance, yoffset=0).perform()
time.sleep(2)
ActionChains(self.driver).release().perform()
return 0
def add_alpha_channel(img):
""" 为jpg图像添加alpha通道 """
r_channel, g_channel, b_channel = cv2.split(img) # 剥离jpg图像通道
alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道
img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel)) # 融合通道
return img_new
def handel_img(img):
imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) # 转灰度图
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) # 高斯模糊
imgCanny = cv2.Canny(imgBlur, 60, 60) # Canny算子边缘检测
return imgCanny
def match(img_jpg_path, img_png_path):
# 读取图像
img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
# 判断jpg图像是否已经为4通道
if img_jpg.shape[2] == 3:
img_jpg = add_alpha_channel(img_jpg)
img = handel_img(img_jpg)
small_img = handel_img(img_png)
res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3)
value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)
value = value[3][0] # 获取到移动距离
return value
# 1. 打开chromedriver,试试下载图片
cs = CrackSlider()
cs.get_pic()
# 2. 对比图片,计算距离
img_jpg_path = 'target.jpg' # 读者可自行修改文件路径
img_png_path = 'template.png' # 读者可自行修改文件路径
distance = match(img_jpg_path, img_png_path)
distance = distance /480 * 345 + 12
# 3. 移动
cs.crack_slider(distance)
来源:https://blog.csdn.net/qq_44419449/article/details/127414044


猜你喜欢
- ueditor是百度编辑器,在本地的iis环境是可以上传图片了,但放在服务器的iis环境无法上传图片了,经过搜索发现是iis设置问题,引起这
- 在认证框架中还有其他的一些功能。 我们会在接下来的几个部分中进一步地了解它们。权限权限可以很方便地标识用户和用户组可以执行的操作。 它们被D
- 概述在本文中,我们将以深度库即 Mediapipe为基础库,以及其他计算机视觉预处理的CV2库来制作手部地标检测模型。市场上有很多关于这种问
- 写一个 python 脚本需要用到 dbus,但因为 dbus-python 这个包并没有提供 setup.py , 所以无法通过 pip
- 一、数据集爬取现在的深度学习对数据集量的需求越来越大了,也有了许多现成的数据集可供大家查找下载,但是如果你只是想要做一下深度学习的实例以此熟
- 我们可以把表里每一个横行的数据,看成是不同的元组。在理解了这个概念后,昨天我们学了不少的namedtuple类,是否也能把元组转换成name
- 一.正常运行:咱们随便写个文件:# test.pyimport argparseap = argparse.ArgumentParser()
- 聚集索引,数据实际上是按顺序存储的,数据页就在索引页上。就好像参考手册将所有主题按顺序编排一样。一旦找到了所要搜索的数据,就完成了这次搜索,
- 前言vue.js的UI组件库,在git上有多个项目,我见的使用者比较多的是iView和Element.两个组件库,组件都很丰富。官网的介绍i
- 适用环境: PHP5.2.x / mysql 5.0.xclass Mysql { priva
- 如何在php中判断一个网页请求是ajax请求还是普通请求?你可以通过传递参数的方法来实现,例如使用如下网址请求:/path/to/pkphp
- 质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。一、判断一个数是否为素数:基于定义def
- MySQL5.7.21安装与密码设置教程,具体如下官方参考手册1.解压MySQL 5.7.20安装包,如X:\MySQL\mysql-5.7
- PDO::getAvailableDriversPDO::getAvailableDrivers — 返回一个可用驱动的数组(PHP 5 &
- 本文实例讲述了PHP基于rabbitmq操作类的生产者和消费者功能。分享给大家供大家参考,具体如下:注意事项:1、accept.php消费者
- 查询操作和性能优化1.基本操作增models.Tb1.objects.create(c1='xx', c2='oo&
- 本文实例为大家分享了python面向对象版的学生信息管理系统的具体代码,供大家参考,具体内容如下功能:1.能循环输入内容2.展示功能-1.新
- 1.mysql-通过sql建立连接池连接池用sql.Open函数创建连接池,可是此时只是初始化了连接池,并没有创建任何连接。连接创建都是惰性
- asp之家注:asp中FSO组件的功能很强大,如果没有FSO很难想象ASP会变成什么样。对于学习asp编程的朋友一定会接触到FSO相关的操作
- 本文实例讲述了Python2.7中SQLite3基本操作方法。分享给大家供大家参考,具体如下:1、基本操作# -*- coding: utf