天天看点

Python爬虫学习笔记二:模拟登录(以API形式调用tesseract识别简单验证码),并打包成执行文件(exe)

一、tesseract dll下载

https://github.com/charlesw/tesseract 这个网址中包含了编译好的exe及dll文件,而且x86,x64两种架构都有。

(特别说明:选择x86还是x64版本dll,只依赖于你的python架构,而不是操作系统的架构,即便是在64位操作系统,假如你的python是32位版本,这里也要选用x86版本dll)。

下载这两个DLL:libtesseract304.dll  和 liblept172.dll

二、语言包下载

网址: https://github.com/tesseract-ocr/tessdata ,下载其中需要的语言包就行了。跟dll放到同一目录 ( 记得把语言包放在tessdata文件夹里面 ) 。

语言包文件格式:eng.traineddata

以上网址打不开的请自行百度关键字:GitHub不能访问

三、vc 2015++发行包下载

注意说明里这一段话:

Since tesseract and leptonica binaries are compiled with Visual Studio 2015 you'll need to ensure you have theVisual Studio 2015 Runtimeinstalled.

意思就是,这个tesseract 的dll是使用vs 2015编译的,所以必须安装其发行包,同样分X64,X86两个版本,还是依赖于你的开发环境,不依赖于操作系统。

四、安装pyocr for python包

用pip就可以安装: pip install pyocr,也可以到官网下载源码,手动安装:https://github.com/jflesch/pyocr

最新的pyocr是0.4.1,其源码还是基于tesseract 3.0.2 ,而前文下载的tesseract 已经是3.0.4版本了,所以需要改下pyocr源码。(需要说明的是pyocr包,比起pytesseract包要更复杂一些,同时支持shell、api 、Cuneiform三种形式。)

----------------------------------------------我是分割线----------------------------------------------

上面都是复制的,红色是我特别说明的。

下面开始贴代码:

我这里创建了两个py文件,MainWindow.py、Logon_Test.py

MainWindow.py代码:

# -*- coding: utf-8 -*-

import Logon_Test

if __name__ == '__main__':
    LoginURL = 'http://######/psdr/login.do?method=enterbs'  # 登陆提交地址
    CodeImgURL = 'http://######/psdr/form/digitalverify.jsp'  # 验证码获取地址
    url = 'http://######/psdr/projectInfo.do?method=queryTrace'  # 项目展示地址
    loginId = "用户名"
    password = "密码"
    a = Logon_Test.CDRS_Logon(LoginURL,CodeImgURL,loginId,password,True)
    img = a.get_VerificationCode_Image()
    Code = a.ImageToString(img)
    #对验证码的识别进行判断
    i = 1
    while Code == "" or not(Code.isdigit()):
        i += 1
        img = a.get_VerificationCode_Image()
        Code = a.ImageToString(img)
        if i > 5 :
            break

    a.set_PostData_And_send(Code)
    source_file = a.get_Web_source_file(url)
    print(source_file)
           

这个文件很简单,就是类初始化、类方法的调用。

我们主要看Logon_Test.py文件的实现:

# -*- coding: utf-8 -*-

try:
    import requests, base64, re, os, sys
    from PIL import Image, ImageDraw
    from io import BytesIO
    from pyocr import libtesseract
    from pyocr.builders import TextBuilder
except ImportError:
    print("ImportError!")
    raise  SystemExit

# determine if application is a script file or frozen exe
if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(sys.executable)
elif __file__:
    application_path = os.path.dirname(__file__)

tessdir = os.getenv('TESSDATA_PREFIX', None)
if tessdir is None  :
    os.environ['TESSDATA_PREFIX'] = application_path
if application_path not in os.environ['PATH']:
    os.environ['PATH']= application_path + ';' +os.environ['PATH']

class CDRS_Logon:
    #模拟登陆的类
    def __init__(self, LoginURL, CodeImgURL, LoginId, Password, base64_utf_8 = False):
        self.LoginURL = LoginURL
        self.CodeImgURL = CodeImgURL
        if base64_utf_8 == True: # base64_utf_8参数判断是否需要进行转码(根据网站需要)
            base64_loginId_utf_8 = base64.b64encode(LoginId.encode('utf-8'))
            base64_password_utf_8 = base64.b64encode(Password.encode('utf-8'))
            ID = re.findall(r'b\'(.*)\'', str(base64_loginId_utf_8))  #用正则处理掉标识符b'
            PWD = re.findall(r'b\'(.*)\'', str(base64_password_utf_8))
            self.LoginId = ID[0]
            self.Password = PWD[0]
        else:
            self.LoginId = LoginId
            self.Password = Password
        self.session = requests.session()  # 创建统一的会话
        self.Code = "null"

    def get_VerificationCode_Image(self):
        #获取验证码图片
        res = self.session.get(self.CodeImgURL, stream=True)  # 获取验证码图片
        img = Image.open(BytesIO(res.content))
        return img

    def ImageToString(self,img):
        bu = TextBuilder(tesseract_layout=7)
        vcode = libtesseract.image_to_string(img, , builder=bu)
        return vcode

    def set_PostData_And_send(self, Code):
        # 构建POST数据并提交
        postData = {'txtLoginId': '', 'loginId': self.LoginId,
                    'txtPassword': '', 'password': self.Password,
                    'vericode': Code, 'chkLoginuser': 'on'}
        self.session.post(self.LoginURL, postData)

    def get_Web_source_file(self, get_URL):
        #获取网页源文件
        Web_source_file_Res = self.session.get(get_URL)
        return Web_source_file_Res.text
           

我再对其中的关键部分解释一下。

# determine if application is a script file or frozen exe
if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(sys.executable)
elif __file__:
    application_path = os.path.dirname(__file__)

tessdir = os.getenv('TESSDATA_PREFIX', None)
if tessdir is None  :
    os.environ['TESSDATA_PREFIX'] = application_path
if application_path not in os.environ['PATH']:
    os.environ['PATH']= application_path + ';' +os.environ['PATH']
           

上面这段代码用于判断当前文件是py脚本文件还是可执行文件(exe),因为这两个不同的文件,在运行中取得的文件路径是不同的,这是很关键的地方,不然就会导致无法找到tessdata文件夹,运行错误。

接着第二段创建了环境变量,用于引导语言包和DLL文件的调用。

构造函数中base64_utf_8参数是我实验的网站需要处理的,通过查看网站源码发现对用户名和密码进行了转码,所以我也处理了一下。实际情况,按看客自己的要求来处理。

def ImageToString(self,img):
        bu = TextBuilder(tesseract_layout=7)
        vcode = libtesseract.image_to_string(img, , builder=bu)
        return vcode
           

上面代码中

vcode = libtesseract.image_to_string(img, , builder=bu)
           

lang参数默认也是英语,这里设置为自己要用的语言包,但一定要下载好对应的语言包文件。

----------------------------------------------我是分割线----------------------------------------------

上面的程序已经可以作为脚本运行了。接下来我们进行exe文件的打包处理。

PyInstaller是一个十分有用的第三方库,它能够在Windows、Linux、Mac OS X 等操作系统下将 Python 源文件打包,通过对源文件打包,Python 程序可以在没有安装 Python 的环境中运行,也可以作为一个独立文件方便传递和管理。PyInstaller 需要在命令行(控制台)下用pip 工具安装,如下:

pip install pyinstaller
           

安装完成后cd到脚本文件的目录下执行打包命令:

pyinstaller -F MainWindow.py
           

执行完成后会生产两个目录build和dist,其中后一个目录里面就有可执行文件了。

接下来我们试验一下。把可执行文件(MainWindow.exe)复制出来,然后把前面开头我们准备的tessdata文件夹和liblept172.dll、libtesseract304.dll也复制出来,放在同一个文件夹下。这里也要注意一下,整个文件的路径不要有中文,不然在环境变量的设置时会出错。

用CMD运行我们的MainWindow.exe文件,就可以看到执行结果了。当然,你也可以直接双击,不过窗口可能会一闪而逝。