验证码读取与识别


思路

验证码读取一直是我很感兴趣的模块,今天就拿湖南大学的登录验证码练练手!

验证码识别

思路一:使用Pythonpytesseract库进行验证码识别

对于验证码的识别,Pythonpytesseract,然而在使用该库前,一定要先安装tesserocr软件(血的教训OVO)
在进行爬虫爬取时,发现系统报错requests.exceptions.SSLError: HTTPSConnectionPool(host='fangkong.hnu.edu.cn', port=443): Max retries exceeded with url: /api/v1/account/getimgvcode (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.")),经过一番查询后发现需要下载对应自己系统的OpenSSL的EXE安装包,在安装该安装包后问题解决。
首先咱从打卡系统抓一千张验证码图片下来测试一下正确率:

# 引入程序需要的相应包(类似C语言中的# include<stdio.h> 、include<math.h>等)
import os
from bs4 import BeautifulSoup
import time
import requests


# 定义下载函数
def download(n):
    ## 设置爬取token的网址
    url = "https://fangkong.hnu.edu.cn/api/v1/account/getimgvcode"

    ## 重定义请求头,防止被网页发现是爬虫,从而进行反爬操作
    headers = {
        "Cookie": "arccount62298=c; arccount62019=c",
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36"
    }

    ## 图片名称初始化
    num = 0

    ## 创建文件夹
    try:
        os.mkdir('./Verification Code')
    except:
        pass

    ## 转换工作路径
    os.chdir('./Verification Code')

    for i in range(n):
        ## 爬取token模块
        html = requests.get(url, headers=headers)# 这里是使用requests函数用之前重定义的请求头读取网页信息
        ### 测试代码
        print(html.text)# <class 'str'>
        token=html.text[27:59]
        #print(token)

        ## 得到验证码的链接
        urltoken = "https://fangkong.hnu.edu.cn/imagevcode?token="+token
        #print(url)

        ## 下载图片
        img = requests.get(urltoken, headers=headers).content
        name = str(num) + '.jpg'
        with open(name, 'wb') as f:
            f.write(img)
            num += 1
            print("第{}张验证码,链接为{}".format(num,urltoken))
        time.sleep(2)

download(1000)

爬取到的验证码
接下来就是使用pytesseract库进行验证码识别

from PIL import Image
import pytesseract
import os

path = "E:/Pythonworks/自动打卡/Verification Code"
for root,dirs,filename in os.walk(path):
    print("根目录:",root)
    print("文件夹:",dirs)
    print("文件名:",filename)

for path1 in filename:
    print(path1)
    path2 = "E:/Pythonworks/自动打卡/Verification Code/" + path1
    text = pytesseract.image_to_string(Image.open(path2))
    print(text)

然而,pytesseract库的识别正确率有点令人堪忧,这是识别出的一些结果,可以看到有很高的错误率

1.jpg
1861
10.jpg
a3io(识别错误)
100.jpg
未识别出
101.jpg
未识别出
102.jpg
4328
103.jpg
未识别出
104.jpg
277 F-(识别错误)
105.jpg
未识别出
106.jpg
2392.—(识别错误)
107.jpg
2660. —(识别错误)
108.jpg
096 1-—(识别错误)
109.jpg
6615

后续还会补充,未完待续!
--------------------------------------------------------------------------------------------------------------------
1月31日更新:
为了提高验证码的识别率,我们使用将彩色图片转换为灰度图的方法
灰度图:
&&&

from PIL import Image

def main():
    image = Image.open('0.jpg')
    imgry = image.convert('L')
    imgry.save('0_gray.png')

if __name__ == '__main__':
    main()

https://heart-of-engine-picture-bed-1.oss-cn-beijing.aliyuncs.com/img/loading1.gif" data-original="灰度图
我们先将图片转移到新文件夹内进行识别

from PIL import Image
import pytesseract
import os

## 定义原图像来源
path = "E:/Pythonworks/自动打卡/Verification Code"

## 转换工作路径
os.chdir('./Verification Code_Gray')

## 转灰度图
def main():
    for data in os.walk(path):
        for path1 in data[2]:# data[2]即为filename列表,详见https://www.cnblogs.com/poloyy/p/12349230.html
            num = path1.replace(".jpg", "")# 图片的序号,replace方法详见https://www.runoob.com/python/att-string-replace.html
            path2 = "E:/Pythonworks/自动打卡/Verification Code/" + path1
            image = Image.open(path2)
            imgry = image.convert('L')# 转为灰度图
            imgry.save('{}_gray.jpg'.format(num))
            path3 = "E:/Pythonworks/自动打卡/Verification Code_Gray/" + num + "_gray.jpg"# 灰度图的绝对路径
            text = pytesseract.image_to_string(Image.open(path3))
            print(path1)
            print(text)

if __name__ == '__main__':
    main()

识别效果

1.jpg
1861
10.jpg
232(识别错误)
100.jpg
未识别出
101.jpg
9627
102.jpg
4328
103.jpg
1124
104.jpg
ELT E(识别错误)
105.jpg
f3 77(识别错误)
106.jpg
2322
107.jpg
2660
108.jpg
0961
109.jpg
6615

可以看到,相较直接上手识别,这次的识别率大幅上升,不过我们还不满意,希望能达到更高的识别成功率

那么,我们将灰度图二值化
二值化:
&&&

from PIL import Image

def main():
    image = Image.open('0.jpg')
    imgry = image.convert('L')
    table = get_bin_table()
    binary = imgry.point(table, '1')
    binary.save('0_binary.png')

def get_bin_table(threshold=115):
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    return table

if __name__ == '__main__':
    main()

我们先将图片转移到新文件夹进行识别:

from PIL import Image
import pytesseract
import os

## 定义原图像来源
path = "E:/Pythonworks/自动打卡/Verification Code"

## 转换工作路径
os.chdir('./Verification Code_Binary')

## 转灰度图
def main():
    for data in os.walk(path):
        for path1 in data[2]:# data[2]即为filename列表,详见https://www.cnblogs.com/poloyy/p/12349230.html
            num = path1.replace(".jpg", "")# 图片的序号,replace方法详见https://www.runoob.com/python/att-string-replace.html,需要注意replace不会改变原字符串的内容
            path2 = "E:/Pythonworks/自动打卡/Verification Code/" + path1
            image = Image.open(path2)
            imgry = image.convert('L')# 转为灰度图
            table = get_bin_table()
            binary = imgry.point(table, '1')# 转为黑白图
            binary.save('{}_binary.jpg'.format(num))
            path4 = "E:/Pythonworks/自动打卡/Verification Code_Binary/" + num + "_binary.jpg"
            text = pytesseract.image_to_string(Image.open(path4))
            print(path1)
            print(text)

def get_bin_table(threshold=115):
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    return table

if __name__ == '__main__':
    main()

代码运行后却发生了诡异的一幕:
图片&&
识别结果:

1.jpg
未识别出
10.jpg
3:(识别错误)
100.jpg
未识别出
101.jpg
96 7(识别错误)
102.jpg
4323
103.jpg
1124
104.jpg
未识别出
105.jpg
未识别出
106.jpg
未识别出
107.jpg
未识别出
108.jpg
未识别出
109.jpg
未识别出

这是由于我们将图片二值化的思路就是设立一个阈值threshold,将大于阈值的像素变为白色,小于阈值的像素变为黑色,以此把图片的像素(灰度值)划分为两部分:0和1,例如0代表黑色,1代表白色,然后我们就可以用一串0和1组成的数字来表示一张图片。
然而,我们的阈值设置得太低了,由于大量的像素高于阈值,导致图片中的很多位置变成了白色,我们适当提高阈值。

意外收获

在使用爬虫进行爬取时,发现了一个构建随机请求头的Python库fake-useragent

学业繁忙,本栏目暂时停更

参考链接

如何实现校园疫情防控自动打卡(更新中)
F12查看headers的含义-CSDN
学习Python爬虫(四):模拟浏览器向服务器提交请求-CSDN
conda SSL错误 SSLError(“Can't connect to HTTPS URL because the SSL module is not available.解决办法-CSDN
GitHub 上有哪些比较好的验证码识别库?-知乎
[Python3 网络爬虫开发实战] 1.3.4-tesserocr 的安装
Python爬虫构建随机请求头headers
Python实例:利用pytesseract库进行图片文字识别(二)
使用python PIL库实现简单验证码的去噪
字符型图片验证码识别完整过程及Python实现


文章作者: Heart-of-engine
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Heart-of-engine !
打赏
  目录