Python爬虫解决极验(geetest)滑动验证码

本文介绍用Python程序识别极验滑动验证码的验证。使用Selenium库和Chrome浏览器,通过初始化、模拟登录填写、获取并储存有无缺口的两张图片、获取缺口位置、获取移动轨迹、按轨迹拖动完成验证等步骤,实现极验管理后台登录页面的自动化登录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

滑动验证码的识别介绍

  • 本节目标:

用程序识别极验滑动验证码的验证,包括分析识别思路、识别缺口位置、生成滑块拖动路径、模拟实现滑块拼合通过验证等步骤。

  • 准备工作:

本次案例我们使用Python库是Selenium,浏览器为Chrome。请确保已安装Selenium库和ChromeDriver浏览器驱动。

  • 了解极验滑动验证码:

极验滑动验证码官网为:http://www.geetest.com/

验证方式为拖动滑块拼合图像,若图像完全拼合,则验证成功,否则需要重新验证,如图所示:
在这里插入图片描述接下来我们链接地址:https://account.geetest.com/login,打开极验的管理后台登录页面,完成自动化登录操作。

实现步骤:

① 初始化

初始化链接地址、创建模拟浏览器对象、设置登录账户和密码等信息。

EMAIL = '登录账户'
PASSWORD = '登录密码'

class CrackGeetest():
   def __init__(self):
       self.url = 'https://account.geetest.com/login'
       self.browser = webdriver.Chrome()
       #设置显示等待时间
       self.wait = WebDriverWait(self.browser, 20)
       self.email = EMAIL
       self.password = PASSWORD

   def crack():
       pass

# 程序主入口
if __name__ == '__main__':
   crack = CrackGeetest()
   crack.crack()

② 模拟登录填写,点开滑块验证

  • 在实例化CrackGeetest对象后调用crack()方法开始模拟登录验证…

  • 调用open()方法,打开登录界面,获取账户和密码输入框节点,完成账户和密码的输入。

  • 调用get_geetest_button()方法获取滑动验证按钮,并点击。

class CrackGeetest():
   #...

   def get_geetest_button(self):
       ''' 获取初始验证按钮,return:按钮对象 '''
       button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_radar_tip')))
       return button

   def open(self):
       ''' 打开网页输入用户名密码, return: None '''
       self.browser.get(self.url)
       email = self.wait.until(EC.presence_of_element_located((By.ID, 'email')))
       password = self.wait.until(EC.presence_of_element_located((By.ID, 'password')))
       email.send_keys(self.email)
       password.send_keys(self.password)

   def crack(self):
       # 输入用户名密码
       self.open()
       # 点击验证按钮
       button = self.get_geetest_button()
       button.click()
       #...
   #...

③ 获取并储存有无缺口的两张图片

  • 首先获取无缺口的验证图片,并保存到本地

  • 获取滑块对象,并执行点击,让浏览器中显示有缺口图片

  • 获取有缺口的验证图片,并保存到本地

 def get_position(self):
       ''' 获取验证码位置, return: 验证码位置(元组) '''
       img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img')))
       time.sleep(2)
       location = img.location
       size = img.size
       top,bottom,left,right = location['y'],location['y']+size['height'],location['x'],location['x']+size['width']
       return (top, bottom, left, right)

   def get_screenshot(self):
       ''' 获取网页截图, return: 截图对象 '''
       #浏览器截屏
       screenshot = self.browser.get_screenshot_as_png()
       screenshot = Image.open(BytesIO(screenshot))
       return screenshot

   def get_geetest_image(self, name='captcha.png'):
       ''' 获取验证码图片, return: 图片对象 '''
       top, bottom, left, right = self.get_position()
       print('验证码位置', top, bottom, left, right)
       screenshot = self.get_screenshot()
       #从网页截屏图片中裁剪处理验证图片
       captcha = screenshot.crop((left, top, right, bottom))
       captcha.save(name)
       return captcha

   def get_slider(self):
       ''' 获取滑块, return: 滑块对象 '''
       slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))
       return slider

   def crack(self):
       #...

       # 获取验证码图片
       image1 = self.get_geetest_image('captcha1.png')
       # 点按呼出缺口
       slider = self.get_slider()
       slider.click()
       # 获取带缺口的验证码图片
       image2 = self.get_geetest_image('captcha2.png')

       #...

④ 获取缺口位置

  • 对比两张图片的所有RBG像素点,得到不一样像素点的x值,即要移动的距离
BORDER = 6
INIT_LEFT = 60

class CrackGeetest():  
   def get_gap(self, image1, image2):
       ''' 获取缺口偏移量, 参数:image1不带缺口图片、image2带缺口图片。返回偏移量 '''
       left = 65
       for i in range(left, image1.size[0]):
           for j in range(image1.size[1]):
               if not self.is_pixel_equal(image1, image2, i, j):
                   left = i
                   return left
       return left

   def is_pixel_equal(self, image1, image2, x, y):
       '''
       判断两个像素是否相同
       :param image1: 图片1
       :param image2: 图片2
       :param x: 位置x
       :param y: 位置y
       :return: 像素是否相同
       '''
       # 取两个图片的像素点(R、G、B)
       pixel1 = image1.load()[x, y]
       pixel2 = image2.load()[x, y]
       threshold = 60
       if abs(pixel1[0]-pixel2[0])<threshold and abs(pixel1[1]-pixel2[1])<threshold and abs(pixel1[2]-pixel2[2])<threshold:
           return True
       else:
           return False

   def crack(self):
       #...

       # 获取缺口位置
       gap = self.get_gap(image1, image2)
       print('缺口位置', gap)
       # 减去缺口位移
       gap -= BORDER

⑤ 获取移动轨迹

  • 模拟人的行为习惯(先匀加速拖动后匀减速拖动),把需要拖动的总距离分成一段一段小的轨迹
def get_track(self, distance):
       '''
       根据偏移量获取移动轨迹
       :param distance: 偏移量
       :return: 移动轨迹
       '''
       # 移动轨迹
       track = []
       # 当前位移
       current = 0
       # 减速阈值
       mid = distance * 4 / 5
       # 计算间隔
       t = 0.2
       # 初速度
       v = 0

       while current < distance:
           if current < mid:
               # 加速度为正2
               a = 2
           else:
               # 加速度为负3
               a = -3
           # 初速度v0
           v0 = v
           # 当前速度v = v0 + at
           v = v0 + a * t
           # 移动距离x = v0t + 1/2 * a * t^2
           move = v0 * t + 1 / 2 * a * t * t
           # 当前位移
           current += move
           # 加入轨迹
           track.append(round(move))
       return track

   def crack(self):
       #...

       # 获取移动轨迹
       track = self.get_track(gap)
       print('滑动轨迹', track)

⑥ 按照轨迹拖动,完全验证

   def move_to_gap(self, slider, track):
       '''
       拖动滑块到缺口处
       :param slider: 滑块
       :param track: 轨迹
       :return:
       '''
       ActionChains(self.browser).click_and_hold(slider).perform()
       for x in track:
           ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
       time.sleep(0.5)
       ActionChains(self.browser).release().perform()

   def crack(self):
       #...

       # 拖动滑块
       self.move_to_gap(slider, track)

       success = self.wait.until(
           EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '验证成功'))
       print(success)

⑦ 完成登录

   def login(self):
       ''' 执行登录 return: None '''
       submit = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'login-btn')))
       submit.click()
       time.sleep(10)
       print('登录成功')

   def crack(self):
       #...

       # 失败后重试
       if not success:
           self.crack()
       else:
           self.login()

出处: bilibili

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值