0%

Discuz简单验证码识别

前言

  • 我之前的文章解决selenium使用location定位与截图中的坐标偏差问题中提到了,如何利用selenium截取验证码,但是并没有讲该怎么去识别验证码,原因是之前一直没有找到好的方法,一开始尝试过pillow + pytesseract,但是效果很差,显然这种验证码不能用这方法。也尝试过网上的一些在线识别,效果不错,但缺点就是要钱。
  • 再后来在github上发现了这个项目https://github.com/nickliqian/cnn_captcha,然后又在这篇文章中Tensorflow实战(二):Discuz验证码识别找到了生成Discuz验证码的php代码,这篇文章也给出了他的深度学习的识别验证码的代码,但我测试时没跑成功,又不懂这方面的知识,排不了错,所以最后选择的是用cnn_captcha这个项目来训练模型,用他给的php代码生成训练用的数据集。最终发现训练的模型效果还不错,一开始用2万张图片训练,虽然训练集准确率达到了100%,但测试集图片准确率一直为0,增加图片数量得到改善,最后调整到用20万张图片训练,测试集字符识别率和图片准确率均达到了99%,实际测试从目标网站爬取下来的图片识别准确率也有80%,这个准确率自用完全OK。

准备阶段

  • 最好拥有一台有高性能GPU的电脑,不然训练只靠CPU真跑不动,或者可以使用像谷歌的colab这种云平台来训练模型,训练好后再下载下来使用

  • tensorflow 1.x 环境,试过tensorflow 2.x以兼容1.x方式运行,但是运行还是出了问题,可以用anaconda创建一个tensorflow 1的虚环境,tensorflow1.5下载地址:https://pypi.org/project/tensorflow/1.15.0/#files

  • php运行环境(生成验证码数据集需要)

  • 如果不想生成验证码或者重复训练模型,这里提供训练用的20万张验证码数据集,以及训练好的模型,模型下载后可以直接使用

    链接: https://pan.baidu.com/s/1neXmwUjlqGzxBk3QoqRWCg?pwd=2zx4 密码: 2zx4

    注意事项:使用这个模型进行识别需要图片满足width 160,hight 60的png格式,而且要有alpha通道,因为用于训练的图片就是这种。如果你的图片宽高不符合请等比缩放调整至一直,否则会运行出错;如果png图没有alpha通道,请转换下即可,否则将导致识别结果不准确(之前试了同一网站两种不同方式获取验证码图片,识别结果天壤之别,排了很久才发现是识别差的那组是因为图片没有alpha通道,才导致识别结果不准。。)

  • 这个模型比较适合这种类型的Discuz验证码,动态和静态一样,因为最终用于识别的都只有那一张图

    misc.gif

开始

生成验证码数据集

  • 首先生成训练用的数据集,一开始是想的从目标网站爬取验证码,爬下来1000张,自己人工标了几百张,大脑就罢工了。。后来找到这个php代码discuz.tar.gz,可以批量生成验证码,还不用自己标注,省去很大麻烦,所以要识别某类验证码,最好看看网上能不能找到相应的验证码库批量生成,实在不行再来考虑爬取标注。

  • 下面讲解如何在不会php的情况下,简单跑起这个生成验证码项目,以MacOS+PHPStorm为例

  • 首先安装php,打开终端用homebrew安装即可:brew install php

  • 下载安装PHPStorm,启动后打开discuz.tar.gz解压后的目录

  • 选择Preferences > PHP > CLI Interpreter > PHP executable,选择php安装目录,一般homebrew安装的在/usr/local/Cellar目录下可以找到,最后选择OK保存即可

    img1.png

  • 选择右上角Add Configuration

    img2.png

  • 点击+添加一个PHP Built-in Web Server

    img3.png

  • 修改Name,Host,Port,其中Name可以随便起,Host可以设为127.0.0.1或者0.0.0.0等,Port选择你电脑上没有被占用的端口即可,其他保持默认即可,然后保存设置

    img4.png

  • 保存后,可以看到右上角有了绿色三角的运行按钮,点击运行,即可启动这个php项目

  • 运行后,就可以用python批量生产验证码了,懂PHP的话其实应该可以修改代码直接PHP生成这些图即可,但奈何不会PHP,下面python代码同样也是改自这篇文章提供的Tensorflow实战(二):Discuz验证码识别,这里因为目标网站就是用的Discuz默认的"BCEFGHJKMPQRTVWXY2346789"词库,所以批量生成验证码时也只用这些来生成,减少干扰项,为了方便cnn_captcha识别,文件命名为"验证码_序号"的格式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #-*- coding:utf-8 -*-
    from urllib.request import urlretrieve
    import time, random, os

    class Discuz():
    def __init__(self):
    # Discuz验证码生成图片地址
    self.url = 'http://127.0.0.1:8080/index.php?label={}&width=160&height=60&background=1&adulterate=1&ttf=1&angle=1&scatter=1&color=1&size=1&shadow=1'

    def random_captcha_text(self, captcha_size = 4):
    """
    验证码一般都无视大小写;验证码长度4个字符
    Parameters:
    captcha_size:验证码长度
    Returns:
    captcha_text:验证码字符串
    """
    # number = ['0','1','2','3','4','5','6','7','8','9']
    # alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
    # char_set = number + alphabet
    char_set="BCEFGHJKMPQRTVWXY2346789"

    return ''.join(random.sample(char_set, 4))

    def download_discuz(self, start=0, end=10000):
    """
    下载验证码图片
    Parameters:
    nums:下载的验证码图片数量
    """
    dirname = './Discuz'
    if not os.path.exists(dirname):
    os.mkdir(dirname)
    for i in range(start, end):
    label = self.random_captcha_text()
    print('第%d张图片:%s下载' % (i + 1,label))
    urlretrieve(url = self.url.format(label), filename = os.path.join(dirname, f'{label}_{i}.png'))
    print('恭喜图片下载完成!')

    if __name__ == '__main__':
    dz = Discuz()
    dz.download_discuz(0, 50000)

  • 至此已经生成了用于训练的图片数据集

训练模型

  • 这里以用谷歌的colab为例来训练模型,没办法自己电脑上的显卡太弱,约等于无

  • 首先上传打包后的验证码到谷歌云盘上,方便colab上访问

  • 新建或者打开一个笔记本,选择左上角的修改 > 笔记本设置,可以选择使用GPU加速

    image-20210728112118379

  • 挂载谷歌云盘(非必须,如果数据在谷歌云盘上,则可以挂载),打开网页后输入口令即可

    1
    2
    3
    4
    5
    6
    import os
    from google.colab import drive
    drive.mount('/content/drive')

    # 查看是否挂载成功
    os.listdir('.')

    image-20210728112328924

  • 选择tensorflow_version 1.x运行环境

    1
    %tensorflow_version 1.x
  • 从github上clone cnn_captcha

    1
    2
    ! git clone https://github.com/nickliqian/cnn_captcha.git
    ! mkdir cnn_captcha/sample
  • 解压图片数据集

    1
    2
    3
    4
    ! tar -zxvf '/content/drive/MyDrive/Discuz-50000.tar.gz' > /dev/null
    ! tar -zxvf '/content/drive/MyDrive/Discuz-50000-100000.tar.gz' > /dev/null
    ! tar -zxvf '/content/drive/MyDrive/Discuz-100000-200000.tar.gz' > /dev/null
    ! mv Discuz cnn_captcha/sample/origin
  • 修改配置文件,如果不是在colab上运行,则可以直接文本编辑器修改json配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ! cd cnn_captcha/tools && python3 collect_labels.py
    import json

    with open('cnn_captcha/conf/sample_config.json', 'r') as fp:
    data=json.load(fp)

    # 修改需要的参数,其余参数可保持默认
    # 最大训练次数
    data['cycle_stop'] = 60000
    # 数据集图片格式
    data['image_suffix']='png'
    # 图片宽高
    data['image_width'] = 160
    data['image_hight'] = 60
    # 生成验证码的所有字符集合,Discuz默认只有这24个
    data['char_set']='BCEFGHJKMPQRTVWXY2346789'
    # 每次测试集使用的图片数量,内存小的机器可减小这个
    data['test_batch_size']=100
    # 每次训练集使用的图片数量,内存小的机器可减小这个
    data['train_batch_size']=128
    # 保存配置
    with open('cnn_captcha/conf/sample_config.json', 'w') as fp:
    json.dump(data, fp)

image-20210728113839158

  • 设置工作目录为cnn_captcha,方便后面运行训练主函数

    1
    os.chdir('cnn_captcha')
  • 拆分图片为训练集和测试集

    1
    ! python3 verify_and_split_data.py
  • 拷贝train_model.py文件内容至colab笔记本输入框,然后运行main函数,这里不直接命令运行是因为,colab中使用命令运行,默认用的还是tensorflow 2,前面设置tensorflow 1就白设置了

  • 训练完毕后打包model并保存到谷歌云盘

    1
    2
    3
    4
    5
    6
    os.chdir('/content/')

    ! tar -zcvf cnn_captcha.tar.gz cnn_captcha > /dev/null # 可以不打包整个cnn_captcha文件夹,看需求调整
    ! tar -zcvf model.tar.gz cnn_captcha/model > /dev/null # 这个即为训练好的模型
    ! cp model.tar.gz drive/MyDrive/ # 拷贝至谷歌云盘
    ! cp cnn_captcha.tar.gz drive/MyDrive/ # 拷贝至谷歌云盘
  • 完整colab的ipynb

    Discuz.ipynb

  • 实际用colab训练发现速度还是可以的:20万张图,按上面参数训练5万多次后,训练集字符和图片准确率100%,测试集的字符和图片准确率达到了99%,总耗时2小时。

启动识别API Server

  • 本地git clone cnn_captcha

    1
    git clone https://github.com/nickliqian/cnn_captcha.git
  • 下载训练好的模型,解压至cnn_captcha目录下

  • 修改配置文件conf/sample_config.json里面的图片格式和大小为模型使用的大小,其他可以保持默认

  • 创建API存放图片文件夹,这个文件夹可以在sample_config.json中修改,启动识别API server前需要有这个错误,否则识别时,报找不到文件错误

    1
    mkdir -p sample/api
  • 启动server,这里运行环境也是需要tensorflow1.x,但是可以不需要GPU

    1
    python3 webserver_recognize_api.py

测试识别

  • 使用jupyter notebook进行测试,方便展示验证码,比较识别结果

    1
    2
    3
    4
    5
    6
    7
    8
    import requests

    # 这里参数说明('code.png', open('code.png', 'rb'), 'application'),前面的code.png随意,可以与后面的open中的名称不一致;open('code.png', 'rb')实际上是参数需要一个bytes型的数据,直接传一个bytes型的数据也是可以的;"application"保持默认即可
    files = {'image_file': ('code.png', open('code.png', 'rb'), 'application')}
    # http://127.0.0.1:6000/b为默认的API URL,可以在webserver_recognize_api.py中修改
    r = requests.post(url='http://127.0.0.1:6000/b', files=files)
    data = r.json()
    data

    image-20210728120402589

  • 可以看到正确识别了CBXB,实际用某论坛的进行测试,图片准确率可达80%

  • 至此可以用这个模型来进行一些使用了之类验证码的Discuz类论坛进行自动登录

参考链接