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

作者:Mingyueyixi 时间:2022-08-23 06:39:23 

准备工作

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滑块验证码的思路详解(完美避开人机识别),希望对大家有所帮助!

来源:https://blog.csdn.net/Mingyueyixi/article/details/104345623

标签:python,滑块,验证码,BiliBili
0
投稿

猜你喜欢

  • mysql数据库你需要特别注意的23个事项

    2010-08-08 08:34:00
  • vue3动态路由刷新后空白或者404问题的解决

    2023-07-02 16:58:39
  • python神经网络Keras实现LSTM及其参数量详解

    2023-02-09 14:02:22
  • pycharm 实现本地写代码,服务器运行的操作

    2023-04-10 21:12:44
  • 教你用Python下载抖音无水印视频

    2022-11-18 06:08:42
  • PyHacker编写URL批量采集器

    2022-03-21 12:42:21
  • mysql中的临时表如何使用

    2024-01-28 10:19:21
  • Python使用xlrd和xlwt实现自动化操作Excel

    2021-08-24 10:54:19
  • python的多线程原来可以这样解

    2021-02-22 16:12:18
  • 在Docker上开始部署Python应用的教程

    2023-11-13 12:38:37
  • 利用Python编写简易版德州扑克小游戏

    2021-02-03 06:00:59
  • mysql 设置默认的时间值

    2024-01-18 02:49:46
  • 段正淳的css笔记(1)分类之间的横竖线

    2007-11-01 21:47:00
  • Python面向对象特殊属性及方法解析

    2022-05-19 15:16:06
  • js实现一个日期联动下拉菜单

    2007-08-04 20:49:00
  • Python基于ThreadingTCPServer创建多线程代理的方法示例

    2022-12-05 19:12:39
  • Pytorch反向求导更新网络参数的方法

    2021-02-07 11:48:52
  • MySQL数据库命令

    2024-01-17 09:27:22
  • python数据分析实战指南之异常值处理

    2023-04-19 21:02:18
  • pycharm使用正则表达式批量添加print括号完美从python2迁移到python3

    2021-11-06 15:30:35
  • asp之家 网络编程 m.aspxhome.com