解决哔哩哔哩网站滑块验证登陆思路
  • 对于滑块,selenium可以很简单的模拟鼠标操作,但是,获取滑动的距离是这种验证破解的难点,首先,研究了B站的代码之后,发现验证是由一个叫极验的公司做的,他们传输过来的图片我发现是坐标被打乱了的一个图片,而且还有一组数据,我估计是计算图片坐标然后拼成一个完整的图片,很多人就会去研究这个坐标怎么计算的,但是我在看了他的HTML发现,最后他将计算后的完整图片加载到了canvas画布中,而且是三个画布(一个完整的,一个有缺口的,一个缺口图片),所以我们不用那么麻烦直接通过js将画布中的图片转为base64数据:

    $('.geetest_canvas_bg')[0].toDataURL('image/png')
    $('.geetest_canvas_fullbg')[0].toDataURL('image/png')
    $('.geetest_canvas_slice')[0].toDataURL('image/png')
  • 拿到数据后就简单了,我们可以通过base64模块以及OpenCV提供的imdecode方法将数据转化为OpenCV图片对象。
  • 然后就是最关键的时候了,我们先将图片转为灰度图片,然后通过scikit-image(计算图片差异模块)模块计算完整图片和有缺口的图片之间的差异,然后将差异数组通过threshold设置阈值,然后将设置完阈值的图像通过findContours函数识别轮廓,然后通过boundingRect就能得到缺口的简单轮廓数据(起始坐标x,y以及宽和高w,h),我们拿到轮廓1的x1,y1数据,然后将缺口图片做灰度处理,然后将通过numpy转为图像数组,然后通过threshold和findContours以及boundingRect函数得到轮廓2的x2,y2数据,最后x1-x2的值就是我们需要滑动的长度,最后将这个值通过selenium滑动模块就可以了,详细的设计在下面的代码中体现。

详细代码

  • image_diff.py图片处理文件

    from skimage.measure import compare_ssim
    import argparse
    import imutils
    import cv2
    import numpy as np
    from base64 import b64decode
    
    class Diff:
      def __init__(self, b1, b2, b3):
          self.imageA = cv2.imdecode(np.frombuffer(b64decode(b1), np.uint8), cv2.COLOR_RGB2BGR)
          self.imageB = cv2.imdecode(np.frombuffer(b64decode(b2), np.uint8), cv2.COLOR_RGB2BGR)
          self.imageC = cv2.imdecode(np.frombuffer(b64decode(b3), np.uint8), cv2.COLOR_RGB2BGR)
    
      def show(self):
          cv2.imshow('imga', self.imageA)
          cv2.imshow('imgb', self.imageB)
          cv2.imshow('imgc', self.imageC)
          if chr(cv2.waitKey(0)) == 'q':
              cv2.destroyAllWindows()
    
      def hOption(self):
          grayA = cv2.cvtColor(self.imageA, cv2.COLOR_BGR2GRAY)
          grayB = cv2.cvtColor(self.imageB, cv2.COLOR_BGR2GRAY)
          grayC = cv2.cvtColor(self.imageC, cv2.COLOR_BGR2GRAY)
          npArr_3 = np.array(grayC)
          return self.diff(grayA, grayB, npArr_3)
    
      def diff(self, grayA, grayB, npArr_3):
          (score, diff) = compare_ssim(grayA, grayB, full=True)
          diff = (diff * 255).astype("uint8")
          print('图片相似度为:%s' % score)
          return self.tf(diff, npArr_3)
    
      def tf(self, diff, npArr_3):
          thresh = cv2.threshold(diff, 0, 255,
                                 cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
          cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                                  cv2.CHAIN_APPROX_SIMPLE)
          cnts = cnts[1] if imutils.is_cv3() else cnts[0]
    
          img3_t = cv2.threshold(npArr_3, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    
          cnts_3 = cv2.findContours(img3_t.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
          cnts_3 = cnts_3[1] if imutils.is_cv3() else cnts_3[0]
          return self.getBr(cnts, cnts_3)
    
      def getBr(self, cnts, cnts_3):
          x1, y1, w1, h1 = cv2.boundingRect(cnts[-1])
          cv2.rectangle(self.imageA, (x1, y1), (x1 + w1, y1 + h1), (0, 0, 255), 1)
          cv2.rectangle(self.imageB, (x1, y1), (x1 + w1, y1 + h1), (0, 0, 255), 1)
          x2, y2, w2, h2 = cv2.boundingRect(cnts_3[-1])
          cv2.rectangle(self.imageC, (x2, y2), (x2 + w2, y2 + h2), (0, 0, 255), 1)
          cv2.rectangle(self.imageC, (x2, y2), (x2 + w2, y2 + h2), (0, 0, 255), 1)
          return x1 - x2
  • seleclass.py主入口文件

    # -*- coding: utf-8 -*-
    import json
    import time
    from selenium import webdriver
    from selenium.webdriver.common.action_chains import ActionChains
    from image_diff import Diff
    
    class SeleClass:
      def __init__(self, url, username, password):
          self.url = url
          self.wdc_option = webdriver.ChromeOptions()
          self.wdc_option.add_argument('--headless')
          self.wdc_option.add_argument('--disable-gpu')
          self.wdc = webdriver.Chrome(options=self.wdc_option)
          self.wdc.implicitly_wait(10)
          self.wdc.get(self.url)
          self.wdc.maximize_window()
          self.input(username, password)
    
      def input(self, username, password):
          self.wdc.find_element_by_id('login-username').send_keys(username)
          self.wdc.find_element_by_id('login-passwd').send_keys(password)
          self.mouseLogin()
    
      def mouseLogin(self):
          ActionChains(self.wdc).move_to_element(self.wdc.find_elements_by_class_name('btn-login')[0]).perform()
          ActionChains(self.wdc).click().perform()
          self.mouseMove(Diff(**self.getBase64Data()).hOption())
          self.isLogin()
    
      def doScript(self, script):
          for _ in range(10):
              try:
                  if len(self.wdc.execute_script(script)) < 3000:
                      print('错误数据大小:%s' % len(self.wdc.execute_script(script)), end='\\t')
                      raise BaseException()
                  return self.wdc.execute_script(script)
              except:
                  time.sleep(1)
          raise BaseException('拉取数据超时')
    
      def mouseMove(self, long):
          print('鼠标移动位移为:%s' % long)
          ActionChains(self.wdc).click_and_hold(
              self.wdc.find_elements_by_class_name('geetest_slider_button')[0]).perform()
          ActionChains(self.wdc).move_by_offset(long, 0).perform()
          time.sleep(1)
          ActionChains(self.wdc).release().perform()
    
      def getBase64Data(self):
          bg = self.doScript("return $('.geetest_canvas_bg')[0].toDataURL('image/png')")[22::]
          full = self.doScript("return $('.geetest_canvas_fullbg')[0].toDataURL('image/png')")[22::]
          slice = self.doScript("return $('.geetest_canvas_slice')[0].toDataURL('image/png')")[22::]
          print('真实数据大小:', len(bg), len(full), len(slice))
          return {
              'b1': bg,
              'b2': full,
              'b3': slice
          }
    
      def isLogin(self):
          for _ in range(10):
              if self.wdc.get_cookie('DedeUserID'):
                  self.wdc.get('' + self.wdc.get_cookie('DedeUserID')['value'])
                  print('登陆成功:%s' % self.wdc.find_element_by_id('h-name').text)
                  return
              else:
                  time.sleep(1)
          raise BaseException('页面跳转超时')
    
      def __del__(self):
          time.sleep(2)
          self.wdc.close()
    
    if __name__ == '__main__':
      s = SeleClass('', 'username', 'password')

效果展示

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇