IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> python基于cv2和selenium通过极验拼图拖动验证 -> 正文阅读

[开发测试]python基于cv2和selenium通过极验拼图拖动验证

前言

部分参考blog

https://blog.csdn.net/m0_50944918/article/details/112135031
https://blog.csdn.net/hjxu2016/article/details/77833336
https://www.bilibili.com/video/BV1kT4y1L7e5?from=search&seid=1953780930962809824&spm_id_from=333.337.0.0

吐槽

这两天想尝试通过拼图拖动这种验证码,后来经过查询发现很多公司都是用的极验。随机上网查了部分博客,从中学习了很多种方法。但是个人觉得都比较复杂,然后自己使用了cv2的灰度+二值化发现可以轻松获取到拼图的边缘,所以边缘检测这边是我自己写得,可以获取到按钮拖动的距离。下面的拖动加速度等拖动操作主要参考了别人的代码(^_?)☆
感谢@我不是秃头sheep的帮忙

代码

1.引入库

import random
import time
import cv2
import numpy as np
from selenium import webdriver

2.初始化浏览器驱动,设置全局变量btn

options = webdriver.ChromeOptions()
options.add_argument("--auto-open-devtools-for-tabs")
driver = webdriver.Chrome(chrome_options=options)
btn = None

3.编写爬虫对网页元素截图

    def get_pic(self):
        url = "https://www.geetest.com/Register?email="
        self.driver.get(url)
        self.driver.maximize_window()
        self.driver.implicitly_wait(10)
        self.driver.find_element_by_xpath(
            '//*[@id="gt-register-mobile"]/div/div[2]/div[1]/div[2]/div/div[3]/div[1]/input').send_keys("1")
        self.driver.find_element_by_xpath(
            '//*[@id="gt-register-mobile"]/div/div[2]/div[1]/div[2]/div/div[3]/div[2]/div[1]/div').click()
        ele = self.driver.find_element_by_xpath(
            '/html/body/div[3]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/div/canvas[2]')
        time.sleep(0.5)
        ele.screenshot('ele.png')
        global btn
        btn = self.driver.find_element_by_xpath("/html/body/div[3]/div[2]/div[6]/div/div[1]/div[2]/div[2]")

4.cv2边缘识别,获取平移值

    def get_targetOffsetX(self):
        """模仿人的拖拽动作:快速沿着X轴拖动(存在误差),再暂停,然后修正误差
        防止被检测为机器人,出现“图片被怪物吃掉了”等验证失败的情况
        :param source:要拖拽的html元素
        :param targetOffsetX: 拖拽目标x轴距离
        :return: None"""
        # 读取原图片
        img = cv2.imread("ele.png", 0)
        # 二值化(达到阈值的像素变成黑色)
        _, th = cv2.threshold(img, 80, 255, 1)
        # cv2.imshow("2", th)
        # cv2.waitKey()

        # hape[0] =图像的高
        # shape[1] =图像的宽

        # 截取起始位置的拼图
        th1 = th[0:th.shape[0], 0:55]
        # 截取拼图的终点位置
        th2 = th[0:th.shape[0], 55:th.shape[1]]

        # 第一个参数是寻找轮廓的图像;
        # 第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
        #     cv2.RETR_EXTERNAL     表示只检测外轮廓
        #     cv2.RETR_LIST                检测的轮廓不建立等级关系
        #     cv2.RETR_CCOMP          建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
        #     cv2.RETR_TREE            建立一个等级树结构的轮廓。
        #
        # 第三个参数method为轮廓的近似办法
        #     cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
        #     cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
        #     cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法

        # contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        contours2, hierarchy2 = cv2.findContours(th2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        temps = list(map(lambda x: np.array(x).reshape(np.array(x).shape[0], 2), contours2))
        result = np.concatenate(tuple(temps), axis=0)
        # 分别为所有坐标的x轴与y轴的列表
        x1 = list(map(lambda x: x[0], result))
        # y1 = list(map(lambda x: x[1], result))
        # height, width = max(y1), max(x1) + 55
        # dst = np.zeros((height, width, 1), np.uint8)
        # img = cv2.drawContours(dst, contours, -1, (255, 255, 255), 3)
        # cv2.imshow("binary2", img)
        # cv2.waitKey()
        return int(max(x1))

5.拖动(ActionChains)

    def simulateDragX(self, source, targetOffsetX):
        action_chains = webdriver.ActionChains(self.driver)
        # 点击,准备拖拽
        action_chains.click_and_hold(source)
        # 拖动次数,二到三次
        # dragCount = random.randint(2, 3)
        # if dragCount == 2:
        #     # 总误差值
        #     sumOffsetx = random.randint(-2, 2)
        #     action_chains.move_by_offset(targetOffsetX + sumOffsetx, 0)
        #     # 暂停一会
        #     action_chains.pause(self.__getRadomPauseScondes())
        #     # 修正误差,防止被检测为机器人,出现图片被怪物吃掉了等验证失败的情况
        #     action_chains.move_by_offset(-sumOffsetx, 0)
        # elif dragCount == 3:
            # 总误差值
        sumOffsetx = random.randint(-5, 5)
        action_chains.move_by_offset(targetOffsetX + sumOffsetx, 0)
        # 暂停一会
        action_chains.pause(self.__getRadomPauseScondes())

        # 已修正误差的和
        fixedOffsetX = 0
        # 第一次修正误差
        if sumOffsetx < 0:
            offsetx = random.randint(sumOffsetx, 0)
        else:
            offsetx = random.randint(0, sumOffsetx)

        fixedOffsetX = fixedOffsetX + offsetx
        action_chains.move_by_offset(-offsetx, 0)
        action_chains.pause(self.__getRadomPauseScondes())

        # 最后一次修正误差
        action_chains.move_by_offset(-sumOffsetx + fixedOffsetX, 0)
        action_chains.pause(self.__getRadomPauseScondes())
        # 参考action_chains.drag_and_drop_by_offset()
        action_chains.release()
        action_chains.perform()

    def simpleSimulateDragX(self, source, targetOffsetX):
        """
        简单拖拽模仿人的拖拽:快速沿着X轴拖动,直接一步到达正确位置,再暂停一会儿,然后释放拖拽动作
        B站是依据是否有暂停时间来分辨人机的,这个方法适用。
        :param source:
        :param targetOffsetX:
        :return: None
        """
        action_chains = webdriver.ActionChains(self.driver)
        # 点击,准备拖拽
        action_chains.click_and_hold(source)
        action_chains.pause(0.2)
        action_chains.move_by_offset(targetOffsetX, 0)
        action_chains.pause(0.6)
        action_chains.release()
        action_chains.perform()

完整代码

import random
import time
import cv2
import numpy as np
from selenium import webdriver

# https://blog.csdn.net/m0_50944918/article/details/112135031
# https://blog.csdn.net/hjxu2016/article/details/77833336
# https://www.bilibili.com/video/BV1kT4y1L7e5?from=search&seid=1953780930962809824&spm_id_from=333.337.0.0

options = webdriver.ChromeOptions()
options.add_argument("--auto-open-devtools-for-tabs")
driver = webdriver.Chrome(chrome_options=options)
btn = None


class DragUtil():
    def __init__(self, driver):
        self.driver = driver

    def get_pic(self):
        url = "https://www.geetest.com/Register?email="
        self.driver.get(url)
        self.driver.maximize_window()
        self.driver.implicitly_wait(10)
        self.driver.find_element_by_xpath(
            '//*[@id="gt-register-mobile"]/div/div[2]/div[1]/div[2]/div/div[3]/div[1]/input').send_keys("1")
        self.driver.find_element_by_xpath(
            '//*[@id="gt-register-mobile"]/div/div[2]/div[1]/div[2]/div/div[3]/div[2]/div[1]/div').click()
        ele = self.driver.find_element_by_xpath(
            '/html/body/div[3]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/div/canvas[2]')
        time.sleep(0.5)
        ele.screenshot('ele.png')
        global btn
        btn = self.driver.find_element_by_xpath("/html/body/div[3]/div[2]/div[6]/div/div[1]/div[2]/div[2]")

    def __getRadomPauseScondes(self):
        """
        :return:随机的拖动暂停时间
        """
        return random.uniform(0.6, 0.9)

    def get_targetOffsetX(self):
        """模仿人的拖拽动作:快速沿着X轴拖动(存在误差),再暂停,然后修正误差
        防止被检测为机器人,出现“图片被怪物吃掉了”等验证失败的情况
        :param source:要拖拽的html元素
        :param targetOffsetX: 拖拽目标x轴距离
        :return: None"""
        # 读取原图片
        img = cv2.imread("ele.png", 0)
        # 二值化(达到阈值的像素变成黑色)
        _, th = cv2.threshold(img, 80, 255, 1)
        # cv2.imshow("2", th)
        # cv2.waitKey()

        # hape[0] =图像的高
        # shape[1] =图像的宽

        # 截取起始位置的拼图
        th1 = th[0:th.shape[0], 0:55]
        # 截取拼图的终点位置
        th2 = th[0:th.shape[0], 55:th.shape[1]]

        # 第一个参数是寻找轮廓的图像;
        # 第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
        #     cv2.RETR_EXTERNAL     表示只检测外轮廓
        #     cv2.RETR_LIST                检测的轮廓不建立等级关系
        #     cv2.RETR_CCOMP          建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
        #     cv2.RETR_TREE            建立一个等级树结构的轮廓。
        #
        # 第三个参数method为轮廓的近似办法
        #     cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
        #     cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
        #     cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法

        # contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        contours2, hierarchy2 = cv2.findContours(th2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        temps = list(map(lambda x: np.array(x).reshape(np.array(x).shape[0], 2), contours2))
        result = np.concatenate(tuple(temps), axis=0)
        # 分别为所有坐标的x轴与y轴的列表
        x1 = list(map(lambda x: x[0], result))
        # y1 = list(map(lambda x: x[1], result))
        # height, width = max(y1), max(x1) + 55
        # dst = np.zeros((height, width, 1), np.uint8)
        # img = cv2.drawContours(dst, contours, -1, (255, 255, 255), 3)
        # cv2.imshow("binary2", img)
        # cv2.waitKey()
        return int(max(x1))

    def simulateDragX(self, source, targetOffsetX):
        action_chains = webdriver.ActionChains(self.driver)
        # 点击,准备拖拽
        action_chains.click_and_hold(source)
        # 拖动次数,二到三次
        # dragCount = random.randint(2, 3)
        # if dragCount == 2:
        #     # 总误差值
        #     sumOffsetx = random.randint(-2, 2)
        #     action_chains.move_by_offset(targetOffsetX + sumOffsetx, 0)
        #     # 暂停一会
        #     action_chains.pause(self.__getRadomPauseScondes())
        #     # 修正误差,防止被检测为机器人,出现图片被怪物吃掉了等验证失败的情况
        #     action_chains.move_by_offset(-sumOffsetx, 0)
        # elif dragCount == 3:
            # 总误差值
        sumOffsetx = random.randint(-5, 5)
        action_chains.move_by_offset(targetOffsetX + sumOffsetx, 0)
        # 暂停一会
        action_chains.pause(self.__getRadomPauseScondes())

        # 已修正误差的和
        fixedOffsetX = 0
        # 第一次修正误差
        if sumOffsetx < 0:
            offsetx = random.randint(sumOffsetx, 0)
        else:
            offsetx = random.randint(0, sumOffsetx)

        fixedOffsetX = fixedOffsetX + offsetx
        action_chains.move_by_offset(-offsetx, 0)
        action_chains.pause(self.__getRadomPauseScondes())

        # 最后一次修正误差
        action_chains.move_by_offset(-sumOffsetx + fixedOffsetX, 0)
        action_chains.pause(self.__getRadomPauseScondes())
        # 参考action_chains.drag_and_drop_by_offset()
        action_chains.release()
        action_chains.perform()

    def simpleSimulateDragX(self, source, targetOffsetX):
        """
        简单拖拽模仿人的拖拽:快速沿着X轴拖动,直接一步到达正确位置,再暂停一会儿,然后释放拖拽动作
        B站是依据是否有暂停时间来分辨人机的,这个方法适用。
        :param source:
        :param targetOffsetX:
        :return: None
        """
        action_chains = webdriver.ActionChains(self.driver)
        # 点击,准备拖拽
        action_chains.click_and_hold(source)
        action_chains.pause(0.2)
        action_chains.move_by_offset(targetOffsetX, 0)
        action_chains.pause(0.6)
        action_chains.release()
        action_chains.perform()


if __name__ == "__main__":
    _driver = DragUtil(driver)
    _driver.get_pic()
    _driver.simulateDragX(btn, _driver.get_targetOffsetX())

总结

目前成功率还算可以,代码可继续完善,如检测失败后对平移值进行误差范围内的增减,cv2二值化阈值进行调整等。完善后代码的可行性会更高。此外还有很多方法,如特征识别等。未来有机会学习到的话会做出来分享给大家(自己)。o(′^`)o

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:34:29  更:2021-10-09 16:35:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 3:00:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码