滑块验证码处理

2023-10-30


最近遇到了滑块验证问题,我看有纯抠js的,难度比较大,也没这个时间和精力去破解,想着还是用selenium自动化工具去解决吧,稍微研究了一下,用selenium + OpenCV还是比较靠谱的,selenium并不是python的专属,我查了一下java也有,参考

使用java + selenium + OpenCV破解网易易盾滑动验证码
没有用过selenium的可以看看我这篇文章:

selenium的使用

查了很多博客代码大多都失效了(我没有找到一个可以用的),下面是我自己用python的解决方案,描述尽量详尽。我就用网易易盾这个网站作为实验案例,因为我之前遇到的是嵌入式的滑动拼图,所以我这篇文章也是针对嵌入式的滑动拼图做演示,网站页面是这样的:
在这里插入图片描述

网址:网易易盾
下面说一下大体解决思路。

1. 进入网站,判断是否成功加载

url = 'https://dun.163.com/trial/jigsaw'
driver = webdriver.Chrome()
driver.get(url)
WebDriverWait(driver, 5).until(EC.title_contains("滑动拼图"))
driver.maximize_window() # 窗口最大化

EC.title_contains(“滑动拼图”) 即判断加载网页的标题是否包含“滑动拼图”字样,如图[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zwrqg2kN-1638251221693)(C:\Users\sumwhy\AppData\Roaming\Typora\typora-user-images\image-20211111105404103.png)]

WebDriverWait(driver, 5) 即5秒之内加载,比主动time.sleep更优。

2. 点击嵌入式,使网页向下滚动

点击嵌入式之后,是这样的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XhfKRJMz-1638251221694)(C:\Users\sumwhy\AppData\Roaming\Typora\typora-user-images\image-20211111105937314.png)]

如果不向下滑动就无法进行下面的滑动操作,所以这一步是必不可少的,

代码实现:

# 定位嵌入式图标
em = driver.find_element_by_xpath('/html/body/main/div[1]/div/div[2]/div[2]/ul/li[2]') 
em.click() # 点击嵌入式
driver.execute_script('window.scrollTo(0, 300)') # 浏览器向下滑动300个像素

3. 获取网页源代码,用正则取出验证码背景和验证码滑块图片的链接并保存到本地

html = driver.page_source  # 获取网页源代码
# print(html)
bg_img = re.findall(r'alt="验证码背景".*?src="(.*?)"',html)[0]
hk_img = re.findall(r'alt="验证码滑块".*?src="(.*?)"',html)[0]

# 保存图片
with open('./images/bg.jpg','wb') as f:
    f.write(requests.get(bg_img).content)
        
with open('./images/hk.png','wb') as f:
    f.write(requests.get(hk_img).content)
             

4.最最重要的一部分——识别图片滑块缺口位置,计算移动距离

网上有很多图片缺口识别的算法,但我试过感觉都不太尽如人意,成功率很低,最后找到一种简洁高效的方案,直接用cv2的模板匹配,成功率很高,大概90%以上,不敢保证百分百,虽然我试了十次都成功了。

def get_distance():
    """
    获取移动距离
    :return:
    """
    # 读取背景图片和缺口图片
    bg_img = cv2.imread('./images/bg.jpg')  # 背景图片
    tp_img = cv2.imread('./images/hk.png')  # 缺口图片
    # 识别图片边缘
    bg_edge = cv2.Canny(bg_img, 100, 200)
    tp_edge = cv2.Canny(tp_img, 100, 200)
    # 转换图片格式
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
    # 缺口匹配
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配
    x = max_loc[0]  # 滑块在验证图片的x坐标(左边)
    # 绘制方框
    th, tw = tp_pic.shape[:2]
    tl = max_loc  # 左上角点的坐标
    print(tl)
    br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标
    print(br)
    print(br[0])
    cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
    cv2.imwrite('./images/out.jpg', bg_img)  # 保存在本地
    return int(br[0]) - 43

效果:在这里插入图片描述

int(br[0]) - 43 就是最后滑块的移动距离了,br[0]是我们画红框的右下角x坐标,然后减去滑块的宽度和红框边线的宽度就是移动距离,
滑块的宽度我量的方形框40个像素,再加上红色矩形框的2个像素,理论上应该是要减42,但最后做测试尝试还是43效果最好,这个要以网页实际测试结果为准。

5. 规划移动轨迹

​ 因为人们在滑动滑块的时候大多是先加速后减速,有时还会倒退,所以不可以做匀速直线运动,要做变速,变加速直线运动。
​ 用到物理知识:初速度:v0、位移:x、时间:t、加速度:a,满足公式:x = v0 * t + 1/2 * a * t^2
​ 加速度用到random模块,随机选择给定的加速度

def track(distance):
    """
    规划移动的轨迹
    
    :param distance:
    :return:
    """
    #匀速移动
    # for i in range(distance):
    #     ActionChains(self.driver).move_by_offset(1, 0).perform()
    # ActionChains(self.driver).move_by_offset(distance-5, 0).perform()
    t = 0.1
    speed = 0
    current = 0
    mid = 3 / 5 * distance
    track_list = []
    while current < distance:
        if current < mid:
            a = random.choice([1,2,3])
            # a = 3
        else:
            a = random.choice([-1,-2,-3])
            # a = -4
        move_track = speed * t + 0.5 * a * t**2
        track_list.append(round(move_track))
        speed = speed + a*t
        current += move_track
    #模拟人类来回移动了一小段
    end_track = [1,0]*10 +[0]*10+[-1,0]*10
    track_list.extend(end_track)
    offset = sum(track_list) - distance
    #由于四舍五入带来的误差,这里需要补回来
    if offset > 0:
        track_list.extend(offset*[-1,0])
    elif offset < 0:
        track_list.extend(offset*[1,0])
    return track_list

6. 开始移动滑块

定位到滑块元素,之后按下不松开开始在规划好的移动轨迹之内移动之前计算好的距离,到位后再松开:

def slid_button(distance):
    """
    根据缺口位置,移动滑块特定的距离distance
    :param diatance:
    :return:
    """
    # 获取滑块元素
    button = driver.find_element_by_xpath(
        '/html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]/div/div/div[2]/div[3]/div/div/div[2]/div[2]/span')
    # /html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]/div/div/div[2]/div[3]/div/div/div[2]/div[2]/span
    ActionChains(driver).click_and_hold(button).perform()
    time.sleep(0.5)
    track_list = track(distance - 3)
    # print(track_list)
    for i in track_list:
        ActionChains(driver).move_by_offset(i, 0).perform()
    time.sleep(1)
    ActionChains(driver).release().perform()

全部代码整合

from selenium import webdriver
import re
import time
import random
import cv2
import requests
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.webdriver import ActionChains

chrome_options = Options()
chrome_options.add_argument('--headless')  # 浏览器不提供可视化页面
# driver = webdriver.Chrome(chrome_options=chrome_options) # 测试用无头模式无效
url = 'https://dun.163.com/trial/jigsaw'
driver = webdriver.Chrome()
driver.get(url)
WebDriverWait(driver, 5).until(EC.title_contains("滑动拼图"))
driver.maximize_window()
# time.sleep(2)
em = driver.find_element_by_xpath('/html/body/main/div[1]/div/div[2]/div[2]/ul/li[2]')
em.click()
driver.execute_script('window.scrollTo(0, 300)')
time.sleep(1)
html = driver.page_source
# print(html)
bg_img = re.findall(r'alt="验证码背景".*?src="(.*?)"', html)[0]
hk_img = re.findall(r'alt="验证码滑块".*?src="(.*?)"', html)[0]
print(bg_img)
print(hk_img)


def save_img():
    with open('./images/bg.jpg', 'wb') as f:
        f.write(requests.get(bg_img).content)
        f.close()

    with open('./images/hk.png', 'wb') as f:
        f.write(requests.get(hk_img).content)
        f.close()


def get_distance():
    """
    获取移动距离
    :return:
    """

    # 读取背景图片和缺口图片
    bg_img = cv2.imread('./images/bg.jpg')  # 背景图片
    tp_img = cv2.imread('./images/hk.png')  # 缺口图片
    # 识别图片边缘
    bg_edge = cv2.Canny(bg_img, 100, 200)
    tp_edge = cv2.Canny(tp_img, 100, 200)
    # 转换图片格式
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
    # 缺口匹配
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配
    x = max_loc[0]  # 滑块在验证图片的x坐标(左边)
    # 绘制方框
    th, tw = tp_pic.shape[:2]
    tl = max_loc  # 左上角点的坐标
    print(tl)
    br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标
    print(br)
    print(br[0])
    cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
    cv2.imwrite('./images/out.jpg', bg_img)  # 保存在本地
    return int(br[0]) - 43


def track(distance):
    """
    规划移动的轨迹

    :param distance:
    :return:
    """
    # 匀速移动
    # for i in range(distance):
    #     ActionChains(self.driver).move_by_offset(1, 0).perform()
    # ActionChains(self.driver).move_by_offset(distance-5, 0).perform()
    t = 0.1
    speed = 0
    current = 0
    mid = 3 / 5 * distance
    track_list = []
    while current < distance:
        if current < mid:
            a = random.choice([1, 2, 3])
            # a = 3
        else:
            a = random.choice([-1, -2, -3])
            # a = -4
        move_track = speed * t + 0.5 * a * t ** 2
        track_list.append(round(move_track))
        speed = speed + a * t
        current += move_track
    # 模拟人类来回移动了一小段
    end_track = [1, 0] * 10 + [0] * 10 + [-1, 0] * 10
    track_list.extend(end_track)
    offset = sum(track_list) - distance
    # 由于四舍五入带来的误差,这里需要补回来
    if offset > 0:
        track_list.extend(offset * [-1, 0])
    elif offset < 0:
        track_list.extend(offset * [1, 0])
    return track_list


def slid_button(distance):
    """
    根据缺口位置,移动滑块特定的距离distance
    :param diatance:
    :return:
    """
    # 获取滑块元素
    button = driver.find_element_by_xpath(
        '/html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]/div/div/div[2]/div[3]/div/div/div[2]/div[2]/span')
    # /html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]/div/div/div[2]/div[3]/div/div/div[2]/div[2]/span
    ActionChains(driver).click_and_hold(button).perform()
    time.sleep(0.5)
    track_list = track(distance - 3)
    # print(track_list)
    for i in track_list:
        ActionChains(driver).move_by_offset(i, 0).perform()
    time.sleep(1)
    ActionChains(driver).release().perform()


if __name__ == '__main__':
    save_img()
    distance = get_distance()
    slid_button(distance)
    # driver.save_screenshot('./images/big.png')
    time.sleep(5) # 看一下效果
    driver.close()

好了,到这里也该跟大家说再见了,如果本文对你有用,请给俺点个赞吧,虽然收到点赞我并不会获利,但这真的是对我的肯定与鼓舞。创作不易,可能你看一篇也就几分钟,我写一篇可能要几个小时甚至几天,这是真正的吃力不讨好。但就我个人来说,我还是觉得人总要有一点情怀的,作为一个技术追求者,应该具备基本的开源精神,我开始写技术博客有很大原因是受开源精神影响的,生活很难,不让生活磨灭我们的个性,是对自己精神价值的鼓舞,更是对自己情怀的一种坚守。

山野千里,只要在路上,内心就满是欢喜,继续坚持,继续加油啊!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

滑块验证码处理 的相关文章

  • 在Python中解析空选项

    我有一个应用程序 允许您将事件数据发送到自定义脚本 您只需布置命令行参数并指定什么事件数据与什么参数相匹配 问题是这里没有真正的灵活性 您制定的每个选项都将被使用 但并非每个选项都必须有数据 因此 当应用程序构建要发送到脚本的字符串时 某些
  • 有没有办法离线将多个 Plotly HTML 文件合并/嵌入到一个页面/HTML 文件中?

    我正在尝试将多个图表合并成一个 HTML 报告来发送 问题是我真的不认为子图是最好的主意 因为图表相对不相关 不同的 X Y 轴 我所需要做的只是将图表附加到 1 个 HTML 文件中 有一个指南解释了如何使用绘图 URL 来完成此操作 但
  • 在 python 中返回 self [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个代表对象的类 我有很多方法可以修改这个对象状态 没有明显的返回或显然没有任何返回 在 C 中 我会将所有这些方法声明为void
  • 为什么我在 Python 中收到“连接被拒绝”错误? (插座)

    我是套接字新手 请原谅我完全缺乏理解 我有一个服务器脚本 server py usr bin python import socket import the socket module s socket socket Create a so
  • 在 AWS Elastic Beanstalk 中部署 Flask 应用程序

    当我部署 Flask 应用程序时 它显示成功 但是当我检索日志时 我看到错误 找不到 Flask 我的需求文件中有烧瓶 任何帮助 Sat Jan 11 06 51 50 503908 2020 error pid 3393 remote 1
  • 如何将当前日期分配给 odoo v8 中的日期字段?

    我想将当前日期分配给以下代码中的日期字段 start date calendar obj create cr uid name rec res act ion user id rec res asgnd to id start date l
  • 为什么通过selenium切换到alert不稳定?

    为什么通过selenium切换到alert不稳定 例如 1 运行代码 一切顺利 一切都很顺利 但如果这段代码在几分钟内运行 那么可能会出现错误 例如 没有可以单击的元素 等等 2 在一个站点上有一个警报窗口 alert driver swi
  • 如何从 python 脚本更改 python 文件中的变量值

    我目前有一个 python 文件 其中包含一堆带有值的全局变量 我想从一个单独的 python 脚本永久更改这些值 我尝试过 setattr 等 但似乎不起作用 有没有办法做到这一点 简短的回答是 不 不值得这么麻烦 听起来您正在尝试创建一
  • Unpickle 二进制文件为文本[重复]

    这个问题在这里已经有答案了 我需要对基本上如下所示的系统进行一些维护 复杂的遗留Python程序 gt 二进制pickle文件 gt 另一个复杂的遗留Python程序 这需要准确弄清楚中间 pickle 文件中的内容 我怀疑文件格式比生成和
  • OpenCV 在使用 anaconda 的 Linux 上无法与 python 正常工作。收到 cv2.imshow() 未实现的错误

    这就是我得到的确切错误 我的操作系统是 Ubuntu 16 10 OpenCV 错误 未指定错误 该功能未实现 使用 Windows GTK 2 x 或 Carbon 支持重新构建库 如果您使用的是 Ubuntu 或 Debian 请安装
  • 如何使用增量值向 Pyspark 中的 DataFrame 添加列?

    我有一个名为 df 的 DataFrame 如下所示 Atr1 Atr2 Atr3 A A A B A A C A A 我想向其中添加一个具有增量值的新列并获取以下更新的 DataFrame Atr1 Atr2 Atr3
  • 让垂直网格线出现在 matplotlib 的线图中

    我想在绘图上同时获得水平和垂直网格线 但默认情况下仅显示水平网格线 我正在使用一个pandas DataFrame从 python 中的 sql 查询生成 x 轴上带有日期的线图 我不知道为什么它们没有出现在日期上 我试图寻找这个问题的答案
  • 如何在Python中设置像素的alpha值

    我正在尝试编辑image https drive google com file d 0B8JcwRV HVk0OURrcTFJczhmV2RlUGdMOG0ybldYUVRoamtF view usp sharing以一种将所有白色像素转
  • 分别计算男女宿舍

    我想要的结果是这样的 males 1990 Q1 value Q2 value Q3 Value Q4 Value females Q1 value Q2 value Q3 Value Q4 value 如果任何值不存在则默认值 0 imp
  • Scrapy文件下载如何使用自定义文件名

    For my scrapy http doc scrapy org index html我目前正在使用的项目文件管道 https doc scrapy org en latest topics media pipeline html scr
  • 尝试输入字符串时出现名称错误[重复]

    这个问题在这里已经有答案了 import pickle import os import time class Person def init self number address self number number self addr
  • 如何加速Python循环

    我查看了几个网站上的一些讨论 但没有一个给我解决方案 这段代码运行时间超过5秒 for i in xrange 100000000 pass 我正在研究整数优化问题 我必须使用O n log n 算法编辑 O n 4 算法 其中n代表矩阵的
  • launchd执行python脚本,但导入失败

    我使用 appscript 编写了一个 python 脚本来跟踪我当前活动的窗口 我通过 launchd 运行它 但是当我这样做时 它无法导入 appscript 我已经在 launchd 的 plist 中设置了 PYTHONPATH 但
  • 是否有可能构建一个可以通过浏览器运行的网络自动化?

    我创建了一个 Java 程序 它使用镀铬驱动程序 https chromedriver chromium org Selenium https www seleniumhq org and Java Excel API http jexce
  • 保存 Jupyter Notebook,并显示 Plotly Express 小部件

    我有一个 Jupyter 笔记本 python 我使用plotlyexpress 在笔记本中绘图以进行分析 我想与非编码人员共享此笔记本 并让交互式视觉效果仍然可用 但它似乎不起作用 我尝试以下此处提出的建议 https community

随机推荐

  • python 图像识别男女_keras实现简单性别识别(二分类问题)

    importosimportrandomimportcv2importnumpy as npfrom tensorflow contrib keras api keras preprocessing image importImageDat
  • 什么是密码应用安全性评估?多久做一次密码应用安全性评估?

    随着信息技术的飞速发展 网络安全形势愈发严峻 各种安全威胁来势汹汹 勒索攻击 数据泄露等各种安全事件层出不穷 我国面临的网络安全问题同样严峻 而商用密码是保障网络空间安全的根本性核心技术和基础支撑 因此 更加标准和规范的管理和使用密码技术就
  • 146. LRU Cache

    1 The key to solve this problem is using a double linked list which enables us to quickly move nodes 2 The LRU cache is
  • 使用stelnet进行安全的远程管理

    1 telnet有哪些不足 2 ssh如何保证数据传输安全 需求 远程telnet管理设备 用户定义需要在AAA模式下 开启远程登录的服务 定义vty接口 然后从R2登录 是可以登录的 同理R3登录 在R1也可以查看哪些用户telnet登录
  • llvm是什么?

    llvm是什么 llvm是low level virtual machine的简称 其实是一个编译器框架 llvm随着这个项目的不断的发展 已经无法完全的代表这个项目了 只是这种叫法一直延续下来 llvm是一个开源的项目 它最早的时候是Il
  • 物联网IOT-基于STM32开发板的智能养殖系统+华为云平台+APP端应用+keil编译工具

    物联网IOT 基于STM32开发板的智能养殖系统 华为云平台 APP端应用 keil编译工具 文章摘要 整体展示 视频展示 1 流程图 1 硬件设备和APP端 华为云平台 一 项目场景及功能说明 1 项目场景 2 功能说明 二 华为云平台搭
  • CXF学习笔记---让通过参数传递数据

    整整折腾了3天终于通过CXF进行参数传递了 CXF的文档和sample都是存在问题的 这么一些简单的常用内容 硬是找不着 opensource的弊病 目地 通过webservice传递值以及错误信息 true 取result值 false
  • 基于Prometheus+Grafana搭建监控平台(Windows/Linux环境exporter部署)

    待优化 添加端口及防火墙开放配置 1 介绍 1 1 Prometheus是什么 Prometheus 普罗米修斯 是一个最初在SoundCloud上构建的监控系统 自2012年成为社区开源项目 拥有非常活跃的开发人员和用户社区 为强调开源及
  • GBDT回归数学推导

    GBDT回归数学推导 一 写在前面 前面推文讲了 GBDT 做回归的主流程 这篇推文讲数学推导啦 没有看过前面那一篇文章的童鞋建议先看一下 二 贴一下算法 来自李航 统计学习方法 算法8 4 输入 训练数据集 T x 1
  • 修复:Lua script attempted to access a non local key in a cluster node

    local key rate limit KEYS 1 local limit tonumber ARGV 1 local current tonumber redis call get key or 0 if current 1 gt l
  • Linux(RHEL6)启动过程详解

    Linux RHEL6 启动过程详解 Linux 红帽RHEL6 启动过程详解 RHEL的一个重要和强大的方面是它是开源的 并且系统的启动过程是用户可配置的 用户可以自由的配置启动过程的许多方面 包括可以指定启动时运行的程序 同样的 系统关
  • java Integer.compare Integer.compareTo() 比较大小

    今天看到这样的用法用于排序 Integer compare Arrays sort intervals x y gt Integer compare x 0 y 0 java lang包的Integer类的compare 方法比较作为参数给
  • pageHelper分页及工作原理浅析

    1 pageHelper PageHelper是Github上开源的MyBatis分页插件 使用起来简单 方便 支持多种数据库 Github网址 https github com pagehelper Mybatis PageHelper
  • 迅雷调用Potplayer边下边播

    或 global Path 您的Potplayer安装路径 PotPlayerMini64 exe 注意 PotPlayerMini64 exe 或 PotPlayerMini exe 需要您看下Potplayer安装路径下的该文件命名
  • C++类的定义要注意最后的分号不要丢了

    ifndef TEST H define TEST H class Test public 定义成内联的有两种方式 int add int a int b 假设我们要将该函数定义为内联的 声明的时候可以不给出inline关键字 可以在实现的
  • 尚硅谷 Vue2.0 + Vue3.0 入门到精通教程学习笔记 (五)

    第五章 Vuex 5 1 理解 vuex 5 1 1 vuex是什么 1 概念 专门在 Vue 中实现集中式状态 数据 管理的一个 Vue 插件 对 vue 应 用中多个组件的共享状态进行集中式的管理 读 写 也是一种组件间通信的方 式 且
  • 上传自定义jar到maven中央仓库

    第一步 注册JIRA账号 Sign up for Jira Sonatype JIRA 上创建一个账号 第二步 创建 Issue 当JIRA 账号一切准备就绪 项目状态 为 Status RESOLVED 即可 第四步 下载 kleopat
  • [记录]缺少MSVCP140_1.dll文件的解决办法

    本人运行三维重建中的开源项目colmap中的COLMAP bat时出现缺少MSVCP140 1 dll文件的错误 尝试了重新修复方法但还是没有解决 后来通过卸载已有的文件 重新下载该文件才得以解决 下载地址为 https support m
  • IDEA之plugin出现爆红(maven-deploy-plugin2.8.2&maven-site-plugin3.7.1)

    1 问题描述 maven中plugin提示有两处红色波浪线 2 原因 在本地仓库中找不到plugin的jar包 3 1 解决办法 删除本地maven仓库下的所有文件 然后在IDEA上点击maven视图 分别点击clean compile s
  • 滑块验证码处理

    文章目录 1 进入网站 判断是否成功加载 2 点击嵌入式 使网页向下滚动 3 获取网页源代码 用正则取出验证码背景和验证码滑块图片的链接并保存到本地 4 最最重要的一部分 识别图片滑块缺口位置 计算移动距离 5 规划移动轨迹 6 开始移动滑