有段日子没写博客了,工作略忙~(这是借口)
回归正题,验证码是爬虫永远绕不过去的坎。无论你是常规爬取还是用selenium+无头浏览器进行用户的登陆操作,都需要识别验证码。为了搞验证码,搞得对图像也有了初步的了解,不废话说结论。
安装:
环境:win10,anaconda3 ,python3.6
1、开源OCR tesseract 下载网址 https://digi.bib.uni-mannheim.de/tesseract/ ,建议选择tesseract-ocr-setup-3.05.01- 20170602.exe,4.0的那几个eng.traineddata训练效果都不咋样,4.0的真的折腾了我好久怎么也训练不好。
2、python适配的包 tesserocr 联网直接 conda install -c simonflueckiger tesserocr pillow。
离线方法: https://github.com/simonflueckiger/tesserocr-windows_build/releases 下载对应tesseract版本的whl,进入conda文件夹下cmd,pip install whl。(经测试 tesserocr v2.4.0 兼容3.05的tesseract)
3、记得配环境path。具体操作别的博客有介绍。
path D:\Tesseract-OCR\ 和 D:\Tesseract-OCR\tessdata\
TESSDATA_PREFIX D:\Tesseract-OCR\tessdata
本文以 http://asone.safesvc.gov.cn/asone/ 国家外汇管理局网上服务平台的验证码为例进行识别。从该网站下载了验证码进行实践,样例如下:
tesseract只能识别最简单的图片,像本文使用的这种验证码无法直接识别,需要经过变灰度图、二值化、去边框、降点噪声才能进行识别。
对图片进行处理前首先要确定它是三通道还是单通道,三通道的图要先变成灰度图才能进行二值化。转灰度、二值化的代码如下:
#灰度 二值化
def binarizing(img, threashold):
img = img.convert("L") # 转灰度
pixdata = img.load()
w, h = img.size
for y in range(h):
for x in range(w):
if pixdata[x, y] < threashold:
pixdata[x, y] = 0
else:
pixdata[x, y] = 255
return img
threashold取200的样例结果:
然后进行去边框,代码如下:
def removeFrame(img, width):
w, h = img.size
pixdata = img.load()
for x in range(width):
for y in range(0, h):
pixdata[x, y] = 255
for x in range(w - width, w):
for y in range(0, h):
pixdata[x, y] = 255
for x in range(0, w):
for y in range(0, width):
pixdata[x, y] = 255
for x in range(0, w):
for y in range(h - width, h):
pixdata[x, y] = 255
return img
width取1的样例结果:
此时还有很多点噪声,用tesseract依然不能成功识别,采用八领域去噪声法进行去噪声。代码如下:
# 点降噪
def depoint(img):
pixdata = img.load()
w,h = img.size
for y in range(1,h-1):
for x in range(1,w-1):
count = 0
if pixdata[x, y-1] > 245:
count = count + 1
if pixdata[x, y+1] > 245:
count = count + 1
if pixdata[x-1, y] > 245:
count = count + 1
if pixdata[x+1, y] > 245:
count = count + 1
if pixdata[x-1, y-1] > 245:
count = count + 1
if pixdata[x-1, y+1] > 245:
count = count + 1
if pixdata[x+1, y-1] > 245:
count = count + 1
if pixdata[x+1, y+1] > 245:
count = count + 1
if count > 5:
pixdata[x,y] = 255
return img
这里count选择的大于5效果最好,这个得根据实际需求去调试最优结果。样例结果:
此时图像已经处理的很清晰了。然后用tesserocr库进行识别,识别成功率还是挺高的,识别结果有的时候中间有空格,和换行符,具体原因不清楚,去掉就好。再强调一次,一定要用tesseract-ocr-setup-3.05.01-20170602.exe安装包!
主程序代码:
import tesserocr
import vc_processing
from PIL import Image
img = Image.open('image.bmp')
img = vc_processing.binarizing(img,200)
img.save('binarizing.bmp')
img = vc_processing.removeFrame(img,1)
img.save('removeFrame.bmp')
img = vc_processing.depoint(img)
img.save('depoint.bmp')
result = tesserocr.image_to_text(img,lang = "eng")
print(result.replace(' ','').strip())
输出结果:4100
理论上,本文的处理方法对彩色的验证码也应该有效果,对有横线的验证码还没有过测试,有机会再进行吧。
现在的验证码类型很多,还有一种拼图的,工作需要时再实践吧。
本文结束~
题外话,有个关于图像保存格式的小坑坑了我好久,当我用jpg格式储存二值化后的图片时,放大图片总会看到一些灰点,一度搞得让我觉得二值化有问题,折腾了好久,严重影响了测试验证码识别的效率,实际上是jpg格式储存失真的原因,用bmp格式就解决了 = =。。。
有机会写一篇关于模拟登陆 http://asone.safesvc.gov.cn/asone/ 国家外汇管理局网上服务平台的博客,在不用selenium的情况下还是挺麻烦的。