使用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 相关文章推荐
Python2/3中urllib库的一些常见用法
Dec 19 Python
Python cookbook(数据结构与算法)在字典中将键映射到多个值上的方法
Feb 18 Python
python实现点对点聊天程序
Jul 28 Python
Django进阶之CSRF的解决
Aug 01 Python
利用python打开摄像头及颜色检测方法
Aug 03 Python
Python eval的常见错误封装及利用原理详解
Mar 26 Python
python爬虫爬取笔趣网小说网站过程图解
Nov 18 Python
pytorch ImageFolder的覆写实例
Feb 20 Python
基于python计算滚动方差(标准差)talib和pd.rolling函数差异详解
Jun 08 Python
使用python爬取抖音app视频的实例代码
Dec 01 Python
matplotlib交互式数据光标实现(mplcursors)
Jan 13 Python
python的netCDF4批量处理NC格式文件的操作方法
Mar 21 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
Yii中创建自己的Widget实例
2016/01/05 PHP
java模拟PHP的pack和unpack类
2016/04/13 PHP
PHP中register_shutdown_function函数的基础介绍与用法详解
2017/11/28 PHP
php-fpm超时时间设置request_terminate_timeout资源问题分析
2019/09/27 PHP
7个Javascript地图脚本整理
2009/10/20 Javascript
Jquery倒计时源码分享
2014/05/16 Javascript
使用ajax+jqtransform实现动态加载select
2014/12/01 Javascript
jquery利用命名空间移除绑定事件的方法
2015/03/11 Javascript
javascript连续赋值问题
2015/07/08 Javascript
jQuery实现输入框邮箱内容自动补全与上下翻动显示效果【附demo源码下载】
2016/09/20 Javascript
原生JS实现的放大镜效果实例代码
2016/10/15 Javascript
bootstrap监听滚动实现头部跟随滚动
2016/11/08 Javascript
Vue computed计算属性的使用方法
2017/07/14 Javascript
react-native中ListView组件点击跳转的方法示例
2017/09/30 Javascript
JS Testing Properties 判断属性是否在对象里的方法
2017/10/01 Javascript
JS实现二维数组横纵列转置的方法
2018/04/17 Javascript
JS加密插件CryptoJS实现的DES加密示例
2018/08/16 Javascript
JQuery实现ajax请求的示例和注意事项
2018/12/10 jQuery
Vue在 Nuxt.js 中重定向 404 页面的方法
2019/04/23 Javascript
浅谈Node 异步IO和事件循环
2019/05/05 Javascript
Vue 实现从小到大的横向滑动效果详解
2019/10/16 Javascript
[04:13]2018国际邀请赛典藏宝瓶Ⅱ饰品一览
2018/07/21 DOTA
python实现的多线程端口扫描功能示例
2017/01/21 Python
编写多线程Python服务器 最适合基础
2018/09/14 Python
pytorch程序异常后删除占用的显存操作
2020/01/13 Python
Python爬取阿拉丁统计信息过程图解
2020/05/12 Python
Django 实现 Websocket 广播、点对点发送消息的代码
2020/06/03 Python
Python爬取12306车次信息代码详解
2020/08/12 Python
Python爬虫之Selenium实现窗口截图
2020/12/04 Python
美国婴儿用品店:Babies”R”Us
2017/10/12 全球购物
对于没有初始化的变量的初始值可以作怎样的假定
2014/10/12 面试题
大学生自我鉴定
2013/12/08 职场文书
《小小雨点》教学反思
2014/02/18 职场文书
领导干部四风问题自我剖析材料
2014/09/25 职场文书
巾帼建功标兵先进事迹材料
2016/02/29 职场文书
《文化苦旅》读后感:阅读,让人诗意地栖居在大地上
2019/12/24 职场文书