1、介绍

    在爬虫中经常会遇到验证码识别的问题,现在的验证码大多分计算验证码、滑块验证码、识图验证码、语音验证码等四种。本文就是识图验证码,识别的是简单的验证码,要想让识别率更高,

  识别的更加准确就需要花很多的精力去训练自己的字体库。

    识别验证码通常是这几个步骤:

    1、灰度处理

    2、二值化

    3、去除边框(如果有的话)

    4、降噪

    5、切割字符或者倾斜度矫正

    6、训练字体库

    7、识别

     这6个步骤中前三个步骤是基本的,4或者5可根据实际情况选择是否需要。

    经常用的库有pytesseract(识别库)、OpenCV(高级图像处理库)、imagehash(图片哈希值库)、numpy(开源的、高性能的Python数值计算库)、 PIL的 Image,

    ImageDraw,ImageFile等。

  2、实例

    以某网站登录的验证码识别为例:具体过程和上述的步骤稍有不同。

    

    首先分析一下,验证码是由4个从0到9等10个数字组成的,那么从0到9这个10个数字没有数字只有第一、第二、第三和第四等4个位置。那么计算下来共有40个数字位置,如下:

    

    

    

    

    

    

    

    

    

    

    那么接下来就要对验证码图片进行降噪、分隔得到上面的图片。以这40个图片集作为基础。

    对要验证的验证码图片进行降噪、分隔后获取四个类似上面的数字图片、通过和上面的比对就可以知道该验证码是什么了。

    以上面验证码2837为例:

    1、图片降噪

      

    

    2、图片分隔

    

    

  3、图片比对

    通过比验证码降噪、分隔后的四个数字图片,和上面的40个数字图片进行哈希值比对,设置一个误差,max_dif: 允许最大hash差值, 越小越精确,最小为0

    

    这样四个数字图片通过比较后获取对应是数字,连起来,就是要获取的验证码。

  完整代码如下:

  1. #coding=utf-8
  2. import os
  3. import re
  4. from selenium import webdriver
  5. from selenium.webdriver.common.keys import Keys
  6. import time
  7. from selenium.webdriver.common.action_chains import ActionChains
  8. import collections
  9. import mongoDbBase
  10. import numpy
  11. import imagehash
  12. from PIL import Image,ImageFile
  13. import datetime
  14. class finalNews_IE:
  15. def __init__(self,strdate,logonUrl,firstUrl,keyword_list,exportPath,codepath,codedir):
  16. self.iniDriver()
  17. self.db = mongoDbBase.mongoDbBase()
  18. self.date = strdate
  19. self.firstUrl = firstUrl
  20. self.logonUrl = logonUrl
  21. self.keyword_list = keyword_list
  22. self.exportPath = exportPath
  23. self.codedir = codedir
  24. self.hash_code_dict ={}
  25. for f in range(0,10):
  26. for l in range(1,5):
  27. file = os.path.join(codedir, "codeLibrary\code" + str(f) + '_'+str(l) + ".png")
  28. # print(file)
  29. hash = self.get_ImageHash(file)
  30. self.hash_code_dict[hash]= str(f)
  31.  
  32. def iniDriver(self):
  33. # 通过配置文件获取IEDriverServer.exe路径
  34. IEDriverServer = "C:\Program Files\Internet Explorer\IEDriverServer.exe"
  35. os.environ["webdriver.ie.driver"] = IEDriverServer
  36. self.driver = webdriver.Ie(IEDriverServer)
  37.  
  38. def WriteData(self, message, fileName):
  39. fileName = os.path.join(os.getcwd(), self.exportPath + '/' + fileName)
  40. with open(fileName, 'a') as f:
  41. f.write(message)
  42.  
  43. # 获取图片文件的hash值
  44. def get_ImageHash(self,imagefile):
  45. hash = None
  46. if os.path.exists(imagefile):
  47. with open(imagefile, 'rb') as fp:
  48. hash = imagehash.average_hash(Image.open(fp))
  49. return hash
  50.  
  51. # 点降噪
  52. def clearNoise(self, imageFile, x=0, y=0):
  53. if os.path.exists(imageFile):
  54. image = Image.open(imageFile)
  55. image = image.convert('L')
  56. image = numpy.asarray(image)
  57. image = (image > 135) * 255
  58. image = Image.fromarray(image).convert('RGB')
  59. # save_name = "D:\work\python36_crawl\Veriycode\mode_5590.png"
  60. # image.save(save_name)
  61. image.save(imageFile)
  62. return image
  63.  
  64. #切割验证码
  65. # rownum:切割行数;colnum:切割列数;dstpath:图片文件路径;img_name:要切割的图片文件
  66. def splitimage(self, imagePath,imageFile,rownum=1, colnum=4):
  67. img = Image.open(imageFile)
  68. w, h = img.size
  69. if rownum <= h and colnum <= w:
  70. print('Original image info: %sx%s, %s, %s' % (w, h, img.format, img.mode))
  71. print('开始处理图片切割, 请稍候...')
  72.  
  73. s = os.path.split(imageFile)
  74. if imagePath == '':
  75. dstpath = s[0]
  76. fn = s[1].split('.')
  77. basename = fn[0]
  78. ext = fn[-1]
  79.  
  80. num = 1
  81. rowheight = h // rownum
  82. colwidth = w // colnum
  83. file_list =[]
  84. for r in range(rownum):
  85. index = 0
  86. for c in range(colnum):
  87. # (left, upper, right, lower)
  88. # box = (c * colwidth, r * rowheight, (c + 1) * colwidth, (r + 1) * rowheight)
  89. if index < 1:
  90. colwid = colwidth + 6
  91. elif index < 2:
  92. colwid = colwidth + 1
  93. elif index < 3:
  94. colwid = colwidth
  95.  
  96. box = (c * colwid, r * rowheight, (c + 1) * colwid, (r + 1) * rowheight)
  97. newfile = os.path.join(imagePath, basename + '_' + str(num) + '.' + ext)
  98. file_list.append(newfile)
  99. img.crop(box).save(newfile, ext)
  100. num = num + 1
  101. index += 1
  102. return file_list
  103.  
  104. def compare_image_with_hash(self, image_hash1,image_hash2, max_dif=0):
  105. """
  106. max_dif: 允许最大hash差值, 越小越精确,最小为0
  107. 推荐使用
  108. """
  109. dif = image_hash1 - image_hash2
  110. # print(dif)
  111. if dif < 0:
  112. dif = -dif
  113. if dif <= max_dif:
  114. return True
  115. else:
  116. return False
  117.  
  118. # 截取验证码图片
  119. def savePicture(self):
  120. self.driver.get(self.logonUrl)
  121. self.driver.maximize_window()
  122. time.sleep(1)
  123.  
  124. self.driver.save_screenshot(self.codedir +"\Temp.png")
  125. checkcode = self.driver.find_element_by_id("checkcode")
  126. location = checkcode.location # 获取验证码x,y轴坐标
  127. size = checkcode.size # 获取验证码的长宽
  128. rangle = (int(location['x']), int(location['y']), int(location['x'] + size['width']),
  129. int(location['y'] + size['height'])) # 写成我们需要截取的位置坐标
  130. i = Image.open(self.codedir +"\Temp.png") # 打开截图
  131. result = i.crop(rangle) # 使用Image的crop函数,从截图中再次截取我们需要的区域
  132. filename = datetime.datetime.now().strftime("%M%S")
  133. filename =self.codedir +"\Temp_code.png"
  134. result.save(filename)
  135. self.clearNoise(filename)
  136. file_list = self.splitimage(self.codedir,filename)
  137. verycode =''
  138. for f in file_list:
  139. imageHash = self.get_ImageHash(f)
  140. for h,code in self.hash_code_dict.items():
  141. flag = self.compare_image_with_hash(imageHash,h,0)
  142. if flag:
  143. # print(code)
  144. verycode+=code
  145. break
  146.  
  147. print(verycode)
  148. self.driver.close()
  149.  
  150. def longon(self):
  151.  
  152. self.driver.get(self.logonUrl)
  153. self.driver.maximize_window()
  154. time.sleep(1)
  155. self.savePicture()
  156. accname = self.driver.find_element_by_id("username")
  157. # accname = self.driver.find_element_by_id("//input[@id='username']")
  158. accname.send_keys('ctrchina')
  159.  
  160. accpwd = self.driver.find_element_by_id("password")
  161. # accpwd.send_keys('123456')
  162. code = self.getVerycode()
  163. checkcode = self.driver.find_element_by_name("checkcode")
  164. checkcode.send_keys(code)
  165. submit = self.driver.find_element_by_name("button")
  166. submit.click()

Python3 简单验证码识别思路及实例的更多相关文章

  1. 简单验证码识别(matlab)

    简单验证码识别(matlab) 验证码识别, matlab 昨天晚上一个朋友给我发了一些验证码的图片,希望能有一个自动识别的程序. 1474529971027.jpg 我看了看这些样本,发现都是很规则 ...

  2. 开发工具类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 六位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数 ...

  3. HNUSTOJ-1696 简单验证码识别(模拟)

    1696: 简单验证码识别 时间限制: 2 Sec  内存限制: 128 MB 提交: 148  解决: 44 [提交][状态][讨论版] 题目描述 验证码是Web系统中一种防止暴力破解的重要手段.其 ...

  4. 基于TensorFlow的简单验证码识别

    TensorFlow 可以用来实现验证码识别的过程,这里识别的验证码是图形验证码,首先用标注好的数据来训练一个模型,然后再用模型来实现这个验证码的识别. 生成验证码 首先生成验证码,这里使用 Pyth ...

  5. windows下简单验证码识别——完美验证码识别系统

    此文已由作者徐迪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 讲到验证码识别,大家第一个可能想到tesseract.诚然,对于OCR而言,tesseract确实很强大,自带 ...

  6. python简单验证码识别

    在学习python通过接口自动登录网站时,用户名密码.cookies.headers都好解决但是在碰到验证码这个时就有点棘手了:于是通过网上看贴,看官网完成了对简单验证码的识别,如果是复杂的请看大神的 ...

  7. python3.7验证码识别MuggleOCR,为什么总是报错

    先来看看MuggleOCR简介(白嫖)这是一个为麻瓜设计的本地OCR模块只需要简单几步操作即可拥有两大通用识别模块,让你在工作中畅通无阻. 这套模型是基于 https://github.com/ker ...

  8. python3图片验证码识别

    http://my.cnki.net/elibregister/CheckCode.aspx每次刷新该网页可以得到新的验证码进行测试 以我本次查看的验证码图片为例,右键保存图片为image.jpg 下 ...

  9. 简单验证码识别 tessnet2

    今天突然间对识别验证码感兴趣,于是网上搜了一下 最简单的是引用tessnet2.dll,然后通过它来识别,代码如下 private void button1_Click(object sender, ...

随机推荐

  1. java集合系列之LinkList

    概要  第1部分 LinkedList介绍第2部分 LinkedList数据结构第3部分 LinkedList源码解析(基于JDK1.6.0_45) 第5部分 LinkedList示例 转载请注明出处 ...

  2. bzoj 1171 并查集优化顺序枚举 | 线段树套单调队列

    详见vfleaking在discuss里的题解. 收获: 当我们要顺序枚举一个序列,并且跳过某些元素,那么我们可以用并查集将要跳过的元素合并到一起,这样当一长串元素需要跳过时,可以O(1)跳过. 暴力 ...

  3. 喵哈哈村的魔法考试 Round #2 (Div.2) 题解

    喵哈哈村的魔法考试 Round #2 (Div.2) 题解 A.喵哈哈村的战争 题解: 这道题就是for一遍,统计每个村子的战斗力的和,然后统计哪个村子的战斗力和大一点就好了. 唯一的坑点,就是这道题 ...

  4. What is OpenOCD?

    About OpenOCD was created by Dominic Rath as part of a 2005 diploma thesis written at the University ...

  5. git 拉取和获取 pull 和 fetch 区别

    使用Git  直接提交的话   直接 push 获取最新版本  有两种  拉取 和 获取 pull 和 fetch git  pull     从远程拉取最新版本 到本地  自动合并 merge   ...

  6. 虫趣:BAD POOL CALLER (par1: 0x20)

    [作者:张佩] [原文:http://www.yiiyee.cn/Blog/0x19-1/] 内核在管理内存的时候,为了提高内存使用效率,对于小片内存的申请(小于一个PAGE大小),都是通过内存池来操 ...

  7. STM32F103 TIM3定时器初始化程序

    //TIM3 分频 #define TIM3_DIV1 (1-1) #define TIM3_DIV18 (18-1) #define TIM3_DIV72 (72-1) //************ ...

  8. android在代码中四种设置控件背景颜色的方法(包含RGB)

    转载请注明出处: http://blog.csdn.net/fth826595345/article/details/9208771  TextView tText=(TextView) findVi ...

  9. Revit API移动风管

    移动风管曲线就可以移动风管 , , ));//向上移动3         ts.Commit();         return Result.Succeeded;     } } url:http: ...

  10. PostgreSQL学习手册(目录)

    原文地址:http://www.cnblogs.com/stephen-liu74/archive/2012/06/08/2315679.html 事实上之前有很长一段时间都在纠结是否有必要好好学习它 ...