背景
正在做的爬虫项目,其中需要使用ocr的功能去识别验证码。所以就使用了paddlocr,结果没想到后期这么大个坑。好在想到一个方法可能规避这个打包的问题。
写这一篇文章主要是记录下在打包有paddlocr的时候的问题,及规避方法。方便给看到这篇博客及有同样问题的网友提供一个思路。
目录
1.4、ModuleNotFoundError: No module named 'xxx' . 找不到包的问题
一、出错情况
首先我在网上搜到的一些解决办法对我的问题都没有解决。我的错误是提示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文件夹中即可。
三、其他
暂时遇到如上几种问题,也是查询了好多资料亲测有效的。