破解滑动验证码最新版本(97%左右通过率) 您所在的位置:网站首页 jQuery实现拼图滑块验证 破解滑动验证码最新版本(97%左右通过率)

破解滑动验证码最新版本(97%左右通过率)

2023-11-26 00:16| 来源: 网络整理| 查看: 265

一、简述:

       最近无聊想搞一下极验的滑块验证码破解这块,发现破解js代码耗时又耗力出现版本更新可能以前的所有努力都要推翻重做,不够通用性,最后还是选用selenium + PIL 来实现滑块验证码的破解。       期间也翻阅过很多文章,大多都已经失效,并且缺口位置查找和模拟滑动轨迹成功率很低,很难应用到实际开发项目中,本次是针对最新版本的极验滑块验证码进行破解。

二、项目环境

大致需要用到以下模块各位看观请提前准备好:python3.6、selenium、numpy、PIL、chromedriver

三、分析步骤以及代码编写

 

1.首先分析目标网站(本次主要以geetest官网滑块demo为参考)   

  网站大致长这个样子,首先f12打开 开发者工具选择Elements查看节点,发现最新版本的滑块图片是使用画布来进行呈现的,期间查阅大量文档,使用如下代码获得画布中的图片数据,获  取到的图片是base64进行编码的

1 document.getElementsByClassName("geetest_canvas_bg geetest_absolute")[0].toDataURL("image/png")

2.通过分析发现这两个画布放的是所需要的背景图和缺口图(其实一眼就看出来的)

3. 接下来就是代码的编写了

  3.1 首先是获得背景图和缺口图的数据

1 def get_images(self): 2 """ 3 获取验证码图片 4 :return: 图片的location信息 5 """ 6 time.sleep(1) 7 self.browser.web_driver_wait_ruishu(10, "class", 'geetest_canvas_slice') 8 fullgb = self.browser.execute_js('document.getElementsByClassName("geetest_canvas_bg geetest_' 9 'absolute")[0].toDataURL("image/png")')["value"] 10 11 bg = self.browser.execute_js('document.getElementsByClassName("geetest_canvas_fullbg geetest_fade' 12 ' geetest_absolute")[0].toDataURL("image/png")')["value"] 13 return bg, fullgb

  3.2 对数据进行解码操作并保存图片

1 def get_decode_image(self, filename, location_list): 2 """ 3 解码base64数据 4 """ 5 _, img = location_list.split(",") 6 img = base64.decodebytes(img.encode()) 7 new_im: image.Image = image.open(BytesIO(img)) 8 9 return new_im

  3.3 接下来就是计算缺口位置了(这里使用的PIL中计算两张图片的差值获得缺口位置)

def compute_gap(self, img1, img2): """计算缺口偏移 这种方式成功率很高""" # 将图片修改为RGB模式 img1 = img1.convert("RGB") img2 = img2.convert("RGB") # 计算差值 diff = ImageChops.difference(img1, img2) # 灰度图 diff = diff.convert("L") # 二值化 diff = diff.point(self.table, '1') left = 43 # 这里做了优化为减少误差 纵坐标的像素点大于5时才认为是找到 # 防止缺口有凸起时有误差 for w in range(left, diff.size[0]): lis = [] for h in range(diff.size[1]): if diff.load()[w, h] == 1: lis.append(w) if len(lis) > 5: return w

  3.4 当滑块的缺口位置找到以后就需要生成滑动轨迹(其中加20是保证在滑动时先超过缺口位置然后在慢慢还原到正确位置)

1 def ease_out_quart(self, x): 2 return 1 - pow(1 - x, 4) 3 4 def get_tracks_2(self, distance, seconds, ease_func): 5 """ 6 根据轨迹离散分布生成的数学 生成 # 参考文档 https://www.jianshu.com/p/3f968958af5a 7 成功率很高 90% 往上 8 :param distance: 缺口位置 9 :param seconds: 时间 10 :param ease_func: 生成函数 11 :return: 轨迹数组 12 """ 13 distance += 20 14 tracks = [0] 15 offsets = [0] 16 for t in np.arange(0.0, seconds, 0.1): 17 ease = ease_func 18 offset = round(ease(t / seconds) * distance) 19 tracks.append(offset - offsets[-1]) 20 offsets.append(offset) 21 tracks.extend([-3, -2, -3, -2, -2, -2, -2, -1, -0, -1, -1, -1]) 22 return tracks

  3.5 最后也就是滑动滑块到缺口位置

1 def move_to_gap(self, track): 2 """移动滑块到缺口处""" 3 slider = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_slider_button'))) 4 ActionChains(self.browser).click_and_hold(slider).perform() 5 6 while track: 7 x = track.pop(0) 8 ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform() 9 time.sleep(0.02) 10 11 ActionChains(self.browser).release().perform()

贴出完整代码(注意selenium有些方法会被极验检测到所以使用js命令直接运行的方式来达到效果)

crack.py

1 # -*-coding:utf-8 -*- 2 import base64 3 import time 4 import functools 5 import numpy as np 6 7 from tools.selenium_spider import SeleniumSpider 8 9 from selenium.webdriver import ActionChains 10 from selenium.webdriver.support import expected_conditions as EC 11 from selenium.webdriver.support.ui import WebDriverWait 12 from selenium.webdriver.common.by import By 13 import PIL.Image as image 14 from PIL import ImageChops, PngImagePlugin 15 from io import BytesIO 16 17 18 class Crack(object): 19 """ 20 解决三代极验滑块验证码 21 """ 22 def __init__(self): 23 self.url = 'https://www.geetest.com' 24 self.browser = SeleniumSpider(path="/personalwork/personal_tools_project/adbtools/chromedriver", max_window=True) 25 self.wait = WebDriverWait(self.browser, 100) 26 self.BORDER = 8 27 self.table = [] 28 29 for i in range(256): 30 if i < 50: 31 self.table.append(0) 32 else: 33 self.table.append(1) 34 35 def open(self): 36 """ 37 打开浏览器,并输入查询内容 38 """ 39 self.browser.get(self.url) 40 self.browser.get(self.url + "/Sensebot/") 41 self.browser.web_driver_wait_ruishu(10, "class", 'experience--area') 42 time.sleep(1) 43 self.browser.execute_js('document.getElementsByClassName("experience--area")[0].getElementsByTagName("div")' 44 '[2].getElementsByTagName("ul")[0].getElementsByTagName("li")[1].click()') 45 46 time.sleep(1) 47 self.browser.web_driver_wait_ruishu(10, "class", 'geetest_radar_tip') 48 49 self.browser.execute_js('document.getElementsByClassName("geetest_radar_tip")[0].click()') 50 51 def check_status(self): 52 """ 53 检测是否需要滑块验证码 54 :return: 55 """ 56 self.browser.web_driver_wait_ruishu(10, "class", 'geetest_success_radar_tip_content') 57 try: 58 time.sleep(0.5) 59 message = self.browser.find_element_by_class_name("geetest_success_radar_tip_content").text 60 if message == "验证成功": 61 return False 62 else: 63 return True 64 except Exception as e: 65 return True 66 67 def get_images(self): 68 """ 69 获取验证码图片 70 :return: 图片的location信息 71 """ 72 time.sleep(1) 73 self.browser.web_driver_wait_ruishu(10, "class", 'geetest_canvas_slice') 74 fullgb = self.browser.execute_js('document.getElementsByClassName("geetest_canvas_bg geetest_' 75 'absolute")[0].toDataURL("image/png")')["value"] 76 77 bg = self.browser.execute_js('document.getElementsByClassName("geetest_canvas_fullbg geetest_fade' 78 ' geetest_absolute")[0].toDataURL("image/png")')["value"] 79 return bg, fullgb 80 81 def get_decode_image(self, filename, location_list): 82 """ 83 解码base64数据 84 """ 85 _, img = location_list.split(",") 86 img = base64.decodebytes(img.encode()) 87 new_im: PngImagePlugin.PngImageFile = image.open(BytesIO(img)) 88 # new_im.convert("RGB") 89 # new_im.save(filename) 90 91 return new_im 92 93 def compute_gap(self, img1, img2): 94 """计算缺口偏移 这种方式成功率很高""" 95 # 将图片修改为RGB模式 96 img1 = img1.convert("RGB") 97 img2 = img2.convert("RGB") 98 99 # 计算差值 100 diff = ImageChops.difference(img1, img2) 101 102 # 灰度图 103 diff = diff.convert("L") 104 105 # 二值化 106 diff = diff.point(self.table, '1') 107 108 left = 43 109 110 for w in range(left, diff.size[0]): 111 lis = [] 112 for h in range(diff.size[1]): 113 if diff.load()[w, h] == 1: 114 lis.append(w) 115 if len(lis) > 5: 116 return w 117 118 def ease_out_quad(self, x): 119 return 1 - (1 - x) * (1 - x) 120 121 def ease_out_quart(self, x): 122 return 1 - pow(1 - x, 4) 123 124 def ease_out_expo(self, x): 125 if x == 1: 126 return 1 127 else: 128 return 1 - pow(2, -10 * x) 129 130 def get_tracks_2(self, distance, seconds, ease_func): 131 """ 132 根据轨迹离散分布生成的数学 生成 # 参考文档 https://www.jianshu.com/p/3f968958af5a 133 成功率很高 90% 往上 134 :param distance: 缺口位置 135 :param seconds: 时间 136 :param ease_func: 生成函数 137 :return: 轨迹数组 138 """ 139 distance += 20 140 tracks = [0] 141 offsets = [0] 142 for t in np.arange(0.0, seconds, 0.1): 143 ease = ease_func 144 offset = round(ease(t / seconds) * distance) 145 tracks.append(offset - offsets[-1]) 146 offsets.append(offset) 147 tracks.extend([-3, -2, -3, -2, -2, -2, -2, -1, -0, -1, -1, -1]) 148 return tracks 149 150 def get_track(self, distance): 151 """ 152 根据物理学生成方式 极验不能用 成功率基本为0 153 :param distance: 偏移量 154 :return: 移动轨迹 155 """ 156 distance += 20 157 # 移动轨迹 158 track = [] 159 # 当前位移 160 current = 0 161 # 减速阈值 162 mid = distance * 3 / 5 163 # 计算间隔 164 t = 0.5 165 # 初速度 166 v = 0 167 168 while current


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有