滑块验证码之模拟人工滑速

前言

代码直接运行即可

此处是用的selenium模拟,主要记录的难点是如何 模拟人工滑速
具体原理和利用到的东西都有做注释,逻辑完整,小白还是可以尝试理解的

一、正常简单模拟滑动

目标网址:点击

import base64
import time
import ddddocr
from selenium import webdriver
from selenium.webdriver.common.by import Bydef text_dis(bg, fg):slide = ddddocr.DdddOcr(det=False, ocr=False)with open(bg, 'rb') as f:target_bytes = f.read()with open(fg, 'rb') as f:background_bytes = f.read()res = slide.slide_comparison(target_bytes, background_bytes) # 计算出距离return res.get('target')[0]def get_slide():options = webdriver.ChromeOptions()# 对于老版本的浏览器不行options.add_argument('--disable-blink-features=AutomationControlled')driver = webdriver.Chrome(chrome_options=options)driver.maximize_window()driver.get('https://www.geetest.com/demo/slide-bind.html')driver.find_element(By.ID, 'username').send_keys('13697028751')  # 输入框输入账号和密码driver.find_element(By.ID, 'password').send_keys('19961227ai')time.sleep(2)driver.find_element(By.CSS_SELECTOR, 'div.btn').click()  # 点击登录time.sleep(2)img_src = driver.execute_script('return document.getElementsByClassName("geetest_canvas_bg geetest_absolute")[0].toDataURL("image/png");')print(img_src)im_base64 = img_src.split(',')[1]im_bytes = base64.b64decode(im_base64)print(im_base64)print(im_bytes)print('-----------------------------------')with open('./bg.png', 'wb') as f:f.write(im_bytes)temp = driver.execute_script("return document.getElementsByClassName('geetest_canvas_fullbg geetest_fade geetest_absolute')[0].toDataURL('image/png');")print(temp)temp_base64 = temp.split(',')[1]temp_bytes = base64.b64decode(temp_base64)with open('./temp.png', 'wb') as f:f.write(temp_bytes)distance = text_dis('bg.png', 'temp.png')  # 计算出距离print('距离:', distance)# 拖动滑块slide = driver.find_element(By.CSS_SELECTOR, 'div.geetest_slider_button')action_chains = webdriver.ActionChains(driver)# 点击,准备拖拽action_chains.click_and_hold(slide)  # 鼠标左键点击但不释放action_chains.pause(0.2)action_chains.move_by_offset(distance - 10, 0)action_chains.pause(0.8)action_chains.move_by_offset(10, 0)action_chains.pause(1.4)action_chains.move_by_offset(-10, 0)action_chains.release()action_chains.perform()time.sleep(20)get_slide()

扩展

selenium常用模拟操作

1、行为控制
perform --- 执行所有准备好的Action
reset_actions --- 清空所有准备好的Action  #  该方法在 selenium 3.141.0版本不生效
pause --- 设置Action之间的动作时间间隔2、鼠标操作
click --- 鼠标左键点击(可以指定或不指定元素对象)
click_and_hold --- 鼠标左键点击但不释放(可以指定或不指定元素对象)
release --- 释放鼠标点击动作(可以指定或不指定在目标元素对象上释放)
context_click --- 鼠标右键点击(可以指定或不指定元素对象)
double_click --- 鼠标左键双击(可以指定或不指定元素对象)
drag_and_drop --- 鼠标左键在两个元素之间拖拽
drag_and_drop_by_offset --- 鼠标左键拖拽元素到目标偏移位置
move_by_offset --- 鼠标移动指定偏移
move_to_element --- 鼠标移动到指定元素
move_to_element_with_offset --- 鼠标移动到指定元素的指定偏移位置

二、应对滑速检测代码

目标网址:点击

#!/usr/bin/env python 
# -*- coding:utf-8 -*-
import json
import random
import re
import time
import cv2
import base64
import os
import numpy as np
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWaitdef get_random_float(min, max, digits=4):return round(random.uniform(min, max), 4)def base64_to_image(base64_code, img_name):dir_path = re.sub(r'/([a-z]|_|-)*.(png|jp(e)?g)$', '', img_name)if not os.path.exists(dir_path):os.makedirs(dir_path)img_data = base64.b64decode(base64_code)file = open(img_name, 'wb')file.write(img_data)file.close()return img_nameclass JD_Register(object):# jd 注册页面验证码def __init__(self, url, username, pwd=''):super(JD_Register, self).__init__()self.url = url          # 实际地址options = ChromeOptions()options.add_experimental_option('excludeSwitches', ['enable-automation'])self.driver = webdriver.Chrome(options=options)self.wait = WebDriverWait(self.driver, 10)self.username = username  # 账户信息self.password = pwdself.target_path = "./target_reg.png"self.template_path = "./template_reg.png"self.zoom = 1  # 网页图片缩放def open_url(self, url=None):self.driver.maximize_window()self.driver.get(url if url else self.url)def main(self):self.open_url()       # 打开网页self.loginOn()        # 登录打开验证码self._crack_slider()  # 模拟人滑动验证码def loginOn(self):print("------------------------ 进度1:填写账号~")self.driver.find_element(By.XPATH, '/html/body/div[4]/div[2]/div/div[2]/button').click()  # 同意time.sleep(2)self.driver.find_element(By.ID, 'form-phone').send_keys('13697028751')  # 输入框输入账号和密码time.sleep(2)self.driver.find_element(By.CLASS_NAME, 'form-item-getcode').click()  # 点击登录time.sleep(2)def _crack_slider(self):pic_success = self._get_pic()  # 获取图片if pic_success:# 模板匹配target = cv2.imread(self.target_path)             # 查看完整图片template = cv2.imread(self.template_path)         # 查看缺少图片distance = self._match_templet(target, template)  # 计算缺口最大距离tracks = self._get_tracks(distance * self.zoom)   # 拖拽轨迹计算self._slider_action(tracks)                       # 模拟人工移动滑块# 判断登录is_go_on = input('是否继续测试?y:是     其它:退出')if is_go_on and is_go_on.lower() == 'y':print("开始下一次尝试")return self._crack_slider()else:return Falsedef _get_pic(self):"""下载图片到本地"""# print("查找缺口图片")time.sleep(1)target = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="slideAuthCode"]/div/div[1]/div[2]/div[1]/img')))template = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="slideAuthCode"]/div/div[1]/div[2]/div[2]/img')))if target and template:print("------------------------ 进度2:下载滑块验证码图片")target_base64 = target.get_attribute('src')template_base64 = template.get_attribute('src')target_base64_str = re.sub(r'data:[a-z]*/[a-z]*;base64,', '', target_base64)template_base64_str = re.sub(r'data:[a-z]*/[a-z]*;base64,', '', template_base64)base64_to_image(target_base64_str, self.target_path)base64_to_image(template_base64_str, self.template_path)time.sleep(1)local_img = Image.open(self.target_path)  # 打开图片size_loc = local_img.size  # 获取图片大小尺寸self.zoom = 364 / int(size_loc[0])  # 对比判断图片是否一致,有无放大过print("计算缩放比例 zoom = %f" % round(self.zoom, 4))return Trueelse:print("未找到缺口图片")return Falsedef _match_templet(self, img_target, img_template):"""模板匹配(用于寻找缺口):param img_target: 带有缺口的背景图:param img_template: 缺口的滑块图:return: 缺口所在的位置的x轴距离"""print("------------------------ 进度3:图片缺口模板匹配")# 滑块图片处理tpl = self.__handle_slider_img(img_template)         # 误差来源就在于滑块的背景图为白色blurred = cv2.GaussianBlur(img_target, (3, 3), 0)    # 图片高斯滤波gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)     # 图片灰度化width, height = tpl.shape[:2]result = cv2.matchTemplate(gray, tpl, cv2.TM_CCOEFF_NORMED) # 灰度化模板匹配  使用灰度化图片print("result = {}".format(len(np.where(result >= 0.5)[0])))# 查找数组中匹配的最大值min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)left_up = max_locright_down = (left_up[0] + height, left_up[1] + width)  # 通过获取最远距离cv2.rectangle(img_target, left_up, right_down, (7, 279, 151), 2)print("验证码位移距离为:%d" % left_up[0])return left_up[0]def __handle_slider_img(self, image):"""对滑块进行二值化处理:param image: cv类型的图片对象"""kernel = np.ones((8, 8), np.uint8)  # 去滑块的前景噪声内核gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 灰度化# 灰化背景width, heigth = gray.shapefor h in range(heigth):for w in range(width):if gray[w, h] == 0:gray[w, h] = 96# 排除背景binary = cv2.inRange(gray, 96, 96)res = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)  # 开运算去除白色噪点return resdef _get_cookie(self):cookie_items = self.driver.get_cookies()ck_dict = {}for cookie in cookie_items:ck_dict[cookie['name']] = cookie['value']print("cookie = %s" % ck_dict)self._save_to_file(json.dumps(ck_dict, separators=(',', ':'), ensure_ascii=False))self.driver.quit()def _save_to_file(self, str_data):file = Nonetry:file = open("../static/temp/cookie.txt", "w")file.write(str_data)except:print("保存cookie异常")finally:if file:file.close()# ---- 拖拽轨迹计算 start ----def _get_tracks(self, distance):"""根据偏移量获取移动轨迹3:param distance: 偏移量:return: 移动轨迹"""print('------------------------ 进度4:计算图片拖拽轨迹')track = []mid1 = round(distance * random.uniform(0.1, 0.2))mid2 = round(distance * random.uniform(0.65, 0.76))mid3 = round(distance * random.uniform(0.84, 0.88))# 设置初始位置、初始速度、时间间隔current, v, t = 0, 0, 0.2distance = round(distance)# 四段加速度while current < distance:if current < mid1:a = random.randint(10, 15)elif current < mid2:a = random.randint(30, 40)elif current < mid3:a = -70else:a = random.randint(-25, -18)v0 = v              # 初速度 v0v = v0 + a * t      # 当前速度 v = v0 + atv = v if v >= 0 else 0move = v0 * t + 1 / 2 * a * (t ** 2)move = round(move if move >= 0 else 1)current += move     # 当前位移track.append(move)  # 加入轨迹# 超出范围back_tracks = []out_range = distance - currentprint("当前= {}, 距离= {}, 超出范围 = {}".format(current, distance, out_range))if out_range < -8:sub = int(out_range + 8)back_tracks = [-1, sub, -3, -1, -1, -1, -1]elif out_range < -2:sub = int(out_range + 3)back_tracks = [-1, -1, sub]print("向前轨道= {}, 返回轨道={}".format(track, back_tracks))return {'forward_tracks': track, 'back_tracks': back_tracks}# ---- 移动滑块 start ----def _slider_action(self, tracks):print("------------------------ 进度5:模拟人工移动滑块")# 点击滑块slider = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="slideAuthCode"]/div/div[2]/div[3]')))if slider:ActionChains(self.driver).click_and_hold(slider).perform()  # 鼠标左键点击不释放,保持滑动状态# 正向滑动for track in tracks['forward_tracks']:yoffset_random = random.uniform(-2, 4)ActionChains(self.driver).move_by_offset(xoffset=track, yoffset=yoffset_random).perform()time.sleep(random.uniform(0.06, 0.5))# 反向滑动for back_tracks in tracks['back_tracks']:yoffset_random = random.uniform(-2, 2)ActionChains(self.driver).move_by_offset(xoffset=back_tracks, yoffset=yoffset_random).perform()# 抖动ActionChains(self.driver).move_by_offset(xoffset=get_random_float(0, -1.67), yoffset=get_random_float(-1, 1)).perform()ActionChains(self.driver).move_by_offset(xoffset=get_random_float(0, 1.67), yoffset=get_random_float(-1, 1)).perform()time.sleep(get_random_float(0.2, 0.6))ActionChains(self.driver).release().perform()print("滑块移动成功")return Trueelse:print("未找到滑块")return Falseif __name__ == '__main__':c = JD_Register(url='https://reg.jd.com/p/regPage', username='13965216565')c.main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/171901.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【全栈开发】RedwoodJS与BlitzJS:全栈JavaScript元框架的未来

Redwood和Blitz是两个即将出现的全栈元框架&#xff0c;它们提供了创建SPAs、服务器端渲染页面和静态生成内容的工具&#xff0c;并提供了生成端到端支架的CLI。我一直在等待一个有价值的Rails JavaScript替代品&#xff0c;谁知道什么时候。这篇文章是对两者的概述&#xff0c…

参数估计(三)区间估计

文章目录 区间估计的概念一个正态总体的情形 μ \mu μ 的区间估计 σ 2 \sigma^2 σ2 的区间估计 两个正态总体的情形 μ 1 − μ 2 \mu_1-\mu_2 μ1​−μ2​ 的区间估计 σ 1 2 / σ 2 2 \sigma_1^2/\sigma_2^2 σ12​/σ22​ 的区间估计 参考文献 区间估计的概念 对未知参…

opencv-利用DeepLabV3+模型进行图像分割去除输入图像的背景

分离图像中的人物和背景通常需要一些先进的图像分割技术。GrabCut是一种常见的方法&#xff0c;但是对于更复杂的场景&#xff0c;可能需要使用深度学习模型。以下是使用深度学习模型&#xff08;如人像分割模型&#xff09;的示例代码&#xff1a; #导入相关的库 import cv2 …

[C++]指针与结构体

标题 一.指针1.指针的定义和使用2.指针所占的内存空间3.空指针与野指针4.const修饰指针5.指针和数组6.指针和函数 二.结构体1.结构体的定义与使用2.结构体数组3.结构体指针4.结构体的嵌套使用5.结构体做函数参数6.结构体中const使用场景7.案例练习 一.指针 作用: 可以通过指针…

FPGA驱动CS4344 VHDL例程

CS4344是一款非常简单的I2S立体声24bit D/A芯片&#xff0c;采样率高达192KHz&#xff0c;相对于ADAU1761复杂的寄存器配置来说&#xff0c;CS4344非常友好&#xff0c;无需配置寄存器&#xff0c;只要按I2S时序输入数据&#xff0c;即可实现立体声输出&#xff0c;且10PIN TSS…

SpringBoot 拦截器高级篇

Springboot 拦截器 定义使用场景拦截器与过滤器的区别实现步骤全局拦截器的局限性全局拦截器VS局部拦截器局部拦截器自定义局部拦截器使用多个局部拦截器 定义 拦截器是Spring MVC框架中的一个重要组件&#xff0c;它是一种AOP&#xff08;面向切面编程&#xff09;的实现方式&…

探索计算机视觉:深度学习与图像识别的融合

探索计算机视觉&#xff1a;深度学习与图像识别的融合 摘 要&#xff1a; 本文将探讨计算机视觉领域中的深度学习技术&#xff0c;并重点关注图像识别方面的应用。我们将介绍卷积神经网络&#xff08;CNN&#xff09;的原理、常用的图像数据集以及图像识别的实际应用场景&…

Leetcode 1727. 具有重排的最大子矩阵

题目要求&#xff1a; 给定一个大小为 m x n 的二进制矩阵&#xff0c;并且允许您以任意顺序重新排列矩阵的列。 对列进行最佳重新排序后&#xff0c;返回矩阵中每个元素都为 1 的最大子矩阵的面积。 输入&#xff1a;矩阵 [[0,0,1],[1,1,1],[1,0,1]] 输出&#xff1a;4 说明…

Java制作“简易王者荣耀”小游戏

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; im…

班级管理五步法

亲爱的教师朋友们&#xff01;今天我要和大家分享一个超级实用的班级管理方法——班级管理五步法&#xff01;用这个方法&#xff0c;轻松掌握班级秩序&#xff0c;一起来看看吧&#xff01; 第一步&#xff1a;建立规矩 我们要和孩子们一起建立规矩。规矩要简单明了&#xff…

java基础-变量类型

1、Java变量类型 在Java语言中&#xff0c;所有的变量在使用前必须声明。声明变量的基本格式如下&#xff1a; type identifier [ value][, identifier [ value] ...] ; 格式说明&#xff1a; type -- 数据类型。identifier -- 是变量名&#xff0c;可以使用逗号 , 隔开来声明…

301. 任务安排2,斜率优化dp

301. 任务安排2 - AcWing题库 有 N 个任务排成一个序列在一台机器上等待执行&#xff0c;它们的顺序不得改变。 机器会把这 N 个任务分成若干批&#xff0c;每一批包含连续的若干个任务。 从时刻 0 开始&#xff0c;任务被分批加工&#xff0c;执行第 i 个任务所需的时间是 …

Go 语言 Printf 函数和格式化动词详解

Printf() 函数可以使用多种格式化动词对输出进行格式化。下面是可以与所有数据类型一起使用的一些通用格式化动词&#xff1a; 通用格式化动词&#xff1a; 以下动词适用于所有数据类型&#xff1a; 动词描述%v以默认格式打印值%#v以 Go 语法格式打印值%T打印值的类型%%打印百…

JAVA小游戏简易版王者荣耀

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;…

从0到1建立前端规范

本文适合打算建立前端规范的小伙伴阅读 一、为什么需要规范 规范能给我们带来什么好处&#xff0c;如果没有规范会造成什么后果&#xff1f;这里主要拿代码规范来说。 统一代码规范的好处&#xff1a; 提高代码整体的可读性、可维护性、可复用性、可移植性和可靠性&#xf…

数据结构 / 顺序表操作 / 顺序表尾部添加

顺序表尾部添加函数代码 /**注意要判断顺序表是否已满*成功返回0*失败返回-1* */int append(sqlist *list, data_type element) {if(NULLlist || 1is_list_full(list)){return -1;}list->arr[list->len]element;return 0; } 完整代码 #include <string.h> #inclu…

Pytorch项目的文件结构一般都是怎么组织的?

如果是从一些比较典型的论文里弄下来的源码&#xff0c;你会发现它们的论文结构往往都非常复杂。不同的模型、不同的论文&#xff0c;可能代码结构组织的方式都不一样。但它们都不外乎就是经历这几个方面&#xff1a; 1、模型和结构模块定义&#xff1b; 2、数据集获取与处理…

Mybatis反射核心类Reflector

Reflector类负责对一个类进行反射解析&#xff0c;并将解析后的结果在属性中存储起来。 一个类反射解析后都有哪些属性呢&#xff1f;我们可以通过Reflector类定义的属性来查看 public class Reflector {// 要被反射解析的类private final Class<?> type;// 可读属性列…

带你用uniapp从零开发一个仿小米商场_6. 配置uniapp项目底部导航栏tabbar

uniapp底部tabbar介绍 在uni-app中&#xff0c;底部tabbar是一种常见的导航方式&#xff0c;它可以让用户在应用的不同页面之间进行切换。通过tabBar配置项&#xff0c;开发者可以指定一级导航栏和tab切换时显示的对应页。 在底部tabbar中&#xff0c;每个tab都有一个页面路径…

cdb数据库强起流程

环境模拟 因为手头没有19.3的环境&#xff0c;用了一个centos 7.9下的18.3的cdb环境,开启了归档 在pdb中创建表&#xff0c;模拟构造数据 然后删除redo log来模拟损坏 模拟插入的过程&#xff0c;及错误时的报错 SQL> create table t(x int); Table created. SQL> b…