破解极验验证码之模拟登录B站

声明:截至2019年7月5号,本人实测此程序可有效破解极验验证码,但是因为极验验证码也是不断在更新的,所以在这之后,如果你发现此程序并不能破解,也请多多包涵,此外如果大家有更好的思路,可以多多交流!

正文:

很多网站登录时都采用了极验验证码作为区分正常用户和爬虫程序的方法之一,B站正是其中的一个,只要掌握了破解的思路和方法,即使是面对不一样的网站也可以采用相似的方法进行破解。本文主要从破解思路来向大家分享破解的过程,最后后放上源码供大家参考和指正!

初探极验验证码

首次登录B站时会先输入账号和密码,点击登录时一般会调出一个滑动验证码,要求你拖动滑块到缺口处,就是下图的样子
对于我们人来说,只需要鼠标点击并拖动滑块到缺口处就可以了。但是当你使用selenium进行同样的操作将滑块直接拖动到缺口处时往往并不能成功, 这是因为服务器在你拖动的过程中会收集你的拖动信息,然后利用算法来判断你是人为拖动还是机器拖动,因为人为拖动时的速度不可能是绝对的匀速的,而利用selenium直接让滑块移动一段距离的速度是衡定的。了解这些之后,下面就跟大家分享破解的思路。

破解过程和思路

从验证过程来看只需要将滑块拖动一段距离让他刚好到达缺口处就可以了,也就是说第一个关键点在于如何获得需要滑动的距离,第二个关键点就是应该以什么样的速度去拖动滑块。

计算滑动距离

验证码本质上是由图片成,通过观察我们可以发现验证码的缺口部分是有阴影的,如果我们能同时获得带缺口和不带缺口的图片,那么我们就可以通过对比两张图片的每个像素点,找到不同的像素点,也就是阴影部分的位置,然后通过简单的计算就可以得到需要滑动的距离了。
通过使用Chrome浏览器观察点击登录后服务器返回的信息可以发现验证码主要是有以下三张图片生成的,分别是滑块、带缺口的图片以及不带缺口的图片,但是两张主要的图片都做了一定的处理,就是把图片分割成了很多块,然后打乱这些块的顺序(早期的极验验证码的图片是没有经过分割并打乱的),那么接下来我们可以通过算法把这两张图片重新合成正确的图片,然后对比计算滑动距离,这么做确实可以,但是比较麻烦,感兴趣的可以看一下知乎上 “小帅b” 的方法:小帅b破解B站验证码的方法而我要分享的是另一种更简单易懂的方法。请继续向下看

滑块

打乱的带缺口的图片

打乱的不带缺口的图片

首先要告诉大家的是我是通过截图的方法来获取两张图片的,但是正常浏览时只能看到带缺口的图片,那也就是说通过截图的方法只能获取一张带缺口的图片,无法获得不带缺口的图片,没关系,我们继续分析。
使用Chrome浏览器选中生成的验证码,然后会发现生成这几张图片的css代码如下:
注意最后一行代码的style属性为"display:none",当我把它改为"display:block"时,神奇的一幕发生了,不带缺口的图片竟然以迅雷不及掩耳的速度的突然出现,而我悬着的心也终于可以悄然落下。那么接下来的问题就变成了如何把style的属性变为"display:block"。方法就是通过selenium执行一段js代码,代码如下:

js = 'document.querySelectorAll("canvas")[3].style="display:block"'      # 大家可以根据自己要破解的网站来修改js代码
browser.execute_script(js)


带缺口的图片

不带缺口的图片

现在我们已经有了两张图片了,接下来就是逐一对比两张图片的每个像素点,不同的地方就是阴影的位置,需要注意的点是对比的部分不包括带有滑块的那些像素点,因为阴影部分不可能在那里,也就是说是从图片左边开始的某一不包括滑块的位置开始对比的。至此获取滑动距离的部分就完结了。总结一下:

获取滑动距离的步骤:

  1. 通过验证码的位置,截取第一张也就是带缺口的图片
  2. selenium执行一段js代码,不带缺口的图片出现
  3. 截取第二张不带缺口的图片
  4. 对比两张图片,获取阴影位置,计算出滑动距离

计算滑动轨迹

前面说了,直接使用selenium拖动滑块到缺口处会被服务器认为拖动的速度过于诡异(匀速)而被判定不合格,那么只要我们能模拟人的拖动过程就可以迷惑服务器,让它认为程序是人为拖动的。通常来说,人为操作是先加速,接近缺口时减速,同时可能会超过缺口位置而需要向后再拖动一小段距离,并且松开鼠标的时候可能会有一点点抖动,而造成滑块有轻微的滑动。程序模拟的过程也是如此,加速以及减速过程通过高中物理中的速度位移公式x= v0*t + 1/2*a*t*t),详细过程请大家根据后面的代码加以思考,代码部分也有详细的备注,毕竟没有思考也就没有真正的收获!关键点在于理解selenium在拖动滑块移动一段距离的时间是基本相等的,那么等于是在很多段固定的时间移动不一样的距离而模拟出加速与减速的,最后这很多段距离加起来就是需要滑动的距离。剩下的就是向后拖动一段距离,然后模拟释放时的抖动了。总结如下:

计算滑动轨迹的步骤

  1. 通过滑动距离计算出加速以及减速的轨迹,(这时的滑动距离比前面计算的要长一些,因为后面还有向后拖动一小段距离的动作,计算出的轨迹为一个轨迹列表,通过循环使selenium不断拖动列表中的每个距离)
  2. 向后拖动一小段距离
  3. 模拟释放时的抖动

只要总的距离加在一起等于或接近我们前面通过对比两张图片计算出的距离就可以了,因为即使是人为操作也是存在一定的误差的,并且计算出的距离也存在一定的误差,所以不一定非得绝对的等于。至此,破解极验验证码的思路分析就结束了,因为每个网站的验证码图片是有差异的,大家可以通过改变代码中BORDER的值来调出最适合自己要破解的网站的程序。最后,因为本人也是一个初学者,代码以及分析有不正确的地方恳请大家指正,感谢阅读!

献上代码:
使用前记得安装好相关的库

# Python3!
# 模拟登录B站,破解极验验证码from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from PIL import Image
from io import BytesIO
import time# 滑块离左边界的距离,可根据验证效果自行调整
BORDER = 7
# B站登录地址
URL = 'https://passport.bilibili.com/login'
# 登录账号(仅作为展示使用)
USER = '284992633@qq.com'
# 登录密码(仅作为展示使用)
PASSWORD = 'qq284992633'class BrackGeetest():def __init__(self):"""初始化"""self.browser = webdriver.Chrome()self.wait = WebDriverWait(self.browser,15)def open(self):"""打开初始网页:return:None"""self.browser.get(URL)self.browser.maximize_window()def close(self):"""关闭浏览器:return:None"""self.browser.close()def submit_user(self):"""提交账号:return:None"""input_user = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#login-username')))input_user.send_keys(USER)time.sleep(1)def submit_password(self):"""提交登录密码:return: None"""input_password = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#login-passwd')))input_password.send_keys(PASSWORD)time.sleep(1)def click_button_login(self):"""点击登录按钮,验证码出现:return: None"""button_login = self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#geetest-wrap > ul > li.btn-box > a.btn.btn-login')))button_login.click()time.sleep(1)def wait_img(self):"""等待验证码出现:return: None"""self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_slicebg geetest_absolute')))def get_screenshot(self):"""获取网页截图:return: 网页截图对象"""screenshot = self.browser.get_screenshot_as_png()screenshot = Image.open(BytesIO(screenshot))return screenshotdef get_position(self):"""获取验证码图片位置:return: 验证码图片位置"""img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_canvas_img')))location = img.locationsize = img.sizetop, bottom = location['y'],location['y'] + size['height']left, right = location['x'],location['x'] + size['width']return (top,bottom,left,right)def get_image(self,name):"""获取验证码图片:param name: 图片名称:return: 验证码图片"""top,bottom,left,right = self.get_position()#print('验证码位置',top,bottom,left,right)screenshot = self.get_screenshot()captcha = screenshot.crop((left,top,right,bottom))captcha.save(name + '.png')time.sleep(1)return captchadef delete_style(self):"""删除无缺口图片的style属性,执行js脚本,屏幕显示无缺口图片:return: None"""js = 'document.querySelectorAll("canvas")[3].style="display:block"'self.browser.execute_script(js)time.sleep(2)def get_slider(self):"""获取滑块:return:滑块对象"""slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'geetest_slider_button')))return sliderdef is_pixel_equal(self,img_1,img_2,x,y):"""判断两个像素是否相同:param img_1: 带缺口图片:param img_2: 不带缺口图片:param x: 位置x:param y: 位置y:return: 像素是否相同"""# 取两个图片的像素点pix_1 = img_1.load()[x,y]pix_2 = img_2.load()[x,y]threshold = 60 #阀值if abs(pix_1[0] - pix_2[0]) <threshold \and abs(pix_1[1] - pix_2[1]) <threshold \and abs(pix_1[2] - pix_2[2]) <threshold:return Trueelse:return Falsedef get_gap(self,img_1,img_2):"""获取缺口偏移量:param img_1: 带缺口图片:param img_2: 不带缺口图片:return: 缺口位置"""distance = 60   # 差不多是滑块的宽度加上滑块左边的间隙for i in range(distance,img_2.size[0]):for j in range(img_2.size[1]):if not self.is_pixel_equal(img_1,img_2,i,j):distance = ireturn distanceprint(img_2.size[0],img_2.size[1])return distancedef get_track(self,distance):"""根据偏移量获取移动轨迹:param distance: 偏移量:return: 移动轨迹"""track = []      # 移动轨迹current = 0      # 当前位移mid = distance * 3 / 5      # 减速阀值t = 0.2     # 计算间隔v = 0       # 初速度distance += 14      # 滑超过一段距离while current < distance:if current < mid:a = 1       # 加速度为正else:a = -0.5    # 加速度为负v0 = v      # 初速度v0v = v0 + a * t      # 当前速度vmove = v0 * t + 1/2 * a * t * t     # 移动距离 movecurrent += move     # 当前位移track.append(round(move))#print(track)return trackdef shake_mouse(self):"""模拟人手释放鼠标抖动:return: None"""ActionChains(self.browser).move_by_offset(xoffset=-2,yoffset=0).perform()ActionChains(self.browser).move_by_offset(xoffset=3,yoffset=0).perform()def move_to_gap(self,slider,tracks):"""拖动滑块到缺口处:param slider: 滑块:param tracks: 轨迹:return:"""back_tracks = [-1,-1,-2,-2,-3,-2,-2,-1,-1]ActionChains(self.browser).click_and_hold(slider).perform()for x in tracks:    # 正向ActionChains(self.browser).move_by_offset(xoffset=x,yoffset=0).perform()time.sleep(0.5)for x in back_tracks:   # 逆向ActionChains(self.browser).move_by_offset(xoffset=x,yoffset=0).perform()self.shake_mouse()time.sleep(0.5)ActionChains(self.browser).release().perform()def start(self):try:self.open()     # 打开B站登录页面self.submit_user()      # 输入账号self.submit_password()      # 输入密码self.click_button_login()       # 点击登录按钮,验证码出现# 进入滑动验证码的循环,成功后退出循环while True:img_1 = self.get_image(name='img_1')  # 获取带缺口的图片self.delete_style()  # 执行js代码,不带缺口的图片出现img_2 = self.get_image(name='img_2')  # 获取不带缺口的图片distance = self.get_gap(img_1, img_2) - BORDER  # 计算需要滑动的距离track = self.get_track(distance)  # 计算轨迹slider = self.get_slider()  # 捕捉滑块self.move_to_gap(slider,track)      # 拖动滑块至缺口处time.sleep(3)slider_box = self.wait.until(EC.presence_of_element_located((By.XPATH,'/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]')))if slider_box.get_attribute('class') == 'geetest_slider geetest_success':print("已完成滑动验证码验证")breakelse:print("验证失败、刷新验证码从新验证")button_refresh = self.wait.until(EC.presence_of_element_located((By.XPATH,'/html/body/div[2]/div[2]/div[6]/div/div[2]/div/a[2]')))button_refresh.click()time.sleep(1)print("已刷新验证码,再次进行验证")time.sleep(1)except:self.close()print("关闭浏览器,从新启动浏览器进行登录")time.sleep(5)self.start()print("已重新启动浏览器")if __name__ == '__main__':brack = BrackGeetest()brack.start()

破解极验验证码之模拟登录B站相关推荐

  1. 极验验证码行为模拟(成功率90%以上)

    这期我来玩一点黑科技的东西 最近有同事在搞爬虫时碰到了极验的第二代拖动式验证码,让我帮忙给研究一下. 于是乎我从极验官网下了demo在看.又通过网上其他同学的思路,大概研究出来了. 本人声明:我只是出 ...

  2. 越过验证码 selenium模拟登录B站项目实战(附源码)

    实战:selenium模拟登录B站 登录验证码处理 selenium 中的难点验证码破解因为确实没有很好的方式,一般都需要通过第三方平台实现破解,本案例中使用的是超级鹰平台(收费,大概1元30次,测试 ...

  3. 爬虫入门经典(十九) | 难度提升,破解极验验证码

      大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语-不温不火,本意是希望自己性情温和.作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己 ...

  4. 【Python爬虫系列教程 40-100】selenium结合拖拽实现极验验证码破解

    文章目录 前言 1. 破解极验验证码思路 2. B站登录界面 3. 极验缺口图和原始图的截取 4. 对比缺陷图和原始图的像素,确定拖拽的像素 5. 拖拽轨迹 6. 执行以上所有代码,实现破解B站极验验 ...

  5. 如何破解极验滑动验证码?成功率 100%!

    注:已对文章中所涉及的敏感内容,如图片/文字/URL 进行脱敏处理. 什么是"极验"? 或许你没听说过极验[1],但你很大可能使用过极验的产品.极验是首家「行为式验证」安全技术服务 ...

  6. 验证码的识别(极验验证码)

    本文介绍了几种常见的验证码类型以及它们的识别方法,包括图形验证码.极验滑动验证码.点触验证码和微博宫格验证码等.其中,针对图形验证码的识别方法是使用OCR技术,并且需要安装tesserocr库.我们可 ...

  7. 第八部分 验证码的识别(极验验证码)

    前言: 验证码是众多网站采取的反爬措施.验证码的花样也很多,主要有下面这几种类验证码: 图形验证码:数字.英文字母.混淆曲线组合成的验证码. 行为验证码:识别文字,点击与文字相符的图片验证码. 交互式 ...

  8. Day06,selenium的剩余用法、万能登录破解和爬取京东商品信息,及破解极验滑动验证码...

    一.自动登录抽屉新热榜 from selenium import webdriver import timedriver = webdriver.Chrome(r'D:\BaiduNetdiskDow ...

  9. 艺赛旗RPA验证码处理系列(三):破解极验滑动验证码

    目前艺赛旗RPA已经更新到8.0版本,可以让所有用户免费下载试用http://www.i-search.com.cn/index.html?from=line1 (复制链接下载) 一,介绍 一些网站会 ...

  10. selenium破解B站极验验证码

    最近刚接触python爬虫,跟大多数人一样网上视频+书籍的形式学习,不过有java基础,是直接跳过前几章内容,上手就是撸selenium模拟登陆知乎,过程倒是不难,这让我信心大增. 于是就想尝试有极验 ...

最新文章

  1. 【模块】ESP32CAM arduino程序下载方法及注意事项避坑笔记
  2. BZOJ2169 连边(动态规划)
  3. Android中Touch事件分析--解决HorizontalScrollView滑动和按钮事件触发问题
  4. matlab 除噪点,MATLAB应用在基于噪声检测的图像均值去噪法
  5. Java 装饰器模式详解
  6. 暴笑小笑话集----转自通信公社
  7. Kafka REST Proxy for MapR Streams入门
  8. [css] 你有使用过哪些栅格系统?都有什么区别呢?
  9. requestmapping配置页面后_SpringBoot2.0 基础案例(03):配置系统全局异常映射处理
  10. 红橙Darren视频笔记 面试题 为什么view获取宽高为0 onCreate onResume view.post源码浅析(继承activity api27)
  11. wpf 轮询mysql数据库_WPF非轮询方式实时更新数据库变化SqlDependency
  12. 内推 |阿里大文娱-数据分析(广州/北京)
  13. 公交车管理系统C语言
  14. C# PDF 静默打印
  15. excel查标准正态分布_利用Excel的NORMSDIST计算正态分布函数表
  16. delln4030安装固态硬盘_戴尔灵越怎么更换固态硬盘
  17. Learning Center Probability Map for Detecting Objects in Aerial Images 论文学习笔记
  18. 常用的SQL语句大全-单表操作
  19. 线性表的基本操作实现
  20. 深度:从 Office 365 新图标来看微软背后的设计新理念

热门文章

  1. 一文带你实现游戏中的音乐、音效设置
  2. zyf的现状 (BFS+优先队列)
  3. 鸿蒙媒体子系统解读-编码录像流程解读
  4. php中超链接怎么去下划线的,html如何去掉超链接下划线?html超链接去掉下划线的方法介绍...
  5. Kubeflow 部署采坑记录
  6. 事件修饰符(2) .prevent 阻止默认事件
  7. C++实现华氏温度转为摄氏温度
  8. 计算机算法基础_如何自学计算机专业
  9. cad文字宽度因子_CAD怎么设置中输入的文字宽度统一?
  10. api 与 implement 的区别