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处理文本文件并生成指定格式的文件
Jul 31 Python
python使用arp欺骗伪造网关的方法
Apr 24 Python
Python的Asyncore异步Socket模块及实现端口转发的例子
Jun 14 Python
Django中使用Celery的教程详解
Aug 24 Python
解决pandas .to_excel不覆盖已有sheet的问题
Dec 10 Python
jupyter notebook 调用环境中的Keras或者pytorch教程
Apr 14 Python
python读取图像矩阵文件并转换为向量实例
Jun 18 Python
Python实现定时监测网站运行状态的示例代码
Sep 30 Python
MoviePy简介及Python视频剪辑自动化
Dec 18 Python
python爬取代理ip的示例
Dec 18 Python
python开发的自动化运维工具ansible详解
Aug 07 Python
Python实现自动玩连连看的脚本分享
Apr 04 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
曾在DC漫画界反派角色扮演的演员,谁才是你心目中的小丑之王?
2020/04/09 欧美动漫
咖啡历史、消费和行业趋势
2021/03/03 咖啡文化
php 中英文语言转换类
2011/09/07 PHP
Smarty变量用法详解
2016/05/11 PHP
php双层循环(九九乘法表)
2017/10/23 PHP
LaravelS通过Swoole加速Laravel/Lumen详解
2018/03/02 PHP
jQuery Validate 验证,校验规则写在控件中的具体实例
2014/02/27 Javascript
jQuery ui 利用 datepicker插件实现开始日期(minDate)和结束日期(maxDate)
2014/05/22 Javascript
JavaScript检查某个function是否是原生代码的方法
2014/08/20 Javascript
javascript实现复制与粘贴操作实例
2014/10/16 Javascript
js实现浏览器窗口大小被改变时触发事件的方法
2015/02/02 Javascript
jquery选择器简述
2015/08/31 Javascript
jquery实现可自动判断位置的弹出层效果代码
2015/10/12 Javascript
NodeJS实现阿里大鱼短信通知发送
2016/01/17 NodeJs
最全的Javascript编码规范(推荐)
2016/06/22 Javascript
微信小程序 引入es6 promise
2017/04/12 Javascript
详解使用angular的HttpClient搭配rxjs
2017/09/01 Javascript
vue.js整合mint-ui里的轮播图实例代码
2017/12/27 Javascript
在vue-cli项目中使用bootstrap的方法示例
2018/04/21 Javascript
Mint-UI时间组件起始时间问题及时间插件使用
2018/08/20 Javascript
使用angular-cli webpack创建多个包的方法
2018/10/16 Javascript
javascript获取select值的方法完整实例
2019/06/20 Javascript
Nodejs监控事件循环异常示例详解
2019/09/22 NodeJs
vue 查看dist文件里的结构(多种方式)
2020/01/17 Javascript
Vue获取页面元素的相对位置的方法示例
2020/02/05 Javascript
element el-table表格的二次封装实现(附表格高度自适应)
2021/01/19 Javascript
[49:08]OpTic vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python中使用中文的方法
2011/02/19 Python
使用go和python递归删除.ds store文件的方法
2014/01/22 Python
Python列表list操作符实例分析【标准类型操作符、切片、连接字符、列表解析、重复操作等】
2017/07/24 Python
python pytest进阶之fixture详解
2019/06/27 Python
Django文件上传与下载(FileFlid)
2019/10/06 Python
python3.9和pycharm的安装教程并创建简单项目的步骤
2021/02/03 Python
学生顶撞老师的检讨书
2014/09/17 职场文书
八年级数学教学反思
2016/02/17 职场文书
漫画「处刑少女的生存之道」第3卷封面公开
2022/03/21 日漫