Python验证码识别初探(tesserocr库)

转载自:https://juejin.im/post/5b1b3cd26fb9a01e700ffe5b

前言

写爬虫有一个绕不过去的问题,那就是验证码,比如像某乎,如果不先登陆,连里面的内容数据都爬不到,而验证码就是网站进行发爬虫的一种措施,随着技术的发展,验证码越来越复杂,爬虫的工作越来越艰苦,所以这次就来讲解,怎么来识别验证码;(听上去口气很大的感觉)

[图片上传失败...(image-481fc8-1552112841682)]

<figcaption></figcaption>

先来看看,目前遇到的验证码种类有哪些?

1)图形验证码
图形验证码应该是最简单的一种验证码,这种验证码是最早出现,也是目前最常见的,一般组成规则是4个字母或数字或混合组成;

[图片上传失败...(image-631d4b-1552112841682)]

<figcaption></figcaption>

2)滑动验证码

[图片上传失败...(image-50e2f6-1552112841682)]

<figcaption></figcaption>

3)点触验证码

[图片上传失败...(image-f5e571-1552112841682)]

<figcaption></figcaption>

[图片上传失败...(image-b119ee-1552112841682)]

<figcaption></figcaption>

Ok,上面这3种验证码方式,应该是目前PC上比较常见的验证码种类的,当然手机app上还会有手势验证,宫格验证,语音验证等等,这里就不介绍,主要针对上面常见的3种介绍;

1 图形验证码

某乎的验证码有2种,一种是图形验证码,一种是点触验证码,经过测试发现,一开始是显示图形验证码,但当登陆退出次数逐渐增多,就会变成点触验证码,这种验证码的切换机制,也算是防爬虫的一种手段,闲话不多说,先喵喵:

某乎链接:https://www.zhihu.com/signup?next=%2F
打开后默认是在注册页面,点击下登陆按钮,如果还是没有验证码,刷新几次网页就行了;

[图片上传失败...(image-a00e41-1552112841682)]

<figcaption></figcaption>

下面这种,下2篇文章会介绍;

[图片上传失败...(image-3c41e6-1552112841682)]

<figcaption></figcaption>

2 信息介绍

识别图形验证码需要安装tesserocr这个库,下面介绍下tesserocr;
tesserocr是Python的一个OCR识别库,但其实是对tesseract做了一层Python Api的封装,
核心还是tesseract,所以在安装tesserocr之前,需要先安装tesseract;

等下,懵逼中,tesserocr这个能看明白,是一个库,但OCR是什么?tesseract又是什么?

OCR
OCR,全称叫 Optical Character Recognition,中文翻译叫光学字符识别,是指通过扫描字符,通过其形状将其翻译成电子文本的过程;

举例:
当有一个图形验证码,先使用OCR技术将其转化成电子文本,然后爬虫将识别的结果提交到服务器,便达到自动识别验证码的过程;

tesseract
tesseract是google开源的OCR

OK,貌似对概念有所理解了,还有个疑问,之前有在图形识别领域,还有个opencv的玩意,那这两者有什么区别?
opencv专注机器视觉
tesseract专注字符识别

所以从领域来说,opencv更广,而图形验证码,opencv也可以做,但杀鸡焉用牛刀~

3 环境准备

windows下的安装

在Windows下,要先下载tesseract,它为tesserocr提供了支持;
tesseract下载地址:https://digi.bib.uni-mannheim.de/tesseract/
打开后,可以看到各种exe的列表,可以随便挑选;
其中文件名中带有dev的为开发版本,不带dev则为稳定版本,例如jb是下载 tesseract-ocr-setup-3.05.01.exe;

[图片上传失败...(image-24f3a4-1552112841682)]

<figcaption></figcaption>

下载后双击,一路点击,直到出现下面这个页面

[图片上传失败...(image-450403-1552112841682)]

<figcaption></figcaption>

这里需要勾选红框里的Additional language data(download),这个选项是安装OCR识别支持的语言包,这样OCR就可以识别多国语言,然后再一路点击NEXT即可,因为要下载语言包,所以需要点时间,大概10-20分钟左右,跟网速有关,如果不需要支持多国语言的话,也可以不勾选,自由选择
需要说明:默认包含英文字库
如果,觉得一次下载那么多语言占空间,又或者觉得网速慢,也可以选择单独安装中文字库;
字库下载地址:https://github.com/tesseract-ocr/tessdata
打开后,直接搜索chi_sim.traineddata,这个代表的就是中文,下载下来;
然后找到刚刚tesseract安装目录,里面会有一个叫tessdata的目录,直接把刚下载的语言包放到这个目录下即可;

[图片上传失败...(image-2f0ccc-1552112841682)]

<figcaption></figcaption>

如何验证tesseract是否安装成功?直接cmd下输入tesseract即可;
成功会直接显示信息;

[图片上传失败...(image-e4152d-1552112841682)]

<figcaption></figcaption>

如果提示'tesseract' 不是内部或外部命令,则是因为没有配置环境变量,手动把tesseract根目录配置到path参数下即可,这块不详细说明;

到此为止,tesseract安装成功啦~

接下来就安装tesserocr,直接pip命令即可:

pip3 install tesserocr install
复制代码

但jb在安装的时候,直接报错:

[图片上传失败...(image-9bb5ad-1552112841682)]

<figcaption></figcaption>

试过很多种方式,就算使用conda install tesserocr,也一样报错。

[图片上传失败...(image-b2ed56-1552112841682)]

<figcaption></figcaption>

经历千辛万苦,终于找到一条可行的命令:

conda install -c simonflueckiger tesserocr
复制代码

[图片上传失败...(image-b0883e-1552112841682)]

<figcaption></figcaption>

最终就安装上tesserocr啦~

如何验证是否真的安装了?很简单,直接import tesserocr,不报错就说明安装好了;

[图片上传失败...(image-6101ac-1552112841682)]

<figcaption></figcaption>

对了,如果有同学不知道conda这条命令的话,请访问下面的链接,直接搜索scrapy安装,会有介绍conda:
https://juejin.im/post/5afcb91251882565bd257097|

OK,windows下的tesserocr跟tesseract的环境已经安装好了;

别着急,顺便介绍下Linux跟Mac,但以下方式均未经过jb验证,信息来源于网上,仅供参考:

Linux下的安装
对于Liunx来说,不同系统已经有了不同的发行包了,它可能叫做tesseract-ocr或者tesseract,直接用对应的命令安装即可;

  • Ubuntu、Debian和Deepin
    在Ubuntu、Debian和Deepin系统下,安装命令如下:

      sudo apt-get install-y tesseract-ocr libtesseract-dev libleptioica-dev
    复制代码
    
  • CentOS、Red Hat 在CentOS和Red Hat系统下,安装命令如下:

      yum install -y tesseract
    复制代码
    

在不同发行版本运行如上命令,即可完成tesseract的安装;
安装完成后,便可以调用tesseract命令;
默认也是指安装英文语言,如果需要安装其他语言,请看下上面Windows的介绍,一样的处理方案,这里不重复说明;

接下来就是安装tesserocr,直接使用pip安装:

pip3 install tesserocr pillow
复制代码

Mac下的安装
在Mac下,首先使用Homebrew 安装ImageMagick 和tesseract库:

brew install imagemagick
brew install tesseract --all-languages
复制代码

接下来再安装tesserocr即可:

brew install tesserocr pillow
复制代码

4 识别测试

为了方便测试,需要把验证码的图片保存到本地;
打开weibo.com,随便输入账号密码,会提示输入验证码,打开开发者工具,找到验证码元素,它的src属性就是一个链接,copy出来直接打开,会看到一个验证码,而且刷新的验证码会变化,由此推断这是个验证码的接口,右键保存验证码即可,就得到一张验证码;
验证码链接:
https://login.sina.com.cn/cgi/pin.php?r=9967937&s=0&p=gz-d0dc363f6a4523cbd602a5a10f00c59b4784

[图片上传失败...(image-f3a7fe-1552112841681)]

<figcaption></figcaption>

[图片上传失败...(image-afd087-1552112841681)]

<figcaption></figcaption>

ok,完事具备,那就开始吧,新建项目,把验证码放到项目根目录下;
用tesserocr库来识别验证码:

import tesserocr
from PIL import Image

#新建Image对象
image = Image.open("3.jpg")
#调用tesserocr的image_to_text()方法,传入image对象完成识别
result = tesserocr.image_to_text(image)
print(result)
复制代码

[图片上传失败...(image-467ae7-1552112841681)]

<figcaption></figcaption>

结果,运行后,啥都没有???
接下来jb陷入了困扰,包括调试,找各种文档,最终,把上面调试的验证码换了一个:

[图片上传失败...(image-4c4e95-1552112841681)]

<figcaption></figcaption>

替换下图片,再执行一次代码:

[图片上传失败...(image-9bb8b6-1552112841681)]

<figcaption></figcaption>

OK,看到是有数据了,不过输出的是MEEE,跟验证码的ME8E还是有点不一样;

目前两个问题:
1)微博的验证码识别失败,输出空
2)第二章验证码部分词识别有误

心想,这库是网上都推荐用的,是Google开源的,理论上没问题,而且人家也都这么用,为什么这里就有问题?难道还需要额外的处理?

怀着疑问跟梦想,继续学习;

题外话: tesserocr还有一个更加简单的方法,这个方法可直接将图片文件转换成字符串,代码如下:

import tesserocr
print(tesserocr.file_to_text("1.jpg"))
复制代码

[图片上传失败...(image-47278c-1552112841681)]

<figcaption></figcaption>

结果也跟上面的一样,但网上不建议这么用,原因是据说这种识别效果不如上一种的好;

关于微博验证码为空,使用tesseract输出下原因:

tesseract 图片路径 output 
复制代码

[图片上传失败...(image-e8ce79-1552112841681)]

<figcaption></figcaption>

leptonica 在解析时没有检测到任何dpi;

5 验证码处理

网上找了下信息,比如这张验证码:

[图片上传失败...(image-8e7a15-1552112841681)]

<figcaption></figcaption>

可能是验证码内的多余线条干扰了图片的识别;

又比如微博这张:

[图片上传失败...(image-858d87-1552112841681)]

<figcaption></figcaption>

可能是字体位置,跟图案等因素干扰了图标的识别;

解决方案还是有的,需要对图片进行额外的处理,如转灰度,二值化等操作;

转灰度处理: 利用Image对象的convert()方法参数传入L,即可将图片转成为灰度图像:

from PIL import Image

image = Image.open("1.jpg")
image = image.convert('L')
image.show()
复制代码

[图片上传失败...(image-f22f8e-1552112841681)]

<figcaption></figcaption>

图片成功转灰了;此时我们再校验一下,发现校验还是MEEE,失败;[图片上传失败...(image-c3c54a-1552112841681)]

<figcaption></figcaption>

传入1的后,即可将图片进行二值化处理:
(二值化是指将图像上的像素点的灰度值设置为0或255,也就是将整个图片呈现出明显的只有黑和百的视觉效果)

import tesserocr
from PIL import Image

image = Image.open("1.jpg")
image = image.convert('1')
image.show()
复制代码

[图片上传失败...(image-6a2b17-1552112841681)]

<figcaption></figcaption>

这个一看,比上面更模糊了,理所当然的,校验结果会错的更加离谱:[图片上传失败...(image-b4154e-1552112841681)]

<figcaption></figcaption>

二值化的阈值是可以指定的,上面的方法采用的是默认阈值127;但一般很少直接转换原图,原因如上可看到,错误的更加离谱了;

一般是先将原图转为灰度图像,然后再指定二值化的阈值,代码如下:

import tesserocr
from PIL import Image

#新建Image对象
image = Image.open("1.jpg")
#进行置灰处理
image = image.convert('L')
#这个是二值化阈值
threshold = 150   
table = []

for i in  range(256):
    if i < threshold:
        table.append(0)
    else:
        table.append(1)
#通过表格转换成二进制图片,1的作用是白色,不然就全部黑色了
image = image.point(table,"1")
image.show()
result = tesserocr.image_to_text(image)
print(result)
复制代码

这里说明下,可能有同学对256不明白,这是什么?
首先,我们是把图片置灰处理,灰度图像是一种具有从黑到白256级灰度色阶或等级的单色图像;
对于灰度图像利用阈值得到二值化的图像, 也就是说,我们设定了一个阈值,从0到256,如果灰度图像少于阈值则设置0,大于阈值则设置1,0是黑色,1是白色,这样做,就可以把一个灰度图完全转换二值化图;
可能还是懵逼,直接贴图:
原图

[图片上传失败...(image-136781-1552112841680)]

<figcaption></figcaption>

灰度图:

[图片上传失败...(image-d250a7-1552112841680)]

<figcaption></figcaption>

二值图:

[图片上传失败...(image-9065a-1552112841680)]

<figcaption></figcaption>

在灰度图上,部分色彩是介于白色跟黑色之间,所以通过设置阈值的方法,把这些中间色彩全部转换成黑色跟白色;

ok,扯远了,上面把验证码二值图后是长这样的:

[图片上传失败...(image-61abbe-1552112841680)]

<figcaption></figcaption>

而校验结果:

[图片上传失败...(image-4b528-1552112841680)]

<figcaption></figcaption>

good,有所变化, 至少不是MEEE了,那我们继续调,调到一个合适的值;
调了半天,jb放弃了,原因是这个8,不管怎么调都调不到一个合适的值,一直在S、R、B之间徘徊;

JB换了个验证码:

[图片上传失败...(image-458247-1552112841680)]

<figcaption></figcaption>

上面同样的代码,无修改,二值图如下:

[图片上传失败...(image-7e83e0-1552112841680)]

<figcaption></figcaption>

校验结果:

[图片上传失败...(image-94537a-1552112841680)]

<figcaption></figcaption>

oh year,这个能校验出来了~

还记得我们一开始那个微博验证码吗?我们也来试试,处理后的验证码是这样的~

[图片上传失败...(image-be6724-1552112841680)]

<figcaption></figcaption>

结果校验的时候,基本上都空,只有在138的时候会有一点点识别效果,但是压根不搭边;[图片上传失败...(image-74a09c-1552112841680)]

<figcaption></figcaption>

对比了下,微博验证码跟上面能识别的验证码:

[图片上传失败...(image-f677e4-1552112841680)]

<figcaption></figcaption>

[图片上传失败...(image-27e8d9-1552112841680)]

<figcaption></figcaption>

能别识别的,是实心,而不能被识别的,是空心;
实心的好处在于,图像处理后,黑白分明,但是空心在图像处理后,由于线条本来就很细,处理后可能都识别不出来了;

6 中文情况如何?

更新于18.6.11
突然想起,上面安装的时候有提及到安装不同语言包,那如果要看看其他语言,怎么搞?因此就补充这点了~

先上图~

[图片上传失败...(image-6609fb-1552112841680)]

<figcaption></figcaption>

直接上代码:

import tesserocr
from PIL import Image

image = Image.open("juejin.jpg")
result = tesserocr.image_to_text(image, lang='chi_sim')
print(result)
复制代码

因为默认是英文,所以英文不需要指定lang,但中文就需要啦,chi_sim就是简体中文了;

[图片上传失败...(image-f74b26-1552112841680)]

<figcaption></figcaption>

从输出的结果来看,小册那估计有个sale,不然估计开源库也能匹配出来~
但依然可以看出,中文也不是很精准~

这里说明下,中午不需要置灰跟二值哈,不然颜色加深了,估计更难辨别了~

7 小结

本章学习了tesserocr及tesseract的环境搭建,以及如何对图形验证码进行噪音处理,并且讲解灰色图跟二值图的概念;

作者:jb
链接:https://juejin.im/post/5b1b3cd26fb9a01e700ffe5b
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容