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文件比较示例分享
Jan 10 Python
Python命名空间详解
Aug 18 Python
使用相同的Apache实例来运行Django和Media文件
Jul 22 Python
Pandas DataFrame 取一行数据会得到Series的方法
Nov 10 Python
Python matplotlib通过plt.scatter画空心圆标记出特定的点方法
Dec 13 Python
对Django外键关系的描述
Jul 26 Python
Python中print函数简单使用总结
Aug 05 Python
python实现字符串和数字拼接
Mar 02 Python
Python应用实现双指数函数及拟合代码实例
Jun 19 Python
Python常用模块函数代码汇总解析
Aug 31 Python
python 爬虫之selenium可视化爬虫的实现
Dec 04 Python
python 使用tkinter与messagebox写界面和弹窗
Mar 20 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
解决File size limit exceeded 错误的方法
2013/06/14 PHP
如何用PHP做到页面注册审核
2017/03/02 PHP
使用jQuery避免鼠标双击的解决方案
2013/08/21 Javascript
基于jQuery+PHP+Mysql实现在线拍照和在线浏览照片
2015/09/06 Javascript
JavaScript调用传递变量参数的相关问题及解决办法
2015/11/01 Javascript
jQuery Validation PlugIn的使用方法详解
2015/12/18 Javascript
AngularJS 日期格式化详解
2015/12/23 Javascript
jQuery数据类型小结(14个)
2016/01/08 Javascript
JS查找字符串中出现次数最多的字符
2016/09/05 Javascript
jQuery序列化表单成对象的简单实现
2016/11/29 Javascript
微信小程序 两种滑动方式(横向滑动,竖向滑动)详细及实例代码
2017/01/13 Javascript
详解vue2.0的Element UI的表格table列时间戳格式化
2017/06/13 Javascript
javascript自定义事件功能与用法实例分析
2017/11/08 Javascript
PHP自动加载autoload和命名空间的应用小结
2017/12/01 Javascript
webpack搭建vue 项目的步骤
2017/12/27 Javascript
vuejs 动态添加input框的实例讲解
2018/08/24 Javascript
JavaScript随机数的组合问题案例分析
2020/05/16 Javascript
如何在vue-cli中使用css-loader实现css module
2021/01/07 Vue.js
深入理解Python 代码优化详解
2014/10/27 Python
Python中实现从目录中过滤出指定文件类型的文件
2015/02/02 Python
python reduce 函数使用详解
2017/12/05 Python
Python2和Python3之间的str处理方式导致乱码的讲解
2019/01/03 Python
使用Template格式化Python字符串的方法
2019/01/22 Python
Python批量生成幻影坦克图片实例代码
2019/06/04 Python
Scrapy框架实现的登录网站操作示例
2020/02/06 Python
Django models filter筛选条件详解
2020/03/16 Python
python实现控制台输出彩色字体
2020/04/05 Python
Python趣味实例,实现一个简单的抽奖刮刮卡
2020/07/18 Python
解决pycharm导入numpy包的和使用时报错:RuntimeError: The current Numpy installation (‘D:\\python3.6\\lib\\site-packa的问题
2020/12/08 Python
英国假发网站:Hothair
2018/02/23 全球购物
草莓网官网:StrawberryNET
2019/08/21 全球购物
俞敏洪北大演讲稿
2014/05/22 职场文书
网络文明传播志愿者活动方案
2014/08/20 职场文书
高中教师先进事迹材料
2014/08/22 职场文书
公司开业致辞
2015/07/29 职场文书
Java面试题冲刺第十五天--设计模式
2021/08/07 面试题