Python使用百度OCR接口进行验证码图像识别

上次从pytesseract软件及其python库入门了OCR的图像识别, 包括图像的读取、格式转换和图像处理,也进行了验证码的识别实验,包括验证码获取、登录验证以及不同图像处理的识别效果测试,具体内容可以点击下面的链接进行阅读:Python使用pytesseract进行验证码图像识别_Cameback_Tang的博客-CSDN博客_验证码图片识别

而这次将使用来自百度的OCR识别接口,采取互联网的方式,而不是基于软件及其接口的方式。另外,它也是免费的,可直接调用,通过测试上次的无干扰的验证码,直接识别率可达99%,这比pytesseract的76%可强太多了。当然如果加了干扰的验证码,自然要处理干扰后才能提高识别率。

本次使用的OCR接口来源:文字识别_通用场景文字识别-百度AI开放平台

单纯的OCR文字识别,主要有以下四种,以“通用文字识别”为主,可通过上述链接自行了解。

代码中需要通过type参数指定对应的OCR接口,默认使用“通用文字识别接口,高精度不带位置”。

跟上次一样,我这边写成两个识别函数,即通过图像文件图像base64编码来进行识别。

 

import requests
import base64
from urllib.parse import urlencode

def get_result_by_baiduOCR(file_path):
    url = 'https://cloud.baidu.com/aidemo'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.47',
        'Content-Type': 'application/x-www-form-urlencoded',
        'Host': 'cloud.baidu.com',
        'Origin': 'https://cloud.baidu.com',
        ## 其他接口请详见https://cloud.baidu.com/product/ocr_general
        'Referer': 'https://cloud.baidu.com/product/ocr/general',  # 通用文字识别接口,高精度不带位置
        # 'Referer': 'https://cloud.baidu.com/product/ocr_others/handwriting', # 手写接口
        # 'Referer': 'https://cloud.baidu.com/product/ocr/doc_analysis_office', # 文档接口
        # 'Referer': 'https://cloud.baidu.com/product/ocr_others/webimage', # 网络图片接口
        # 'Connection':'keep-alive',
        # 'Cookie':'hadhsahjsaj',
        # # '':'',
    }
    with open(file_path, 'rb') as f:
        img_base64 = base64.b64encode(f.read())
        data = {
            'image':f'data:image/png;base64,{img_base64.decode()}',
            'image_url':'xxxxxx',
            'type':'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic',
            # 'type':'https://aip.baidubce.com/rest/2.0/ocr/v1/handwriting',
            # 'type':'https://aip.baidubce.com/rest/2.0/ocr/v1/doc_analysis_office',
            # 'type':'https://aip.baidubce.com/rest/2.0/ocr/v1/webimage',
            'detect_direction': 'false',
            # 'language_type':'CHN_ENG',
            'language_type': 'ENG',
            # 'detect_direction':False,
        }
        data = urlencode(data)
        data = data.replace('image_url=xxxxxx', 'image_url')
        html = requests.post(url, data, headers=headers)
        # print(html.text)
        # rsp = {
        #     "errno": 0,
        #     "msg": "success",
        #     "data": {
        #         "words_result": [{"words": "Pi15"}],
        #         "words_result_num": 1,
        #         "log_id": "1515968155725851265"}
        # }
        html = html.json()
        print(html)
        if html.get('errno') == 0:
            result = html.get('data').get('words_result')[0].get('words')
            result = ''.join(list(filter(str.isalnum, result)))  # 只保留字母和数字
        else:
            result = ''
    return result

def get_result_by_baiduOCR_base64(img_base64):
    url = 'https://cloud.baidu.com/aidemo'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.47',
        'Content-Type': 'application/x-www-form-urlencoded',
        'Host': 'cloud.baidu.com',
        'Origin': 'https://cloud.baidu.com',
        'Referer': 'https://cloud.baidu.com/product/ocr/general',
        # 'Connection': 'close'   # http的连接数超过最大限制,默认的情况下连接是Keep-alive的,所以这就导致了服务器保持了太多连接而不能再新建连接。
        # 'Connection':'keep-alive',
        # 'Cookie':'',
        # # '':'',
    }
    data = {
        'image':f'data:image/png;base64,{img_base64}',
        # 'image_url':'xxxxxx',
        'type':'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic',
        'detect_direction':'false',
        # 'language_type':'CHN_ENG',
        'language_type':'ENG',
    }
    data = urlencode(data)
    html = requests.post(url, data, headers=headers)
    html = html.json()
    if html.get('errno') == 0:
        result = html.get('data').get('words_result')[0].get('words')
        result = ''.join(list(filter(str.isalnum, result)))  # 只保留字母和数字
    else:
        result = ''
    return result

另外,您可能需要图像对象图像base64编码之间的转换,否则就需要保存和读取文件了。

import base64
from PIL import Image
from io import BytesIO

# image:图像对象


    def image_to_base64(image, fmt='JPEG'):
        output_buffer = BytesIO()
        image.save(output_buffer, format=fmt)
        byte_data = output_buffer.getvalue()
        base64_str = base64.b64encode(byte_data).decode('utf-8')
        return base64_str

    def base64_to_image(base64_str):
        byte_data = base64.b64decode(base64_str)
        image_data = BytesIO(byte_data)
        img = Image.open(image_data)
        return img

这里插个题外话,关于验证码获取,




# 获取验证码,保存html到图片文件
session = requests.session()
vpic_url = 'https://xxxxxxx/getVerify'
html = session.get(vpic_url, headers=headers)
with open("py016.jpeg", "wb") as f:
    f.write(html.content)
    img = Image.open("py016.jpeg")


# 获取验证码,使用selenium.webdriver和谷歌浏览器方式
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
url = 'https://xxxxxx/login'
driver = webdriver.Chrome()
driver.get(url)

img = driver.find_element_by_tag_name('img') 
img.screenshot('aaa.jpeg')  # 神来之笔,保存为图像文件
verifyCode = get_result_by_baiduOCR_base64(
    driver.find_element_by_tag_name('img').screenshot_as_base64 # 神来之笔,直接变成图像base64编码
)

这里再插个题外话,关于验证码处理,发现它们的背景干扰简直不要太一样,而且还只有一种颜色,比较淡的颜色,试下用灰度处理并二值黑白化,结果太棒了。

 采用阈值threshold为100,进行黑白二值的结果如下:

# 灰度化和其他阈值二值黑白化
def gray_processing(img, threshold = 127):
    img = img.convert('L')
    # threshold = 127 # image.convert('1')
    # threshold = 125
    lookup_table = [0 if i < threshold else 1 for i in range(256)]
    img = img.point(lookup_table, '1')
    return img


# 如果有干扰线,也可采用九宫格去噪,一次不行就两次,然后还可以膨胀腐蚀法
# 九宫格法去噪音点
def denoise(image, pixel_node):
    rows, cols = image.size
    noise_pos = []

    for i in range(1, rows-1):
        for j in range(1, cols-1):
            pixel_around = 0
            for m in range(i-1, i+2):
                for n in range(j-1, j+2):
                    if image.getpixel((m,n)) != 1:
                        pixel_around +=1
            if pixel_around <= pixel_node:
                noise_pos.append((i,j))
    for pos in noise_pos:
        image.putpixel(pos, 1)
    return image

 至此,就不插入题外话了,大概就这样吧。

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值