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


Posted in Python onOctober 19, 2018

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

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

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

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

数字代表箭头指向:

1234 2134 3124 4321
1243 2143 3142 4312
1342 2314 3214 4123
1324 2341 3241 4132
1423 2413 3412 4213
1432 2431 3421 4231

所有的情况就是以上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()

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

Python 相关文章推荐
python多线程编程中的join函数使用心得
Sep 02 Python
研究Python的ORM框架中的SQLAlchemy库的映射关系
Apr 25 Python
python单元测试unittest实例详解
May 11 Python
Windows中安装使用Virtualenv来创建独立Python环境
May 31 Python
详解python3实现的web端json通信协议
Dec 29 Python
python使用pil进行图像处理(等比例压缩、裁剪)实例代码
Dec 11 Python
Python3.6实现连接mysql或mariadb的方法分析
May 18 Python
python3中zip()函数使用详解
Jun 29 Python
使用Pyinstaller转换.py文件为.exe可执行程序过程详解
Aug 06 Python
详解python列表(list)的使用技巧及高级操作
Aug 15 Python
Python中filter与lambda的结合使用详解
Dec 24 Python
基于logstash实现日志文件同步elasticsearch
Aug 06 Python
Selenium的使用详解
Oct 19 #Python
Python爬取成语接龙类网站
Oct 19 #Python
将Django项目部署到CentOs服务器中
Oct 18 #Python
python中将zip压缩包转为gz.tar的方法
Oct 18 #Python
Python 忽略warning的输出方法
Oct 18 #Python
解决python通过cx_Oracle模块连接Oracle乱码的问题
Oct 18 #Python
解决python3捕获cx_oracle抛出的异常错误问题
Oct 18 #Python
You might like
PHP4引用文件语句的对比
2006/10/09 PHP
php INI配置文件的解析实现分析
2011/01/04 PHP
php中常量DIRECTORY_SEPARATOR用法深入分析
2014/11/14 PHP
浅谈本地WAMP环境的搭建
2015/05/13 PHP
jquery nth-child()选择器的简单应用
2010/07/10 Javascript
两种方法实现文本框输入内容提示消失
2013/03/17 Javascript
深入理解javascript动态插入技术
2013/11/12 Javascript
绑定回车enter事件代码
2014/05/18 Javascript
JavaScript中number转换成string介绍
2014/12/31 Javascript
javascript中sort() 方法使用详解
2015/08/30 Javascript
jQuery绑定事件监听bind和移除事件监听unbind用法实例详解
2016/01/19 Javascript
基于Bootstrap的UI扩展 StyleBootstrap
2016/06/17 Javascript
Web打印解决方案之证件套打的实现思路
2016/08/29 Javascript
Angularjs根据json文件动态生成路由状态的实现方法
2017/04/17 Javascript
Vue computed计算属性的使用方法
2017/07/14 Javascript
解决低版本的浏览器不支持es6的import问题
2018/03/09 Javascript
js操作table中tr的顺序实现上移下移一行的效果
2018/11/22 Javascript
React优化子组件render的使用
2019/05/12 Javascript
Vue CLI3创建项目部署到Tomcat 使用ngrok映射到外网
2019/05/16 Javascript
vue 表单输入框不支持focus及blur事件的解决方案
2020/11/17 Vue.js
[05:39]2014DOTA2西雅图国际邀请赛 淘汰赛7月14日TOPPLAY
2014/07/14 DOTA
Python中pow()和math.pow()函数用法示例
2018/02/11 Python
python3处理含有中文的url方法
2018/05/10 Python
Python函数装饰器常见使用方法实例详解
2019/03/30 Python
Django继承自带user表并重写的例子
2019/11/18 Python
在django中使用post方法时,需要增加csrftoken的例子
2020/03/13 Python
Python绘图之二维图与三维图详解
2020/08/04 Python
Windows环境下Python3.6.8 importError: DLLload failed:找不到指定的模块
2020/11/01 Python
HTML5 video标签(播放器)学习笔记(二):播放控制
2015/04/24 HTML / CSS
欧洲最大的化妆品连锁公司:Douglas道格拉斯
2017/05/06 全球购物
考试退步检讨书
2014/01/15 职场文书
偷看我的初中毕业鉴定
2014/01/29 职场文书
人力资源管理专业求职信
2014/07/23 职场文书
2015年电话销售工作总结范文
2015/04/20 职场文书
Pytorch 如何实现LSTM时间序列预测
2021/05/17 Python
SQL Server中搜索特定的对象
2022/05/25 SQL Server