Python+Selenium+Pytesseract实现图片验证码识别

作者:Python可乐呀 时间:2023-08-17 11:44:01 

一、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

Python+Selenium+Pytesseract实现图片验证码识别

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

三、处理验证码图片

直接截图的验证码图片存在噪点或者干扰线等,直接使用pytesseract识别可能会没有输出结果,如果环境正常,但没有输出结果,那多半是因为图片没有处理好,识别不出来,可以多尝试一些处理图片的方式,以下代码处理我截图这种类似的图片效果比较好。

图片处理识别

对图片处理的过程:

图片处理过程中可以多用im.show()看看每一步处理后的图片是不是符合预期,如果效果不好调一下参数。另外在学习过程中发现有童鞋说识别不出来把图片使用cv2.resize()这个方法放大就能识别,可以参考Python中图像的缩放 resize()函数的应用

实际截取的图片

Python+Selenium+Pytesseract实现图片验证码识别

处理后的图片

Python+Selenium+Pytesseract实现图片验证码识别

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 :将图像视为单个字符。
   '''

来源:https://www.cnblogs.com/sn520/p/15777998.html

标签:Python,验证码,识别
0
投稿

猜你喜欢

  • Tornado高并发处理方法实例代码

    2022-10-13 15:30:07
  • Python牛刀小试密码爆破

    2021-10-05 14:18:47
  • Oracle 存储过程总结(一、基本应用)

    2009-07-07 10:21:00
  • 详解python requests中的post请求的参数问题

    2023-09-20 07:50:40
  • Golang实现简易的rpc调用

    2024-04-25 15:07:55
  • 如何判断字段的类型?

    2010-01-18 20:48:00
  • python如何提升爬虫效率

    2021-12-17 22:18:24
  • 解决Navicat for MySQL 连接 MySQL 报2005错误的问题

    2024-01-16 13:13:26
  • JavaScript每天必学之事件

    2024-04-22 13:08:43
  • Python注释、分支结构、循环结构、伪“选择结构”用法实例分析

    2021-01-15 14:45:25
  • MySql数据库备份的几种方式

    2024-01-17 03:15:05
  • Python利用OpenCV和skimage实现图像边缘检测

    2023-01-27 01:08:43
  • Git分支合并冲突解决的方法实现

    2023-12-08 08:41:47
  • Python实现从订阅源下载图片的方法

    2021-08-14 19:19:37
  • mysql5.6.zip格式压缩版安装图文教程

    2024-01-17 20:13:53
  • vue实现移动端图片裁剪上传功能

    2024-05-10 14:15:04
  • css样式表滤镜全接触

    2007-10-26 12:48:00
  • python访问系统环境变量的方法

    2023-06-16 00:30:39
  • OpenCV半小时掌握基本操作之分水岭算法

    2023-04-10 11:24:51
  • vuex中...mapstate和...mapgetters的区别及说明

    2023-07-02 16:33:53
  • asp之家 网络编程 m.aspxhome.com