背景

        正在做的爬虫项目,其中需要使用ocr的功能去识别验证码。所以就使用了paddlocr,结果没想到后期这么大个坑。好在想到一个方法可能规避这个打包的问题。

        写这一篇文章主要是记录下在打包有paddlocr的时候的问题,及规避方法。方便给看到这篇博客及有同样问题的网友提供一个思路。

目录

一、出错情况

        1.1、多线程的问题

        1.2、路径下文件找不到的问题

        1.3、设置paddle libs路径问题

        1.4、ModuleNotFoundError: No module named 'xxx' . 找不到包的问题

        1.5、paddle/libs缺少依赖文件

二、解决方法

        2.1、多线程问题解决

        2.2、路径下文件找不到问题解决

        2.3、设置 paddle libs问题解决

        2.4、找不到paddleocr依赖包一类问题解决

        2.5、缺少paddle依赖扩展问题解决

三、其他


一、出错情况

        首先我在网上搜到的一些解决办法对我的问题都没有解决。我的错误是提示pyd文件找不到,重要的是我提示的路径是一个动态路径,就是c盘tmp目录下的。每次运行报错的文件夹不一样,根本不知道从何搞起。具体的错误信息没有了,当时没有记录。

        我这边出现的问题有以下几种:

        1.1、多线程的问题

                打好包之后一直运行不打印内容,使用任务管理器看后台会发现xx.exe开了多个进程(这个问题网上有解决的办法)

        1.2、路径下文件找不到的问题

                Error: Can not import avx core while this file exists: xxx/paddle/fluid/core_avx.pyd

        1.3、设置paddle libs路径问题

                TypeError: sequence item 0: expected str instance, NoneType found

        1.4、ModuleNotFoundError: No module named 'xxx' . 找不到包的问题

                ModuleNotFoundError: No module named 'tools'

                ModuleNotFoundError: No module named 'pyclipper'                

                ModuleNotFoundError: No module named 'lmdb'

                …….

        1.5、paddle/libs缺少依赖文件

                RuntimeError: (PreconditionNotMet) The third-party dynamic library (libmklml_intel.so) that Paddle depends on is not configured correctly. (error code is libmklml_intel.so: cannot open share object file: No such file or directory)

                本质是没有把paddle的依赖扩展文件打进去。window环境下为.ddl文件,linux环境下为.so文件。        

二、解决方法

        2.1、多线程问题解决

                关于启动多进程的问题,解决方法是修改一个py文件。解决方法是上site-packages里找到paddle这个包,然后进入到dataset文件夹。然后打开里面一个叫image.py文件,打开并按照如下的写法进行修改即可

# FIXME(minqiyang): this is an ugly fix for the numpy bug reported here
# https://github.com/numpy/numpy/issues/12497
# if six.PY3:
#     import subprocess
#     import sys
#     import_cv2_proc = subprocess.Popen(
#         [sys.executable, "-c", "import cv2"],
#         stdout=subprocess.PIPE,
#         stderr=subprocess.PIPE)
#     out, err = import_cv2_proc.communicate()
#     retcode = import_cv2_proc.poll()
#     if retcode != 0:
#         cv2 = None
#     else:
#         import cv2
# else:
#     try:
#         import cv2
#     except ImportError:
#         cv2 = None

'''
    注释上面的,添加下面的
'''

try:
    import cv2
except ImportError:
    cv2 = None

        2.2、路径下文件找不到问题解决

                我的问题属于第二个问题,只不过路径不是固定的,而是动态路径。就很烦。我试过网上的解决办法,然而对我来说并没有什么用。然后我想到一个办法去规避他。

                思路:既然本地跑没有问题,为什么不可以把单独识别ocr的代码做一个服务。然后再实际生产调用服务传入图片,使用服务的返回结果呢。这样既能解决打包的问题,也能减少最终打包的大小,简直是一举两得!说干就干,当天就把程序写好了,并测试过这个方法是可行的。具体的代码及思路参考如下

                ①:先开发一个服务接口,只集成ocr的功能。具体如下代码所示:

import flask
from PIL import Image
from paddleocr import PaddleOCR
from flask import request


'''
    OCR识别验证码服务
'''
@server.route('/ocrServer', methods=['get', 'post'])
def run():
    file = request.files['file']
    file.save('api_save.png')

    binary = np.array(Image.open(r'api_save.png').convert('L'), 'f')

    # ocr 识别验证码
    ocr = PaddleOCR(use_angle_cls=True, lang='ch')
    img_info = ocr.ocr(binary, cls=False)

    # 最终结果
    img_result = ""
    for line in img_info:
        # 得到图片中文字  循环加总,(多行文字的情况)
        img_result += line[-1][0]
        img_result += ' '
    # 去除特殊字符
    code_value = re.findall(r'[^\*"/:?\\|<>″′‖ 〈\n]', img_result, re.S)
    code_value = "".join(code_value)

    print('识别验证码信息:', code_value)
    # 及时删除
    os.remove('api_save.png')

    return code_value


if __name__ == '__main__':
    # ocr识别   https://localhost:8888/ocrServer? & photoFile
    server.run(debug=True, port='8888', host='0.0.0.0')

                ②:在生产,即实际需要ocr识别的部分调用上面写好的服务接口即可。代码如下

import requests


def ocr_code():
    # 以二进制格式打开保存的验证码图片
    r_file = open('code.png', 'rb')
    # 封装参数 为字典
    code_info = {'file': r_file}

    # 调用服务识别验证码 codeOcrServer                        传入验证码信息
    r = requests.get('http://21.144.105.129:8888/ocrServer?',files=code_info)
    code_value = r.text
    r.close()

    return code_value

         最后困扰了两天的问题完美解决(其实也就是规避,不算真正的解决。但是确实好使!)

        2.3、设置 paddle libs问题解决

                在linux打包遇到的问题,执行打包后的程序后报错文件为paddle/fluid/core.py中386行set_paddle_lib_path函数。解决办法就是修改这个函数。

# 将原文件set_paddle_lib_path函数及其调用代码注释掉,新增set_paddle_lib_path_udf函数
def set_paddle_lib_path_udf():
    site_dir = os.path.sep.join([os.getcwd(), '_internal'])
    lib_dir = os.path.sep.join([site_dir, 'paddle', 'libs'])
    if ps.path.exists(lib_dir):
        _set_paddle_lib_path(lib_dir)
        set_paddle_custom_device_lib_path(
            os.path.sep.join([lib_dir, '..', '..', 'paddle-plugins'])
        )
# 调用
set_paddle_lib_path_udf()

        2.4、找不到paddleocr依赖包一类问题解决

                参考GitHub上的一篇文章,原文点我。其实就在pyinstaller打包时加上--collect-all xxx解决,缺什么加什么。

                省流解决(修改对应的pyinstaller和主py文件的路径):

pyinstaller.exe -D .\main.py --collect-all paddleocr --collect-all pyclipper --collect-all imghdr --collect-all skimage --collect-all imgaug --collect-all scipy.io --collect-all lmdb

        2.5、缺少paddle依赖扩展问题解决

                参考GitHub解决办法,将开发环境site-package/paddle/libs下的文件复制到打完包后的paddle/libs文件夹中即可。

三、其他

        暂时遇到如上几种问题,也是查询了好多资料亲测有效的。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐