Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)


Posted in Python onFebruary 17, 2020

准备工作

B站登录页 https://passport.bilibili.com/login
python3
pip install selenium (webdriver框架)
pip install PIL (图片处理)
chrome driver:http://chromedriver.storage.googleapis.com/index.html
firefox driver:https://github.com/mozilla/geckodriver/releases

Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)

B站的滑块验证码如上。

这类验证码可以使用 selenium 操作浏览器拖拽滑块来进行破解,难点两个,一个如何确定拖拽到的位置,另一个是避开人机识别(反爬虫)。

确定滑块验证码需要拖拽的位移距离

有三种方式

  • 人工智能机器学习,确定滑块位置
  • 通过完整图片与缺失滑块的图片进行像素对比,确定滑块位置
  • 边缘检测算法,确定位置

各有优缺点。人工智能机器学习,确定滑块位置,需要进行训练,比较麻烦,也可以看是否存在在线api可以调用。以下介绍其他两种方式。

对比完整图片与缺失滑块的图片

| 仅介绍,本文不进行实现。对于B站来说,是准确率最高的方式(100%),但不能保证未来B站的滑块验证升级,导致不可用。

B站的滑块验证模块,一共有三张图片:

完整图、缺失滑块图、滑块图,都是由画布绘制出的。类似于:

完整图:

Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)

缺失滑块图:

Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)

滑块图:

Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)

HTML代码类似于:

<div class="geetest_canvas_img geetest_absolute" style="display: block;">
<div class="geetest_slicebg geetest_absolute">
	<canvas class="geetest_canvas_bg geetest_absolute" height="160" width="260"></canvas>
	<canvas class="geetest_canvas_slice geetest_absolute" width="260" height="160"></canvas>
</div>
<canvas class="geetest_canvas_fullbg geetest_fade geetest_absolute" height="160" width="260" style="display: none;"></canvas>
</div>

只需要通过selenium获取画布元素,执行js拿到画布像素,遍历完整图和缺失滑块图的像素,一旦获取到差异(需要允许少许像素误差),像素矩阵x轴方向即是滑块位置。
另外由于滑块图距离画布坐标原点有距离,还需要减去这部分距离。
最后使用 selenium 拖拽即可。

边缘检测算法,确定位置

| 滑块基本上是个方形,通过算法确定方形起始位置即可。

Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)

介绍两种方式

  • 滑块是方形的,存在垂直的边,该边在缺失滑块图中基本都是灰黑的。遍历像素找到基本都是灰黑的边即可。
  • 缺失滑块图中滑块位置是灰黑封闭的。通过算法可以找到封闭区域,大小与滑块相近,即是滑块需要拖拽到的位置。

第二种实现起来有些复杂,不进行实现了。

下面是第一种实现方式,会存在检测不出或错误的情况,使用时需要换一张验证码。也可能存在检测出的边是另一条(因为B站的滑块不是长方形,存在弧形边),那么需要减去滑块宽度

class VeriImageUtil():

 def __init__(self):
  self.defaultConfig = {
   "grayOffset": 20,
   "opaque": 1,
   "minVerticalLineCount": 30
  }
  self.config = copy.deepcopy(self.defaultConfig)

 def updateConfig(self, config):
  # temp = copy.deepcopy(config)
  for k in self.config:
   if k in config.keys():
    self.config[k] = config[k]

 def getMaxOffset(self, *args):
  # 计算偏移平均值最大的数
  av = sum(args) / len(args)

  maxOffset = 0
  for a in args:
   offset = abs(av - a)
   if offset > maxOffset:
    maxOffset = offset
  return maxOffset

 def isGrayPx(self, r, g, b):
  # 是否是灰度像素点,允许波动offset
  return self.getMaxOffset(r, g, b) < self.config["grayOffset"]

 def isDarkStyle(self, r, g, b):
  # 灰暗风格
  return r < 128 and g < 128 and b < 128

 def isOpaque(self, px):
  # 不透明
  return px[3] >= 255 * self.config["opaque"]

 def getVerticalLineOffsetX(self, bgImage):
  # bgImage = Image.open("./image/bg.png")
  # bgImage.im.mode = 'RGBA'
  bgBytes = bgImage.load()

  x = 0
  while x < bgImage.size[0]:
   y = 0
   # 点》》线,灰度线条数量
   verticalLineCount = 0
   if x == 258:
    print(y)
   while y < bgImage.size[1]:
    px = bgBytes[x, y]
    r = px[0]
    g = px[1]
    b = px[2]
    # alph = px[3]
    # print(px)
    if self.isDarkStyle(r, g, b) and self.isGrayPx(r, g, b) and self.isOpaque(px):
     verticalLineCount += 1
    else:
     verticalLineCount = 0
     y += 1
     continue

    if verticalLineCount >= self.config["minVerticalLineCount"]:
     # 连续多个像素都是灰度像素,直线
     # print(x, y)
     return x

    y += 1

   x += 1
  pass


if __name__ == '__main__':
 bgImage = Image.open("./image/bg.png")
 veriImageUtil = VeriImageUtil()

 # veriImageUtil.updateConfig({
 #  "grayOffset": 20,
 #  "opaque": 0.6,
 #  "minVerticalLineCount": 10
 # })
  bgOffsetX = veriImageUtil.getVerticalLineOffsetX(bgImage)
 print("bgOffsetX:{} ".format(bgOffsetX))

总结

以上所述是小编给大家介绍的Python破解BiliBili滑块验证码的思路详解(完美避开人机识别),希望对大家有所帮助!

Python 相关文章推荐
使用python提取html文件中的特定数据的实现代码
Mar 24 Python
python实用代码片段收集贴
Jun 03 Python
每天迁移MySQL历史数据到历史库Python脚本
Apr 13 Python
python 重定向获取真实url的方法
May 11 Python
python将txt文件读入为np.array的方法
Oct 30 Python
Python OpenCV实现鼠标画框效果
Aug 19 Python
Django之路由层的实现
Sep 09 Python
基于Python新建用户并产生随机密码过程解析
Oct 08 Python
用Python可视化新冠疫情数据
Jan 18 Python
pytorch分类模型绘制混淆矩阵以及可视化详解
Apr 07 Python
python多次执行绘制条形图
Apr 20 Python
Python sklearn分类决策树方法详解
Sep 23 Python
Tensorflow 实现将图像与标签数据转化为tfRecord文件
Feb 17 #Python
将自己的数据集制作成TFRecord格式教程
Feb 17 #Python
tensorflow 实现数据类型转换
Feb 17 #Python
Django Haystack 全文检索与关键词高亮的实现
Feb 17 #Python
python使用docx模块读写docx文件的方法与docx模块常用方法详解
Feb 17 #Python
python itsdangerous模块的具体使用方法
Feb 17 #Python
django-crontab实现服务端的定时任务的示例代码
Feb 17 #Python
You might like
星际争霸任务指南——虫族
2020/03/04 星际争霸
php 攻击方法之谈php+mysql注射语句构造
2009/10/30 PHP
使用配置类定义Codeigniter全局变量
2014/06/12 PHP
基于Codeigniter框架实现的student信息系统站点动态发布功能详解
2017/03/23 PHP
基于PHP实现发微博动态代码实例
2020/12/11 PHP
jquery之Document元素选择器篇
2008/08/14 Javascript
JavaScript 浏览器验证代码(来自discuz)
2010/07/17 Javascript
jQuery提交多个表单的小例子
2013/06/30 Javascript
js中浮点型运算BUG的解决方法说明
2014/01/06 Javascript
jQuery调用RESTful WCF示例代码(GET方法/POST方法)
2014/01/26 Javascript
详谈javascript中DOM的基本属性
2015/02/26 Javascript
JS闭包、作用域链、垃圾回收、内存泄露相关知识小结
2016/05/16 Javascript
基于JavaScript实现鼠标向下滑动加载div的代码
2016/08/31 Javascript
js中获取键盘事件的简单实现方法
2016/10/10 Javascript
JavaScript中捕获与冒泡详解及实例
2017/02/03 Javascript
Web开发使用Angular实现用户密码强度判别的方法
2017/09/27 Javascript
vue 实现 ios 原生picker 效果及实现思路解析
2017/12/06 Javascript
解决npm管理员身份install时出现权限的问题
2018/03/16 Javascript
vue页面切换项目实现转场动画的方法
2019/11/12 Javascript
小程序api实现promise封装过程解析
2019/11/21 Javascript
解决vue组件没显示,没起作用,没报错,但该显示的组件没显示问题
2020/09/02 Javascript
js实现石头剪刀布游戏
2020/10/11 Javascript
Python中的下划线详解
2015/06/24 Python
解决每次打开pycharm直接进入项目的问题
2018/10/28 Python
python实现给scatter设置颜色渐变条colorbar的方法
2018/12/13 Python
wxpython绘制音频效果
2019/11/18 Python
Agoda.com官方网站:便宜预订全球酒店,高达80%的折扣
2018/04/04 全球购物
Jones Bootmaker官网:优质靴子和鞋子在线
2020/11/30 全球购物
经理秘书岗位职责
2013/11/14 职场文书
舞蹈比赛获奖感言
2014/02/04 职场文书
《最佳路径》教学反思
2014/04/13 职场文书
教师作风建设剖析材料
2014/10/11 职场文书
市委常委会班子党的群众路线教育实践活动整改方案
2014/10/25 职场文书
2014年党小组工作总结
2014/12/20 职场文书
三八红旗手主要事迹材料
2015/11/04 职场文书
Python中相见恨晚的技巧
2021/04/13 Python