当前位置:   article > 正文

验证码_像素缺口识别原理

像素缺口识别原理

极验滑动验证码缺口识别

极验滑动验证码缺口识别

 

感谢崔大佬的《python3网络爬虫开发实战》这本书让我开了眼界。最近学习到验证码识别这一块,发现随着网站防爬手段的不断更新,要填的坑真是越来越多,这篇文章就分享一下近段时间的填坑之旅。

首先来说一下书上的缺口识别函数,大概原理是通过两张图片的像素对比,识别像素不同的点确定缺口位置。然而这种识别方法的前提条件是必须要有两张图,一张图是不含缺口的图片,另一张则是带缺口的图片。

但由于时间原因,我接触书上的代码时,极验证网站的滑动识别机制已经更新。对的,网站上截不到第一张不带缺口的图片了,所以在我手动copy崔大佬的代码运行时结果必然是失败的。

所以我自己写了两种解决滑动验证码的方法与大家分享,希望能擦出思想的火花。

第一种方法大概不算识别方法吧,因为里面有些投机取巧的地方。

投机就投机在我偶然发现了绕过验证码可以直接登录的地方。

偶然间发现极验证那个智能验证按钮,按钮左边的小圆圈里的指针,会随着鼠标的坐标而转动,然后我就发现这个小圈圈其实就是所谓智能验证的核心。也就是只要在这个按钮加载出来后,有鼠标在周围移动时,就会被视为是人为操作;而如果是按钮加载出来后代码直接点击就会被视为爬虫,然后就会有滑动验证码来作为反爬虫的一道大坎。

所以要解决这个问题其实很简单,我能想到的就是用代码在按钮附近移动鼠标,巧妙地绕过验证。

所以我导入了py的pyautogui 模块,在确认了按钮坐标后根据坐标位置让鼠标在其周围稍微移动。

核心代码是:pyautogui.moveTo(x,y,duration=0.1)

pyautogui.moveTo(x+20,y+20,duration=5)

其中x,y为按钮的坐标,duration为移动延时。延时尽量调整在5秒左右,因为移动速度过快那个小圈圈不买账。

上面代码执行后再点击按钮就会出现如下情况(嘿嘿):

第一种解决方法真的是绝妙,绕过了复杂的缺口识别,轻而易举就完事了。

但,这似乎有点胜之不武,是男人就应该正面解决问题(钢),在别人背后偷偷插一刀不是男人的作风。所以,重点来了,第二种方法就是正面解决问题的正路!

先讲讲思路吧。

在经过一番观察后,我发现我想要找到那个缺口的位置似乎是黑乎乎的,这个黑,就成为了解决问题的切入点。

是的,基本思路就是通过像素的rgb值找出那块黑乎乎的目标位置的x坐标。

然后我展开了我的一系列仔细的观察,还能发现,那个滑块的周围的颜色似乎是固定的,

固定的橙色系(瞎说)。

下面是研究对象:

 

然后我就开始寻找这个橙色系的rgb值的浮动范围。

下面是经过一系列计算后的结果:

上面的计算包括rgb三个值的浮动范围,三个值两两相减的绝对值的浮动范围以及rgb值的比率。

后来我就把这个橙色系的rgb范围大概计算出来了:

r区间:[159,247]

g区间:[154,249]

b区间:[102,231]

abs(r-g)区间:[0,10]

abs(g-b)区间:[18,117]

计算三个值的比例我是通过rgb各值除以r值,然后取的g值和b值之和,浮动区间为:

[1.4,1.9]

有了这些数据之后就很容易能识别出滑块周围的那一圈橙色系(似乎不是很专业,嘿嘿)。

接下来就是发现滑块的位置的y坐标的那条直线必定经过缺口。

能够定位滑块边缘坐标之后,为了减少其他因素的影响,通过减少识别范围提高识别率,对上面的图进行范围缩小处理(截图)。

接下来要处理的就是如何识别出上面红框框里面的缺口的x坐标。

黑是识别的关键,也就是上面红线标注旁边的那条竖线像素rgb三值之和是图像中以x坐标为直线所有像素点rgb三个值和的最小值。

解决方法来了,也就是以x坐标划竖线,遍历计算出rgb三值之和最小的那条,然后确定x坐标,x坐标即为缺口位置。

 

如下为截取的图片:

 

 

在ps上放大分析:

 

 

大功告成!!!

  1. from io import BytesIO
  2. from PIL import Image
  3. from selenium import webdriver
  4. from selenium.webdriver.common.by import By
  5. from selenium.webdriver.support.ui import WebDriverWait
  6. from selenium.webdriver.support import expected_conditions as EC
  7. import time
  8. url = 'https://account.geetest.com/login'
  9. EMAIL = '*********'
  10. PASSWORD = '*********'
  11. def open_firefox(url,email,password):
  12. '''
  13. :param url: 极验证登录页面地址
  14. :param email: 登录账号
  15. :param password: 密码
  16. :return:
  17. '''
  18. browers=webdriver.Firefox()
  19. browers.get(url)
  20. wait=WebDriverWait(browers,10)
  21. email_block=wait.until(EC.presence_of_element_located((By.ID, 'email')))
  22. password_block=wait.until((EC.presence_of_element_located((By.ID, 'password'))))
  23. email_block.send_keys(email)
  24. password_block.send_keys(password)
  25. button =wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_radar_tip')))
  26. button.click()
  27. return browers,wait
  28. def identify_gap(browers,wait):
  29. '''
  30. :param browers: 浏览器对象
  31. :param wait: wait对象
  32. :return: 缺口位置x坐标
  33. '''
  34. #定位验证码图片
  35. small_img=wait.until(EC.presence_of_element_located((By.XPATH, '//canvas[@class="geetest_canvas_bg geetest_absolute"]')))
  36. location=small_img.location #获取图片位置,及大小
  37. size=small_img.size
  38. top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
  39. 'width'] #确定截图位置
  40. time.sleep(5)
  41. screenshot=browers.get_screenshot_as_png()
  42. screenshot = Image.open(BytesIO(screenshot))
  43. captcha = screenshot.crop((left, top, right, bottom))
  44. captcha.save(r'first.png') #保存图片
  45. first=Image.open(r'first.png')
  46. xsize,ysize=first.size
  47. pool=[] #保存符合条件的像素点的坐标信息的数据池
  48. pix=first.load()
  49. for i in range(xsize): #颜色识别区域
  50. for j in range(ysize):
  51. if 159<=(pix[i,j])[0]<=247 and 154<=(pix[i,j])[1] <=249 and 102 <=(pix[i,j])[2]<=231:
  52. if 0<=abs((pix[i,j])[0]-(pix[i,j])[1])<=10:
  53. if 18<=abs((pix[i,j])[1]-(pix[i,j])[2])<=117 :
  54. if 1.4<=(pix[i,j])[1]/(pix[i,j])[0]+(pix[i,j])[2]/(pix[i,j])[0]<=1.97:
  55. pool.append((i,j))
  56. #print(pool)
  57. x,y=(pool[0])[0],(pool[0])[1] #获取第一个符合条件的像素点的位置
  58. captcha1=screenshot.crop((left+x,top+y,right,top+y+5)) #进行截图
  59. captcha1.save(r'second.png')
  60. Pool=[] # 第二张截图根据x坐标的每一条竖线的rgb值和的数据池
  61. second=Image.open(r'second.png')
  62. Xsize,Ysize=second.size
  63. pix1=second.load()
  64. for i in range(Xsize):
  65. sum=0
  66. for j in range(Ysize):
  67. sum+=(pix1[i,j])[0]+(pix1[i,j])[1]+(pix1[i,j])[1]
  68. Pool.append((i,sum))
  69. Pool=sorted(Pool,key=lambda x:x[1]) #排序,找出rgb值得和的最低竖线的x坐标
  70. #print(Pool)
  71. return (Pool[0])[0]+x #返回偏移值
  72. if __name__=='__main__':
  73. browers,wait=open_firefox(url=url,email=EMAIL,password=PASSWORD)
  74. print(identify_gap(browers,wait))

转自:https://zhuanlan.zhihu.com/p/52705053

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/287181
推荐阅读
相关标签
  

闽ICP备14008679号