使用Selenium破解新浪微博的四宫格验证码

作者:回忆不说话 时间:2021-06-16 11:22:28 

在我们爬虫的时候经常会遇到验证码,新浪微博的验证码是四宫格形式。

可以采用模板验证码的破解方式,也就是把所有验证码的情况全部列出来,然后拿验证码的图片和这所有情况中的图片进行对比,然后获取验证码,再通过selenium自动拖拽点击,进行破解。

使用Selenium破解新浪微博的四宫格验证码

我们将验证码四个点标注为1234,那么所有的情况就是以下24种情况。

数字代表箭头指向:

1234213431244321
1243214331424312
1342231432144123
1324234132414132
1423241334124213
1432243134214231

所有的情况就是以上24种。我们将这24中验证码的情况放在一个文件夹内,当我们在登录的时候用获取的验证码截图去和所有的情况一一对比,然后获取完全相同的验证码,进行点击即可。代码如下:


from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.action_chains import ActionChains
import time
from PIL import Image
from io import BytesIO
from os import listdir
USERNAME = ''
PASSWORD = ''
class CrackWeiboSlide():
 def __init__(self):
   self.url = 'https://passport.weibo.cn/signin/login'
   self.browser = webdriver.Chrome()
   self.wait = WebDriverWait(self.browser,20)
   self.username = USERNAME
   self.password = PASSWORD
 def __del__(self):
   self.browser.close()
 def open(self):
   """
   打开网页输入用户名密码登录
   :return: None
   """
   self.browser.get(self.url)
   username = self.wait.until(EC.presence_of_element_located((By.ID,'loginName')))
   password = self.wait.until(EC.presence_of_element_located((By.ID,'loginPassword')))
   submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'loginAction')))
   username.send_keys(self.username)
   password.send_keys(self.password)
   submit.click()
 def get_position(self):
   """
   获取验证码的位置
   :return: 位置
   """
   try:
     img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'patt-shadow')))
   except TimeoutException:
     print('未出现验证码')
     self.open()
   time.sleep(2)
   location = img.location
   size = img.size
   top=location['y']
   bottom = location['y']+size['height']
   left = location['x']
   right = location['x']+size['width']
   return (top,bottom,left,right)
 def get_screenshot(self):
   """
   获取截图
   :return:截图
   """
   screentshot = self.browser.get_screenshot_as_png()
   # BytesIO将网页截图转换成二进制
   screentshot = Image.open(BytesIO(screentshot))
   return screentshot
 def get_image(self,name):
   """获取验证码图片"""
   top,bottom,left,right = self.get_position()
   print('验证码位置',top,bottom,left,right)
   screenshot = self.get_screenshot()
   # crop()将图片裁剪出来,后面需要一个参数
   captcha = screenshot.crop((left,top,right,bottom))
   captcha.save(name)
   return captcha
 def detect_image(self,image):
   """
   匹配图片
   :param self:
   :param image: 图片
   :return: 拖动顺序
   """
   # 图片所在的文件夹
   for template_name in listdir('templates/'):
     print('正在匹配',template_name)
     template = Image.open('templates/'+template_name)
     # 匹配图片
     if self.same_img(image,template):
       # 将匹配到的文件名转换为列表
       numbers = [int(number)for number in list(template_name.split('.')[0])]
       print('拖动顺序',numbers)
       return numbers
 def is_pixel_equal(self,image1,image2,x,y):
   """
   判断两个像素的相似度
   :param image1: 图片1
   :param image2: 图片2
   :param x: 位置x
   :param y: 位置y
   :return: 像素是否相同
   """
    # 取像素点
   pixel1 = image1.load()[x,y]
   pixel2 = image2.load()[x,y]
   # 偏差量等于60
   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 same_img(self,image,template):
   """
   识别相似的验证码
   :param image: 准备识别的验证码
   :param template: 模板
   :return:
   """
   # 相似度阈值
   threshold = 0.99
   count = 0
   # 匹配所有像素点
   for x in range(image.width):
     for y in range(image.height):
       # 判断像素
       if self.is_pixel_equal(image,template,x,y):
         count+=1
   result = float(count)/(image.width*image.height)
   if result>threshold:
     print('成功匹配')
     return True
   return False
 def move(self,numbers):
   """
   根据顺序拖动,此处接收的参数为前面的验证码的顺序列表
   :param numbers:
   :return:
   """
   # 获取四宫格的四个点
   circles = self.browser.find_elements_by_css_selector('.patt-wrap .patt-circ')
   print('-----------------',circles)
   dx = dy =0
   for index in range(4):
     circle = circles[numbers[index]-1]
     if index == 0:
       # 点击第一个点
       ActionChains(self.browser).move_to_element_with_offset(circle,circle.size['width']/2,circle.size['height']/2).click_and_hold().perform()
     else:
       # 慢慢移动
       times = 30
       for i in range(times):
         ActionChains(self.browser).move_by_offset(dx/times,dy/times).perform()
         time.sleep(1/times)
     if index == 3:
       # 松开鼠标
       ActionChains(self.browser).release().perform()
     else:
       # 计算下次的偏移
       dx = circles[numbers[index+1]-1].location['x'] - circle.location['x']
       dy = circles[numbers[index+1]-1].location['y'] - circle.location['y']
 def crack(self):
   """
   破解入口
   :return:
   """
   self.open()
   # 获取验证码图片
   image = self.get_image('captcha.png')
   numbers = self.detect_image(image)
   self.move(numbers)
   time.sleep(10)
   print('识别结束')
if __name__ == '__main__':
 crack = CrackWeiboSlide()
 crack.crack()

设置自己的账号密码即可实现。

有时候会匹配不上,图片相似度阈值达不到0.99以上,这个时候可能是我们收集的验证码图片过时了,重新开启图片收集程序,运行收集一下即可。

收集图片程序代码如下:


from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
import time
from PIL import Image
from io import BytesIO
from os import listdir
USERNAME = '18239831004'
PASSWORD = 'qweqweqwe'
class CrackWeiboSlide():
 def __init__(self):
   self.url = 'https://passport.weibo.cn/signin/login'
   self.browser = webdriver.Chrome()
   self.wait = WebDriverWait(self.browser,20)
   self.username = USERNAME
   self.password = PASSWORD
 def __del__(self):
   self.browser.close()
 def open(self):
   """
   打开网页输入用户名密码登录
   :return: None
   """
   self.browser.get(self.url)
   username = self.wait.until(EC.presence_of_element_located((By.ID,'loginName')))
   password = self.wait.until(EC.presence_of_element_located((By.ID,'loginPassword')))
   submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'loginAction')))
   username.send_keys(self.username)
   password.send_keys(self.password)
   submit.click()
 def get_position(self):
   """
   获取验证码的位置
   :return: 位置
   """
   try:
     img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'patt-shadow')))
   except TimeoutException:
     print('未出现验证码')
     self.open()
   time.sleep(2)
   location = img.location
   size = img.size
   top=location['y']
   bottom = location['y']+size['height']
   left = location['x']
   right = location['x']+size['width']
   return (top,bottom,left,right)
 def get_screenshot(self):
   """
   获取截图
   :return:截图
   """
   screentshot = self.browser.get_screenshot_as_png()
   # BytesIO将网页截图转换成二进制
   screentshot = Image.open(BytesIO(screentshot))
   return screentshot
 def get_image(self,name):
   """获取验证码图片"""
   top,bottom,left,right = self.get_position()
   print('验证码位置',top,bottom,left,right)
   screenshot = self.get_screenshot()
   # crop()将图片裁剪出来,后面需要一个参数
   captcha = screenshot.crop((left,top,right,bottom))
   captcha.save(name)
   return captcha
 # 获取所有的验证码
 def main(self):
   count = 0
   while True:
     name = str(count)+'.png'
     self.open()
     self.get_image(name)
     count+=1
if __name__ == '__main__':
 crack = CrackWeiboSlide()
 crack.main()

来源:https://blog.csdn.net/qq_39138295/article/details/82888722

标签:python,selenium,验证码
0
投稿

猜你喜欢

  • Jmail发信的实例,模块化随时调用

    2007-09-27 13:35:00
  • JS数组方法汇总

    2009-08-03 14:06:00
  • HTML在线编辑器的原理分析(整理)

    2007-12-22 10:25:00
  • innerHTML,outerHTML,innerText,outerText用法

    2008-02-15 12:22:00
  • 如何实现文本的卷屏浏览?

    2010-05-24 18:36:00
  • Cpython解释器中的GIL全局解释器锁

    2021-08-29 22:06:43
  • ASP常见数学函数 Abs Atn Cos 等详解

    2008-05-28 12:33:00
  • MySql循环插入数据

    2010-10-14 13:50:00
  • Python反射机制案例超详细讲解

    2022-08-06 16:24:53
  • php判断输入不超过mysql的varchar字段的长度范围

    2023-11-14 12:02:10
  • 页面无刷新调用数据(IFRAME+js)

    2009-06-01 11:29:00
  • Dreamweaver使用技巧--让css使网页图片半透明

    2010-09-05 21:13:00
  • MySQL性能诊断与调优工具

    2010-11-02 11:41:00
  • php生成4位数字验证码的实现代码

    2023-11-20 15:00:12
  • 960 时代的终结

    2011-01-11 19:24:00
  • python读取json文件并将数据插入到mongodb的方法

    2021-03-22 20:30:22
  • 如何改良你的CSS代码编写结构

    2008-09-29 16:03:00
  • Ubuntu下Python+Flask分分钟搭建自己的服务器教程

    2023-11-12 04:37:43
  • 用SQL语句添加删除修改字段、一些表与字段的基本操作、数据库备份等

    2011-12-01 07:53:11
  • python之线程通过信号pyqtSignal刷新ui的方法

    2022-01-03 22:28:45
  • asp之家 网络编程 m.aspxhome.com