使用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 httplib模块使用实例
Apr 11 Python
详解Python Socket网络编程
Jan 05 Python
使用rst2pdf实现将sphinx生成PDF
Jun 07 Python
python利用正则表达式排除集合中字符的功能示例
Oct 10 Python
分享6个隐藏的python功能
Dec 07 Python
pandas.DataFrame 根据条件新建列并赋值的方法
Apr 08 Python
python定位xpath 节点位置的方法
Aug 27 Python
python 实现查询Neo4j多节点的多层关系
Dec 23 Python
Python打包工具PyInstaller的安装与pycharm配置支持PyInstaller详细方法
Feb 27 Python
Python3实现个位数字和十位数字对调, 其乘积不变
May 03 Python
Python Django中间件使用原理及流程分析
Jun 13 Python
Python高并发和多线程有什么关系
Nov 14 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
php截取后台登陆密码的代码
2012/05/05 PHP
php调用方法mssql_fetch_row、mssql_fetch_array、mssql_fetch_assoc和mssql_fetch_objcect读取数据的区别
2012/08/08 PHP
php操作xml入门之xml标签的属性分析
2015/01/23 PHP
Add a Table to a Word Document
2007/06/15 Javascript
jQuery 行级解析读取XML文件(附源码)
2009/10/12 Javascript
JavaScript中的null和undefined解析
2012/04/14 Javascript
关于删除时的提示处理(确定删除吗)
2013/11/03 Javascript
jquery插件jquery倒计时插件分享
2013/12/27 Javascript
jQuery.extend()、jQuery.fn.extend()扩展方法示例详解
2014/05/08 Javascript
javascript实现表单提交后,提交按钮不可用的方法
2015/04/18 Javascript
JS控件bootstrap suggest plugin使用方法详解
2017/03/25 Javascript
MUI实现上拉加载和下拉刷新效果
2017/06/30 Javascript
JS+HTML5实现图片在线预览功能
2017/07/22 Javascript
jQuery实现可兼容IE6的淡入淡出效果告警提示功能示例
2017/09/20 jQuery
Angularjs渲染的 using 指令的星级评分系统示例
2017/11/09 Javascript
微信小程序实现点击按钮修改文字大小功能【附demo源码下载】
2017/12/06 Javascript
在vue中获取token,并将token写进header的方法
2018/09/26 Javascript
[15:46]教你分分钟做大人——沙王
2015/03/11 DOTA
[02:05:03]完美世界DOTA2联赛循环赛 LBZS VS Matador BO2 10.28
2020/10/28 DOTA
Python中scatter函数参数及用法详解
2017/11/08 Python
Python机器学习之决策树算法实例详解
2017/12/06 Python
PyQt5内嵌浏览器注入JavaScript脚本实现自动化操作的代码实例
2019/02/13 Python
对Django 转发和重定向的实例详解
2019/08/06 Python
python异步Web框架sanic的实现
2020/04/27 Python
python 抓取知乎指定回答下视频的方法
2020/07/09 Python
英国领先的男装设计师服装购物网站:Mainline Menswear
2018/02/04 全球购物
木马的传播途径主要有哪些
2016/04/08 面试题
文员个人的求职信范文
2013/09/26 职场文书
关于礼仪的演讲稿
2014/01/04 职场文书
开学季活动策划方案
2014/02/28 职场文书
2014年社区重阳节活动策划方案
2014/09/16 职场文书
2014最新毕业证代领委托书
2014/09/26 职场文书
赞助商致辞
2015/07/30 职场文书
2015年大学组织委员个人工作总结
2015/10/23 职场文书
Vue过滤器(filter)实现及应用场景详解
2021/06/15 Vue.js
常用的Python代码调试工具总结
2021/06/23 Python