Mac + Python + Selenium之获取验证码图片code并进行登录

Posted Owen_ET

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mac + Python + Selenium之获取验证码图片code并进行登录相关的知识,希望对你有一定的参考价值。

 初稿代码,可以忽略不计(自己留着看)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/01/15 13:27
# @Author  : zc
# @File    : 115test.py



from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance
import pytesseract

imgPath1 = "/Users/zhangc/zh/111/test/img/识别失败图片.png"
imgPath = "/Users/zhangc/zh/111/test/img/img.png"
driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")

def remove(string):
    return string.replace(" ","")


def open(code):
    url = \'http://192.168.2.213:9100\'

    driver.get(url)
    driver.maximize_window()
    login(code)


def login(code):
    if (code == "") | (len(remove(code)) != 4):
        getCodeImg()
    else:
        # 输入用户名
        telephone = driver.find_element(By.NAME,"telephone")
        telephone.clear()
        telephone.send_keys("13642040631")
        # 输入密码
        password = driver.find_element(By.NAME,"password")
        password.clear()
        password.send_keys("123456")
        # 输入验证码
        code_loc = driver.find_element(By.NAME,"code")
        code_loc.clear()
        code_loc.send_keys(code)
        # 点击登录按钮
        button = driver.find_element(By.XPATH,"//button[@type=\'button\']")
        button.click()
        try:
            # 后台获取验证码校验内容
            text1 = driver.find_element(By.CSS_SELECTOR, ".el-message__content").text
            print(text1)
            while text1 == "":
                button.click()
                text1
            # 前台获取验证码校验内容
            text2 = driver.find_element(By.CSS_SELECTOR, ".el-el-form-item__error").text
            print(text2)

            if text1 == "验证码不正确":
                print("验证码不正确")
                driver.find_element(By.XPATH, "//div[@class=\'divIdentifyingCode\']/img").click()
                getCodeImg()
                code2 = test()
                login(code2)
            elif text2 == "请输入正确的验证码":
                print("请输入正确的验证码")
                driver.find_element(By.XPATH, "//div[@class=\'divIdentifyingCode\']/img").click()
                getCodeImg()
                code2 = test()
                login(code2)
            else:
                print("登陆成功!")
        except:
            print("进入首页!!!!")
            pass


def getCodeImg():
    \'\'\'获取code图片\'\'\'
    size2 = driver.get_window_size()
    print("页面的总size:"+str(size2))
    img_el = driver.find_element(By.XPATH,"//div[@class=\'divIdentifyingCode\']/img")
    # 获取图片的坐标
    location = img_el.location
    print("页面坐标点的size:"+str(location))
    # 获取图片的大小
    size = img_el.size
    print("验证码的size:"+str(size))
    left = location[\'x\']/size2[\'width\']
    top = location[\'y\']/size2[\'height\']
    right = (location[\'x\'] + size[\'width\'])/size2[\'width\']
    bottom = (location[\'y\'] + size[\'height\'])/size2[\'height\']
    print(left,top,right,bottom)

    # 截图操作
    driver.get_screenshot_as_file(imgPath)
    imgSize = Image.open(imgPath).size
    print("截图的size:"+str(imgSize))

    sleep(2)

    img = Image.open(imgPath).crop((left*imgSize[0],
                                    top*imgSize[1]+100,
                                    right*imgSize[0]+20,
                                    bottom*imgSize[1]+150))
    img = img.convert(\'L\')             #转换模式:L | RGB
    img = ImageEnhance.Contrast(img)#增强对比度
    img = img.enhance(2.0)             #增加饱和度
    img.save(imgPath)




def test():

    img2 = Image.open(imgPath)
    code = pytesseract.image_to_string(img2).strip()
    print("=============输出的验证码为:"+remove(code))
    while (code == "") | (len(remove(code)) != 4):

        # 重新获取验证码
        driver.find_element(By.XPATH, "//div[@class=\'divIdentifyingCode\']/img").click()
        getCodeImg()
        img2 = Image.open(imgPath)
        code = pytesseract.image_to_string(img2).strip()

        if code == "":
            print("code获取为空值=================")
            continue
        elif len(remove(code)) != 4:
            print("code获取不是4位数字=============")
            continue
        else:
            print("识别成功!")
            # break
        break
    print("=============输出的验证码为:" + remove(code))
    return remove(code)


if __name__ == \'__main__\':
    code = ""
    open(code)
    code1 = test()
    login(code1)






# 页面的总size:{\'width\': 1206, \'height\': 1129}
# 页面坐标点的size:{\'x\': 961, \'y\': 518}
# 验证码的size:{\'height\': 28, \'width\': 70}
# 0.796849087893864 0.4588131089459699 0.8548922056384743 0.48361381753764393
# 截图的size:(2412, 1950)
View Code

====================下面看正文=========================

之前有个问题一直在困扰着我,如何获取验证码的值

后来查询大神们的文章得知:

用pytesseract库来读取图片的文字。

先安装两个库:

# python有着更加优雅的方式调用系统的tesseract工具,首先安装pytesseract模块;pytesseract是对tesseract的封装,要和PIL联合使用

# 安装pytesseract
sudo pip install pytesseract

# 安装图片处理器PIL
pip install pillow

好了接下来看看我是怎么一步一步实现的吧

第一步、保存验证码图片

 

核心代码:

getCodeImg()方法

import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance

class LoginCode(object):

    # 用户名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密码框元素
    password_loc = (By.NAME,"password")
    # 验证码框元素
    code_loc = (By.NAME,"code")
    # 登录按钮元素
    button_loc = (By.XPATH,"//button[@type=\'button\']")
    # 验证码图片元素
    img_el_loc = (By.XPATH, "//div[@class=\'divIdentifyingCode\']/img")
    # 验证码错误提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")

    def find_element(self,*loc):
        # 实验得知方法中的参数loc↑加上*,定位会更稳定
        \'\'\'定位单个元素\'\'\'

        return self.driver.find_element(*loc)

   # 核心代码↓
def getCodeImg(self): \'\'\'获取验证码图片\'\'\' # 验证码图片的元素定位 img_el = self.find_element(*self.img_el_loc) # 获取整个浏览器的size chromeSize = self.driver.get_window_size() print("页面的总size:"+str(chromeSize))
# 页面的总size:{\'width\': 1202, \'height\': 1129} # 获取图片的坐标 self.location = img_el.location print("页面坐标点的size:"+str(self.location))
     # 页面坐标点的size:{\'x\': 959, \'y\': 518} x:指的图片左边距;y:指的图片上边距
# 获取图片的大小 imgSize = img_el.size print("验证码的size:"+str(imgSize))
   # 验证码的size:{\'height\': 28, \'width\': 70}
     # 左边距占整个浏览器的百分比
     left = self.location[\'x\']/chromeSize[\'width\']
     # 上边距占整个浏览器的百分比
        top = self.location[\'y\']/chromeSize[\'height\']                           

     # 右边距占整个浏览器的百分比 right = (self.location[\'x\'] + imgSize[\'width\'])/chromeSize[\'width\']

     # 下边距占整个浏览器的百分比 bottom = (self.location[\'y\'] + imgSize[\'height\'])/chromeSize[\'height\']

    print(left,top,right,bottom)
     # 0.7978369384359401 0.4588131089459699 0.8560732113144759 0.48361381753764393 # 浏览器截屏操作 self.driver.get_screenshot_as_file(self.imgPath) screenshotImgSize = Image.open(self.imgPath).size print("截图的size:"+str(screenshotImgSize))
     # 截图的size:(2404, 1950) 宽:2404,高:1950 sleep(2) # 从文件读取截图,截取验证码位置再次保存 img = Image.open(self.imgPath).crop(( # left*screenshotImgSize[0], # top*screenshotImgSize[1]+100, # right*screenshotImgSize[0]+20, # bottom*screenshotImgSize[1]+150
       # 左边距百分比*截图的高≈截图左边距,再加上微调的距离+350
            left * screenshotImgSize[1]+350,                
       # 上边距百分比*截图的高≈截图左边距,再加上微调的距离-100 top * screenshotImgSize[0]-100,
       # 右边距百分比*截图的宽≈截图上边距,再加上微调的距离+400 right * screenshotImgSize[1]+400,
       # 下边距百分比*截图的高≈截图右边距,再加上微调的距离-50 bottom * screenshotImgSize[0]-50 )) img = img.convert(\'L\') # 转换模式:L | RGB img = ImageEnhance.Contrast(img) # 增强对比度 img = img.enhance(2.0) # 增加饱和度 img.save(self.imgPath) # 再次保存图片

获取页面中验证码图片的截图:

第二步、循环获取验证码截图的code

为什么要循环获取呢,一次获取不就可以了吗,原因是图片识别文字不准确,经常会识别为空或者不是4位数的值

所以要循环做判断,下面上代码:

 

核心方法是:

①getCode():先获取图片code值

②loopGetCode():如果获取的code值不符合条件,循环判断获取正确的图片code值

import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance



class LoginCode(object):

    # 用户名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密码框元素
    password_loc = (By.NAME,"password")
    # 验证码框元素
    code_loc = (By.NAME,"code")
    # 登录按钮元素
    button_loc = (By.XPATH,"//button[@type=\'button\']")
    # 验证码图片元素
    img_el_loc = (By.XPATH, "//div[@class=\'divIdentifyingCode\']/img")
    # 验证码错误提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")


    def remove(self,string):
        \'\'\'字符串去除空格\'\'\'

        return string.replace(" ","")


    def find_element(self,*loc):
        # 实验得知方法中的参数loc↑加上*,定位会更稳定
        \'\'\'定位单个元素\'\'\'

        return self.driver.find_element(*loc)

   # 核心代码↓
def getCode(self): \'\'\'获取图片的code\'\'\' # 再次读取识别验证码 img = Image.open(self.imgPath) code = pytesseract.image_to_string(img).strip() print("=============输出的验证码为:" + self.remove(code)) return code
   # 核心代码↓
def loopGetCode(self): \'\'\'循环判断获取正确的图片code\'\'\' code = self.remove(self.getCode()) # 循环前获取code字数 codeNumBf = len(code) # 如果获取图片的code值为空或者不满足4位数进行循环 while (code == "") | (codeNumBf != 4): # 重新获取验证码 self.find_element(*self.img_el_loc).click() self.getCodeImg() # 获取验证码图片 code = self.remove(self.getCode()) # 循环后获取code字数 codeNumAf = len(code) if code == "": print("code获取为空值=================") continue elif codeNumAf != 4: print("code获取不是4位数字=============") continue else: print("识别成功!") # 识别成功退出循环 break print("=============输出的验证码为:" + code) # 输出满足条件的code return code

三、进行登录操作并判断验证码正确性

为什么登陆操作时还要判断验证码正确性呢,因为还是图片识别文字不准确虽然识别出4位数但是并不是验证码图片中的值,所以需要再次判断,如果验证码错误就重新获取验证码的值。

 

核心代码:

login():登录操作

import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance



class LoginCode(object):

    # 用户名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密码框元素
    password_loc = (By.NAME,"password")
    # 验证码框元素
    code_loc = (By.NAME,"code")
    # 登录按钮元素
    button_loc = (By.XPATH,"//button[@type=\'button\']")
    # 验证码图片元素
    img_el_loc = (By.XPATH, "//div[@class=\'divIdentifyingCode\']/img")
    # 验证码错误提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")


    def open(self):
        \'\'\'打开浏览器\'\'\'

        url = \'http://192.168.2.213:9100\'
        self.driver.get(url)
        self.driver.maximize_window()
        self.driver.implicitly_wait(10)
        # 获取验证码图片
        self.getCodeImg()

   # 核心代码↓
    def login(self,code):
        \'\'\'进行登录操作\'\'\'

        # 输入用户名
        telephone = self.find_element(*self.telephone_loc)
        telephone.clear()
        telephone.send_keys("13642040631")
        # 输入密码
        password = self.find_element(*self.password_loc)
        password.clear()
        password.send_keys("123456")
        # 输入验证码
        code_loc = self.find_element(*self.code_loc)
        code_loc.clear()
        code_loc.send_keys(code)
        # 点击登录按钮
        button = self.find_element(*self.button_loc)
        button.click()
        sleep(0.5)
        try:
            # 后台获取验证码校验内容
            codeErrMsg = self.find_element(*self.codeErrMsg_loc).text
            print("打印后台:"+codeErrMsg)
            if codeErrMsg == "验证码不正确":
                print("验证码不正确111")
                self.find_element(*self.img_el_loc).click()
                self.getCodeImg()
                self.loopGetCode_action()
            else:
                print("登陆成功!")
        except:
            print("进入首页!!!!")
            pass

   # 核心相关代码↓
    def loopGetCode_action(self):
        \'\'\'循环验证code的正确性\'\'\'

        resultCode = self.loopGetCode()
        self.login(resultCode)

   # 核心相关代码↓
    def login_action(self):
        \'\'\'执行验证码登录操作\'\'\'

        # 打开浏览器并获取验证码图片
        self.open()
        self.loopGetCode_action()

以上三步就是完整获取图片文字的方法了,虽然有点多但是都是必不可少的步骤。

==========================================================

注:需要安装tesseract,不然会提示:

# CHANGE THIS IF TESSERACT IS NOT IN YOUR PATH, OR IS NAMED DIFFERENTLY
pytesseract.pytesseract.TesseractNotFoundError: tesseract is not installed or it\'s not in your path

未找到tesseract的路径,需要进入pytesseract.py文件

 

# Mac安装tesseract
brew install --with-training-tools tesseract

# 查看版本
tesseract -v

tesseract 4.0.0
 leptonica-1.77.0
  libgif 5.1.4 : libjpeg 9c : libpng 1.6.36 : libtiff 4.0.10 : zlib 1.2.11 : libwebp 1.0.2 : libopenjp2 2.3.0
 Found AVX2
 Found AVX
 Found SSE

# 查看安装路径
which tesseract
/usr/local/bin/tesseract

 ==========================================================

下面上完整代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/01/15 13:27
# @Author  : zc
# @File    : 115test.py


import pytesseract
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from PIL import Image,ImageEnhance



class LoginCode(object):

    # 用户名框元素
    telephone_loc = (By.NAME,"telephone")
    # 密码框元素
    password_loc = (By.NAME,"password")
    # 验证码框元素
    code_loc = (By.NAME,"code")
    # 登录按钮元素
    button_loc = (By.XPATH,"//button[@type=\'button\']")
    # 验证码图片元素
    img_el_loc = (By.XPATH, "//div[@class=\'divIdentifyingCode\']/img")
    # 验证码错误提示元素
    codeErrMsg_loc = (By.CSS_SELECTOR, ".el-message__content")

    imgPath = "/Users/zhangc/zh/111/test/img/img.png"
    driver = webdriver.Chrome("/Users/zhangc/zh/111/test/chromedriver")


    def remove(self,string):
        \'\'\'字符串去除空格\'\'\'

        return string.replace(" ","")


    def find_element(self,*loc):
        # 实验得知方法中的参数loc↑加上*,定位会更稳定
        \'\'\'定位单个元素\'\'\'

        return self.driver.find_element(*loc)


    def open(self):
        \'\'\'打开浏览器\'\'\'

        url = \'http://192.168.2.213:9100\'
        self.driver.get(url)
        self.driver.maximize_window()
        self.driver.implicitly_wait(10)
        # 获取验证码图片
        self.getCodeImg()


    def getCodeImg(self):
        \'\'\'获取验证码图片\'\'\'

        # 验证码图片的元素定位
        img_el = self.find_element(*self.img_el_loc)
        # 获取整个浏览器的size
        chromeSize = self.driver.get_window_size()
        print("页面的总size:"+str(chromeSize))               
        # 页面的总size:{\'width\': 1202, \'height\': 1129}
        
        # 获取图片的坐标
        self.location = img_el.location
        print("页面坐标点的size:"+str(self.location

以上是关于Mac + Python + Selenium之获取验证码图片code并进行登录的主要内容,如果未能解决你的问题,请参考以下文章

selenium+python在mac环境上的搭建转载

mac下selenium+python环境搭建

Selenium 之 Mac 环境下 Python 安装 selenium 踩坑记录

Mac python+selenium 环境配置

MAC 配置 python + selenium

Mac上Python3+selenium2环境搭建