Qt调用python脚本识别验证码
一些懒人经常会想让很多工作都由机器处理,实现自动化。而一些涉及验证码的就要费些力气了。
python在许多领域都是让人省时省力的神兵利器,任何程序员都可以加以利用获取裨益,因为python的库实在太好太全太方便了。
在验证码识别上,python下也有一个pytesseract。只所以说也,是因为tesseract库有很多版本,比如java下的,比如c++下的(但是c++直接用起来来就没那么简单直接了,可以搜相关文章,一大段一大段的,安装库也有些费事)。此处不讨论pytesseract的识别正确率和训练改进,因为本人尚未研究到那一地步。此处只记录如何在Qt中调用python脚本。
代码
python脚本
python识别验证码的代码,输入为验证码图片的路径:
identCode.py
# coding:utf-8
import sys
print(sys.path)
import pytesseract
from PIL import Image
def getCode(path):
image = Image.open(path)
vcode = pytesseract.image_to_string(image)
return vcode
if __name__=="__main__":
if len(sys.argv) < 2:
print("give pic path please\n")
sys.exit(0)
print(getCode(sys.argv[1]))
在命令行中执行 ”identCode.py recg.png“即可显示出所识别的验证码结果。
c++调用脚本获取结果代码
identifycode.h
#ifndef IDENTIFYCODE_H
#define IDENTIFYCODE_H
#include<string>
#include<iostream>
#include<QProcess>
using std::string;
class IdentifyCodeSh
{
public:
IdentifyCodeSh(){};
virtual ~IdentifyCodeSh(){};
virtual string recg(std::string path);
};
#endif // IDENTIFYCODE_H
identifycode.cpp
#include "identifycode.h"
using namespace std;
std::string IdentifyCodeSh::recg(std::string path)
{
string result;
QProcess proc;
string trim="\r\n\t\v\d";
//启动进程
proc.start(QString("python identCode.py %1 ")
.arg(QString::fromStdString(path)).toLocal8Bit());
//等待进程可读
proc.waitForReadyRead();
if(proc.isReadable()){
result=proc.readAll().data();
std::cout<<"str read is:"<<result.c_str()<<std::endl;
//去掉头尾多余的空格、换行符
result=result.substr(result.find_first_not_of(trim),
result.find_last_not_of(trim)+1);
cout<<" str trimmed is "<<result.c_str()<<endl;
}else{
cout<<"not readable"<<endl;
}
//等待进程执行完毕
proc.waitForFinished();
return result;
}
这里用到了QProcess类,可以执行一个系统命令,有点类似于c语言中的system(char* cmd)命令。但是QProcess封装得更好,可以读取到命令的输出,也可以向其中输入指令。如果将功能再封装,完全就可以实现一个自动交互式的expect(或者pexpect)模块功能了。当然,性能可能不是那么好:),具体的expect的底层源码有空也可以研究研究。
这样,基本上python中的所有功能都可以在c++项目中借用到了。其他python模块的功能借用如法炮制即可。:)。
问题
上面这种解决方案如果人品好的话,是可行的。人品好指的是你的Python脚本版本正好就是子进程执行时所对应的Python版本。
Qt中自带了一个版本的Python,比如我的Qt5.3带了个Python2.7。而我的脚本中用的是Python3.5。可想而知,会出现一些什么问题。报错如下:
Traceback (most recent call last): File "F:/SoftwareDevelopByMyself/Qt/StockAi/python/identCode.py", line 10, in <module> import pytesseract File "C:\Python35\Lib\site-packages/pytesseract/__init__.py", line 4, in <module> from pytesseract.pytesseract import image_to_string File "C:\Python35\Lib\site-packages/pytesseract/pytesseract.py", line 65, in <module> from PIL import Image File "C:\Python35\Lib\site-packages/PIL/Image.py", line 67, in <module> from PIL import _imaging as core ImportError: cannot import name _imaging
上面这个错误发生的原因,是QProcess中调用时默认就用了Qt中的Python2.7。而直接指定python3.5的可执行文件解析脚本又报一个Py_initialize错误。未能了解这个问题的深层原因。留待以后进步了再回头寻找答案。:)
“Fatal Python error:Py_Initialize: unable to load the file system codec”
知道问题原因的大神麻烦指点下。:)
于是本人尝试了另一种方法,不用qt,用纯c++来实现python脚本的调用。而纯C++是可行的。代码如下:
#include<iostream>
#include<cstdlib>
#include<windows.h>
using namespace std;
int main(void){
FILE* fp=popen("C:/Python35/python.exe F:/SoftwareDevelopByMyself/Qt/StockAi/python/identCode.py d:/recg.bmp","r");
char buf[256];
while (fgets(buf, sizeof(buf), fp) != 0) {
cout<<buf<<endl;
}
pclose(fp);
printf("done");
getchar();
return 1;
}