Python+Selenium+Pytesseract實現圖片驗證碼識別

一、selenium截取驗證碼

import json
from io import BytesIO

import time
from test.testBefore.testDriver import driver
from test.util.test_pytesseract import recognize
from PIL import Image
import allure
import unittest

 '''
 /處理驗證碼
 '''
 # 要截圖的元素
 element = driver.find_element_by_xpath('//*[@id="imgVerifyCode"]')
 # 坐標
 x, y = element.location.values()
 # 寬高
 h, w = element.size.values()
 # 把截圖以二進制形式的數據返回
 image_data = driver.get_screenshot_as_png()
 # 以新圖片打開返回的數據
 screenshot = Image.open(BytesIO(image_data))
 # 對截圖進行裁剪
 result = screenshot.crop((x, y, x + w, y + h))
 # 顯示圖片
 # result.show()
 # 保存驗證碼圖片
 result.save('VerifyCode.png')
 # 調用recognize方法識別驗證碼
 code = recognize('VerifyCode.png')
 # 輸入驗證碼
 driver.find_element_by_xpath('//*[@id="txtcode"]').send_keys(code)
 '''
 處理驗證碼/
 '''

註意:driver是引用我自己寫的文件,可以自己隨便寫一個。識別圖片的代碼單獨放在util文件夾下面的,參考標題三的代碼,需要時引用。以上代碼定位元素都需要根據自己的項目定位元素修改。

二、安裝識別環境pytesseract+Tesseract-OCR

如果沒有輸出,又不確定你的pytesseract環境是否安裝好,可以用一張沒有幹擾的圖片識別看看能不能有輸出結果,以下樣例在我的環境中可以直接輸出識別結果8fnp

驗證識別環境是否正常

直接使用pytesseract識別圖片

001.png

text = pytesseract.image_to_string('./001.png')
print(text)

三、處理驗證碼圖片

直接截圖的驗證碼圖片存在噪點或者幹擾線等,直接使用pytesseract識別可能會沒有輸出結果,如果環境正常,但沒有輸出結果,那多半是因為圖片沒有處理好,識別不出來,可以多嘗試一些處理圖片的方式,以下代碼處理我截圖這種類似的圖片效果比較好。

圖片處理識別

對圖片處理的過程:

圖片處理過程中可以多用im.show()看看每一步處理後的圖片是不是符合預期,如果效果不好調一下參數。另外在學習過程中發現有童鞋說識別不出來把圖片使用cv2.resize()這個方法放大就能識別,可以參考Python中圖像的縮放 resize()函數的應用

實際截取的圖片

處理後的圖片

test_pytesseract.py

import pytesseract
from fnmatch import fnmatch
import cv2
import os


def clear_border(img, img_name):
    '''
    去除邊框
    '''
    h, w = img.shape[:2]
    for y in range(0, w):
        for x in range(0, h):
            # if y ==0 or y == w -1 or y == w - 2:
            if y < 2 or y > w - 2:
                img[x, y] = 255
            # if x == 0 or x == h - 1 or x == h - 2:
            if x < 1 or x > h - 1:
                img[x, y] = 255

    return img


def interference_line(img, img_name):
    '''
    幹擾線降噪
    '''

    h, w = img.shape[:2]
    # !!!opencv矩陣點是反的
    # img[1,2] 1:圖片的高度,2:圖片的寬度
    for r in range(0, 2):
        for y in range(1, w - 1):
            for x in range(1, h - 1):
                count = 0
                if img[x, y - 1] > 245:
                    count = count + 1
                if img[x, y + 1] > 245:
                    count = count + 1
                if img[x - 1, y] > 245:
                    count = count + 1
                if img[x + 1, y] > 245:
                    count = count + 1
                if count > 2:
                    img[x, y] = 255
    return img


def interference_point(img, img_name, x=0, y=0):
    """點降噪
    9鄰域框,以當前點為中心的田字框,黑點個數
    :param x:
    :param y:
    :return:
    """
    # todo 判斷圖片的長寬度下限
    cur_pixel = img[x, y]  # 當前像素點的值
    height, width = img.shape[:2]

    for y in range(0, width - 1):
        for x in range(0, height - 1):
            if y == 0:  # 第一行
                if x == 0:  # 左上頂點,4鄰域
                    # 中心點旁邊3個點
                    sum = int(cur_pixel) \
                          + int(img[x, y + 1]) \
                          + int(img[x + 1, y]) \
                          + int(img[x + 1, y + 1])
                    if sum <= 2 * 245:
                        img[x, y] = 0
                elif x == height - 1:  # 右上頂點
                    sum = int(cur_pixel) \
                          + int(img[x, y + 1]) \
                          + int(img[x - 1, y]) \
                          + int(img[x - 1, y + 1])
                    if sum <= 2 * 245:
                        img[x, y] = 0
                else:  # 最上非頂點,6鄰域
                    sum = int(img[x - 1, y]) \
                          + int(img[x - 1, y + 1]) \
                          + int(cur_pixel) \
                          + int(img[x, y + 1]) \
                          + int(img[x + 1, y]) \
                          + int(img[x + 1, y + 1])
                    if sum <= 3 * 245:
                        img[x, y] = 0
            elif y == width - 1:  # 最下面一行
                if x == 0:  # 左下頂點
                    # 中心點旁邊3個點
                    sum = int(cur_pixel) \
                          + int(img[x + 1, y]) \
                          + int(img[x + 1, y - 1]) \
                          + int(img[x, y - 1])
                    if sum <= 2 * 245:
                        img[x, y] = 0
                elif x == height - 1:  # 右下頂點
                    sum = int(cur_pixel) \
                          + int(img[x, y - 1]) \
                          + int(img[x - 1, y]) \
                          + int(img[x - 1, y - 1])

                    if sum <= 2 * 245:
                        img[x, y] = 0
                else:  # 最下非頂點,6鄰域
                    sum = int(cur_pixel) \
                          + int(img[x - 1, y]) \
                          + int(img[x + 1, y]) \
                          + int(img[x, y - 1]) \
                          + int(img[x - 1, y - 1]) \
                          + int(img[x + 1, y - 1])
                    if sum <= 3 * 245:
                        img[x, y] = 0
            else:  # y不在邊界
                if x == 0:  # 左邊非頂點
                    sum = int(img[x, y - 1]) \
                          + int(cur_pixel) \
                          + int(img[x, y + 1]) \
                          + int(img[x + 1, y - 1]) \
                          + int(img[x + 1, y]) \
                          + int(img[x + 1, y + 1])

                    if sum <= 3 * 245:
                        img[x, y] = 0
                elif x == height - 1:  # 右邊非頂點
                    sum = int(img[x, y - 1]) \
                          + int(cur_pixel) \
                          + int(img[x, y + 1]) \
                          + int(img[x - 1, y - 1]) \
                          + int(img[x - 1, y]) \
                          + int(img[x - 1, y + 1])

                    if sum <= 3 * 245:
                        img[x, y] = 0
                else:  # 具備9領域條件的
                    sum = int(img[x - 1, y - 1]) \
                          + int(img[x - 1, y]) \
                          + int(img[x - 1, y + 1]) \
                          + int(img[x, y - 1]) \
                          + int(cur_pixel) \
                          + int(img[x, y + 1]) \
                          + int(img[x + 1, y - 1]) \
                          + int(img[x + 1, y]) \
                          + int(img[x + 1, y + 1])
                    if sum <= 4 * 245:
                        img[x, y] = 0

    return img


def _get_dynamic_binary_image(filedir, img_name):
    '''
    自適應閥值二值化
    '''
    filename = './' + img_name.split('.')[0] + '-binary.png'
    img_name = filedir + '/' + filename
    im = cv2.imread(img_name)
    im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

    th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)

    return th1


def recognize(image):

    filedir = './'  # 驗證碼路徑

    for file in os.listdir(filedir):
        if fnmatch(file, image):
            img_name = file
            # 自適應閾值二值化
            im = _get_dynamic_binary_image(filedir, img_name)
            # # 去除邊框
            im = clear_border(im, img_name)
            # 對圖片進行幹擾線降噪
            im = interference_line(im, img_name)
            # 對圖片進行點降噪
            im = interference_point(im, img_name)
            filename = './' + img_name.split('.')[0] + '-interferencePoint.png'  # easy_code為保存路徑
            cv2.imwrite(filename, im)  # 保存圖片
            text = pytesseract.image_to_string(im, lang="eng",
                                               config='--psm 6 digits')  # config=digits隻識別數字
    return text

    '''
    --psm 參數含義
    0:定向腳本監測(OSD)
    1: 使用OSD自動分頁
    2 :自動分頁,但是不使用OSD或OCR(Optical Character Recognition,光學字符識別)
    3 :全自動分頁,但是沒有使用OSD(默認)
    4 :假設可變大小的一個文本列。
    5 :假設垂直對齊文本的單個統一塊。
    6 :假設一個統一的文本塊。
    7 :將圖像視為單個文本行。
    8 :將圖像視為單個詞。
    9 :將圖像視為圓中的單個詞。
    10 :將圖像視為單個字符。
    '''

到此這篇關於Python+Selenium+Pytesseract實現圖片驗證碼識別的文章就介紹到這瞭,更多相關Python圖片驗證碼識別內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: