004python+selenium+opencv滑块验证

一.内容简介:

  实现对QQ自动模拟登录,以及解决滑块验证。

二.模块描述:

  (1).qq_login.py:主程序
  (2).test_distance.py:定位滑块,获取x轴方向
  (3).info.json:个人账户(json数据格式)

三.实现:

  (1)分析url:https://i.qq.com/;F12调试打开
  (2)问题一:关于iframe框架作用域问题,会影响接下来定位不到元素。
  (3)问题二:关于iframe多层跳入与跳出问题,会影响接下来定位不到滑块元素。


代码一:

import os
import re
import sys
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
import time
import json
from parsel import Selector
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from test_distance import get_distance


class QQLogin(object):
    def __init__(self):
        self.bw = webdriver.Chrome()

    def get_qq_page(self, url):
    	# 创建brower对象
        bw = self.bw
        # 全窗口显示
        bw.maximize_window()
        bw.get(url)
        # 跳过作用域
        bw.switch_to.frame('login_frame')
        # page = bw.page_source
        # 定位选择使用账号密码登录
        swither_login = WebDriverWait(bw, 10, 0.5).until(EC.presence_of_element_located((By.ID, "switcher_plogin")))
        swither_login.click()
        # 获取个人用户信息(账号,密码)
        with open('info.json', 'r', encoding="utf-8") as fr:
            account = json.load(fr)
        # 定位账号输入框
        user_area = WebDriverWait(bw, 5, 0.5).until(EC.presence_of_element_located((By.ID, "u")))
        user_area.click()
        bw.find_element_by_id('u').send_keys(account["username"])
        # 定位密码输入框
        pwd_area = WebDriverWait(bw, 5, 0.5).until(EC.presence_of_element_located((By.ID, "p")))
        pwd_area.click()
        bw.find_element_by_id('p').send_keys(account["pwd"])
        # 点击登录
        login_submit = WebDriverWait(bw, 5, 0.5).until(EC.presence_of_element_located((By.ID, "login_button")))
        time.sleep(1)
        login_submit.click()
        # 跳出iframe框架,到最外层
        bw.switch_to.default_content()
        # 定位下一个iframe2框架
        iframe2 = bw.find_element_by_css_selector(".login_wrap > iframe")
        # 跳进指定iframe2框架
        bw.switch_to.frame(iframe2)
        time.sleep(1)
        # 跳进指定iframe3框架
        iframe3 = bw.find_element_by_css_selector('#newVcodeIframe > iframe')
        bw.switch_to.frame(iframe3)
        time.sleep(1)

NO.1
在这里插入图片描述
NO.2
在这里插入图片描述


代码二:
  前提是已经解决iframe问题。主要获取滑块背景图和滑块图

    def get_area_img(self, brower):
        # 定位滑块元素,获取滑块图片
        slide_block = brower.find_element_by_id("slideBlock")
        # 截图保存图片
        slide_block.screenshot('./tag_img.png')
		# 获取滑块图片的url
        bg_img_url = brower.find_element_by_xpath('//img[@id="slideBg"]').get_attribute('src')
        # print(bg_img)
        options = webdriver.ChromeOptions()
        # 设置无头浏览,以防关闭上一个窗口
        options.add_argument('--headless')
        bw2 = webdriver.Chrome(options=options)
        bw2.get(bg_img_url)
        # print(brower.page_source)
        # 滑块图定位
        bg_img = bw2.find_element_by_css_selector('body > img')
        bg_img.screenshot('./bg_img.png')

NO.1:滑块背景图
在这里插入图片描述
NO.2:滑块图片
在这里插入图片描述


代码三:
  展示目录
在这里插入图片描述

  test_distance.py

import cv2


def detail_img(old_bg_img):
    bg_img1 = cv2.imread(old_bg_img)
    # 修改图片尺寸
    bg_img_res = cv2.resize(bg_img1, (280, 163), )
    # 保存修改后的图片
    cv2.imwrite('bg_img_res.png', bg_img_res)


def get_distance(bg_image, slider_image):
    detail_img('./bg_img.png')
    bg_img = cv2.imread(bg_image)
    slider_img = cv2.imread(slider_image)
    # cv2.GaussianBlur: https://www.freesion.com/article/2473908556/
    # 高斯滤波,(9,9)高斯内核:都必须为正数和奇数,也可以为零
    bg_gus = cv2.GaussianBlur(bg_img, (9, 9), 0)
    slider_guas = cv2.GaussianBlur(slider_img, (3, 3), 0)
    # 识别图片边缘
    # 127表示最小阈值,260表示最大阈值,用于进一步删选边缘信息(可以自己调试)
    bg_edge = cv2.Canny(bg_gus, 127, 260)
    slider_edge = cv2.Canny(slider_guas, 127, 255)
    # RGB模式是(255,0,0),BGR模式是(0,0,255)
    bg_img_gray = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    slider_img_gray = cv2.cvtColor(slider_edge, cv2.COLOR_GRAY2RGB)
    # 显示处理后的图片
    # cv2.imshow('v1', bg_img_gray)
    # cv2.imshow('v2', slider_img_gray)
    # 在滑块背景图中匹配滑块。参数cv.TM_CCOEFF_NORMED是opencv中的一种归一化相关系数匹配法
    res = cv2.matchTemplate(bg_img_gray, slider_img_gray, cv2.TM_CCOEFF_NORMED)
    # min_val, max_val:矩阵最大值最小值
    # min_loc, max_loc:索引最小值,最大值
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    # x轴坐标
    tl = max_loc
    th, tw = slider_img_gray.shape[:2]
    br = (tl[0]+tw, tl[1]+th)
    # 方框标记,可以在‘out.png’图片查看标记
    cv2.rectangle(bg_img, tl, br, (0, 0, 255), 1)
    cv2.imwrite('out.png', bg_img)
    # print(min_val, max_val, min_loc, max_loc)
    cv2.waitKey(0)
    # print(tl[0])
    return tl[0]


if __name__ == '__main__':
    get_distance('./bg_img_res.png', './tag_img.png')

NO.1:边缘检测结果图
在这里插入图片描述
NO.2:标记结果图(红色方框是自己生成的):
在这里插入图片描述


代码四(完整):
# -*- coding:utf8 -*-
import os
import re
import sys
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
import time
import json
from parsel import Selector
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from test_distance import get_distance


class QQLogin(object):
    def __init__(self):
        self.bw = webdriver.Chrome()
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
            'Connection': 'keep-alive',
            'Host': 'aegis.qq.com'
        }

    def get_qq_page(self, url):
        bw = self.bw
        bw.maximize_window()
        bw.get(url)
        # 跳过作用域
        bw.switch_to.frame('login_frame')
        # page = bw.page_source
        swither_login = WebDriverWait(bw, 10, 0.5).until(EC.presence_of_element_located((By.ID, "switcher_plogin")))
        swither_login.click()
        with open('info.json', 'r', encoding="utf-8") as fr:
            account = json.load(fr)
        user_area = WebDriverWait(bw, 5, 0.5).until(EC.presence_of_element_located((By.ID, "u")))
        user_area.click()
        bw.find_element_by_id('u').send_keys(account["username"])
        pwd_area = WebDriverWait(bw, 5, 0.5).until(EC.presence_of_element_located((By.ID, "p")))
        pwd_area.click()
        bw.find_element_by_id('p').send_keys(account["pwd"])
        # 点击登录
        login_submit = WebDriverWait(bw, 5, 0.5).until(EC.presence_of_element_located((By.ID, "login_button")))
        time.sleep(1)
        login_submit.click()
        # 跳出上层的iframe框架
        bw.switch_to.default_content()
        iframe2 = bw.find_element_by_css_selector(".login_wrap > iframe")
        # 跳进指定iframe2框架
        bw.switch_to.frame(iframe2)
        time.sleep(1)
        # 跳进指定iframe3框架
        iframe3 = bw.find_element_by_css_selector('#newVcodeIframe > iframe')
        bw.switch_to.frame(iframe3)
        time.sleep(1)

        self.get_area_img(bw)
        self.get_distance(bw)

    def get_area_img(self, brower):
        # # 获取去全图图片
        # full_img_screen = brower.get_screenshot_as_png()
        # # 左上(左上节点), 右下(右下节点)
        # cut_info = (774, 161, 1054, 320)
        # # 将图片转成二进制流形式
        # full_img = Image.open(BytesIO(full_img_screen))
        # # 二进制流截图
        # cut_img = full_img.crop(cut_info)
        # # 保存区域截图
        # cut_img.save("./yz.png")

        # 定位滑块元素,获取滑块图片
        slide_block = brower.find_element_by_id("slideBlock")
        slide_block.screenshot('./tag_img.png')

        bg_img_url = brower.find_element_by_xpath('//img[@id="slideBg"]').get_attribute('src')
        # print(bg_img)
        options = webdriver.ChromeOptions()
        options.add_argument('--headless')
        bw2 = webdriver.Chrome(options=options)
        bw2.get(bg_img_url)
        # print(brower.page_source)
        # 背景图定位
        bg_img = bw2.find_element_by_css_selector('body > img')
        bg_img.screenshot('./bg_img.png')

    def get_distance(self, brower):
        # 获取距离
        distance = get_distance('./bg_img_res.png', './tag_img.png')
        # 定位按钮
        slider_block = WebDriverWait(brower, 10, 0.5).until(EC.presence_of_element_located((By.ID, "slideBlock")))
        # 创建动作链
        action = webdriver.ActionChains(brower)
        action.click_and_hold(slider_block).perform()
        page = brower.page_source
        element = Selector(page)
        # 获取slideBlock css样式
        slideBlock_style = element.css('#slideBlock::attr("style")').get()
        slideBlock_left_val = re.findall(r'left: (\d+|\d+.\d+)px;', slideBlock_style)[0]
        print(distance, slideBlock_left_val)
        diff_distance = float(int(distance) - int(slideBlock_left_val))
        action.move_by_offset(diff_distance, 0)
        action.release().perform()

    def main(self):
        self.get_qq_page('https://i.qq.com/')


if __name__ == '__main__':
    qq_login = QQLogin()
    qq_login.main()

备注:有些图片未能识别滑块缺口,导致不能自动登录。( 仅供学习使用,违法必究!)
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值