【爬虫】8.1. 使用OCR技术识别图形验证码

使用OCR技术识别图形验证码

文章目录

  • 使用OCR技术识别图形验证码
    • 1. OCR技术
    • 2. 准备工作
      • 2.1. tesserocr安装异常
    • 3. 验证码图片爬取
    • 4. 无障碍识别测试
    • 5. 错误识别
    • 6. 识别实战:
    • 7. 参数设置

图形验证码是最早出现的验证方式,现在依然很常见,一般由4位左右的字母或者数字组成。本章节使用的网站时https://captcha7.scrape.center/,这个网站的验证码相对来说比较平整,没有过多的干扰线和干扰点,文字也没有大幅度的变形和旋转,因此比较好作为案例进行分析,对于这类验证码,可以使用OCR技术识别。参考书籍依然是Python3网络爬虫开发实战(第三版)。

1. OCR技术

OCR,即Optical Character Recognition,中文叫做光学字符识别,是指使用电子设备(例如扫描仪和数码相机)检查打印再纸上的字符,通过检查暗、亮的模式确定字符形状,然后使用字符识别方法将形状转化位计算机文字。现在OCR技术已经广泛应用于生产活动中,如文档识别,证件识别,字幕识别,文档搜索等。当然用来识别本节所述的图形验证码也没有问题。

2. 准备工作

再本节的学习中需要导入tesserocr库,这个库的安装需要参考https://setup.scrape.center/tesserocr.另外,还需要安装Selenium、Pillow、Numpy和retrying库用来模拟登录、处理图像和重试操作,可以使用pip3工具安装这些库。 安装好这些库就可以开始了。

2.1. tesserocr安装异常

如果安装异常的话就换一个,可以参照我的,我用的库不是上面的,而是pytesseract,我觉得两者差别不大

  • 打开tesseract下载的网页 tesseract,下载最后一个(应该是)tesseract-ocr-w64-setup-v5.3.0.2.221214这个版本,接着就是安装,安装过程中自己记好自己安装在哪里!!!然后就是选择语言包,建议不要全选会下载很慢。
  • 将你记下来的安装路径的整个文件地址给添加到环境变量中去。
  • 接着python安装pytesseract,找到pytesseract.py文件,打开并找到tesseract_cmd这个变量(大约在30行左右)将里面的值修改为tesseract.exe文件的地址(这个文件在你一开始记下的文件地址里面,查找文件夹就找到了,不用进其他的文件夹,注意转义字符)。
  • 搞定上述之后在cmd窗口运行tesseract --list-langs可以看到你下载的语言包。
  • 重启,然后运行你的示例代码就行了,如果还不可以,那你去看其他下载教程

3. 验证码图片爬取

这个网页使用JavaScript渲染出来的,所以我们进行爬取的时候使用selenium自动化测试工具。

from selenium import webdriver
from selenium.webdriver.common.by import By
from PIL import Image
from io import BytesIO
import time

def demo():
    browser = webdriver.Chrome()
    browser.get("https://captcha7.scrape.center")
    time.sleep(3)
    captcha = browser.find_element(By.CSS_SELECTOR,"#captcha")
    image = Image.open(BytesIO(captcha.screenshot_as_png))
    image.show()

if __name__ == "__main__":
    demo()

这里使用了我很少见的BytesIO,这是一个类,它的功能是读取二进制数据流,而图片就是二进制数据流;还有就是captcha.screenshot_as_png这部分的功能就是将当前页面的内容捕获为一张图像,以bytes二进制数据保存;最后调用image的show方法来显式验证码的图像。

4. 无障碍识别测试

首先我们选用两张图片来进行测试,第一张是有换行和明显空格,第二张是一张验证码。
在这里插入图片描述
在这里插入图片描述

我们运行下面代码:

import pytesseract
from PIL import Image
image1 = Image.open("tesseract_tt1.png")
result1 = pytesseract.image_to_string(image1)
image2 = Image.open("tesseract_tt2.png")
result2 = pytesseract.image_to_string(image2)
print(result1, end= '')
print("=========")
print(result2, end= '')
Demons
Lin
Ss ZzTU
=========
2034

我们可以看到在输出SZTU这部分时候出现了SsZz这样大小写都输出的情况,这是因为pytesseract库在识别大小写字母时候很难准确识别出大小写,你可以采取其他办法来执行,这里就不列出来。

5. 错误识别

我选取到了一张图片,如下所示:
在这里插入图片描述

import pytesseract
from PIL import Image
image = Image.open("error.png")
result = pytesseract.image_to_string(image)
print(result, end= '')
04-8 d.

可以看到这个输出结果明显不是我们想要的,这是因为OCR识别技术是通过检查暗、亮的模式确定字符形状,不是我们想当然的用脑子来看。所以,我们需要做一些额外处理,把干扰信息去掉,我们观察发现,图片里哪些造成干扰的点,其颜色大多比文本的颜色更浅,因此可以通过颜色将干扰点去掉。首先将保存的图片转化为数组,看一下维度:

from PIL import Image
import numpy as np
image = Image.open("error.png")
print(np.array(image).shape)
print(image.mode)
(38, 112, 4)
RGBA

从结果上可以看出,这个图片其实是一个三维数组,38和112代表图片的高和宽,4则是每个像素点的表示向量,那为什么是4呢?因为最后一维是一个长度为4的数组分别表示R(红)G(绿)B(蓝)A(透明度),即一个像素点由4个数字表示。那为什么是RGBA而不是RGB或者其他的呢?因为image.mode是RGBA,即由透明通道的真彩色。

mode属性定义了图片的类型和像素的位宽,一共由9种类型:

  • 1:像素用1位表示,Python中表示为True或False,即二值化。
  • L:像素用8位表示,取值位0-255,表示灰度图像,数字越小,颜色越黑。
  • P:像素用8位表示,即调色板数据。
  • RGB:像素用3X8位表示,即真彩色。
  • RGBA:像素用4X8位标识,即有透明通道的真彩色。
  • CMYK:像素用4X8位表示,即印刷四色模式。
  • YCbCr:像素用3X8位表示,即彩色视频格式。
  • I:像素用32位整型表示。
  • F:像素用32位浮点型表示。

为了方便处理,可以把RGBA转化位更简单的L,即把图片转化位灰度图像。往图片对象的convert方法中传入L即可,代码如下表示:

image = image.convert('L')
image.show()

我们选择把图片转化位灰度图像,然后根据阈值删除图片上的干扰点,成功识别出验证码,代码如下:

from PIL import Image
import numpy as np

image = Image.open("error.png")
image = image.convert('L')
threshold = 90
array = np.array(image)
array = np.where(array> threshold, 255, 0)
image = Image.fromarray((array.astype('uint8')))
# image.show()
result = pytesseract.image_to_string(image)
print(result)

这里先将变量threshold赋值位50.它代表灰度的阈值。接着将图片转化位Numpy数组,利用Numpy的where方法对数组进行筛选和处理,其中将灰度大于阈值的图片的像素设置为255表示白色,否则为0,表示黑色。

6. 识别实战:

import time
import re
import pytesseract
from selenium import webdriver
from io import BytesIO
from PIL import Image
from retrying import retry
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
import numpy as np


def preprocess(image):
    image = image.convert('L')
    array = np.array(image)
    array = np.where(array > 105, 255, 0)
    image = Image.fromarray(array.astype('uint8'))
    return image


@retry(stop_max_attempt_number=10, retry_on_result=lambda x: x is False)
def login():
    browser.get('https://captcha7.scrape.center/')
    browser.find_element(By.CSS_SELECTOR, '.username input[type="text"]').send_keys('admin')
    browser.find_element(By.CSS_SELECTOR, '.password input[type="password"]').send_keys('admin')
    captcha = browser.find_element(By.CSS_SELECTOR,'#captcha')
    image = Image.open(BytesIO(captcha.screenshot_as_png))
    image = preprocess(image)
    image.show()
    captcha = pytesseract.image_to_string(image)
    print(captcha)
    captcha = re.sub('[^A-Za-z0-9]', '', captcha)
    browser.find_element(By.CSS_SELECTOR, '.captcha input[type="text"]').send_keys(captcha)
    browser.find_element(By.CSS_SELECTOR, '.login').click()
    try:
        WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH, '//h2[contains(., "登录成功")]')))
        time.sleep(5)
        browser.close()
        return True
    except TimeoutException:
        return False


if __name__ == '__main__':
    browser = webdriver.Chrome()
    login()

7. 参数设置

在使用 pytesseract 时,你可以使用以下参数:

  1. lang: 这个参数用于指定 OCR 使用的语言。默认为 ‘eng’,表示英文。如果你的验证码是英文的,那么你可以保持这个默认值。如果验证码是其他语言的,你需要指定相应的语言代码。例如,中文的语言代码是 ‘chi_sim’。
  2. config: 这个参数用于指定 tesseract 的配置文件。你可以使用它来调整 OCR 的行为。例如,你可以设置 tesseract 只识别数字和大写字母。
  3. nice: 这个参数用于指定 OCR 的质量。值的范围是 0-3,0 表示最快但质量最低,3 表示最慢但质量最高。默认值是 0。如果你的验证码很难识别,你可能需要将这个值设为 3。

这些参数可以在调用 pytesseract.image_to_string 时通过关键字参数的方式指定。例如:

captcha = pytesseract.image_to_string(image, lang='chi_sim', config='--psm 10', nice=3)

另外,你也可以使用 pytesseract.image_to_data 函数,它比 image_to_string 更灵活。image_to_data 函数返回一个包含了 OCR 结果的数据结构,你可以从这个数据结构中提取你需要的信息。例如,你可以提取每个单词的置信度,然后只保留置信度高的单词。

还有其他的识别技巧可以学习,这里给出CSDN博客我觉得挺好的一篇:

借助Tesseract-OCR进行文本检测(1)

借助Tesseract-OCR进行文本检测(2)

你可能感兴趣的:(爬虫,ocr,python,tesseract)