在web页面中,经常会遇到验证码,这对于我这么一个热爱web自动化测试人员,就变成了一件头疼的事。于是千方百计找各种资源得到破解简单的验证码方法。

识别验证码

  大致分如下几个步骤:

    1.获取验证码图片

    2.灰度处理

    3.增加对比度

    4.降噪

    5.识别

>>>>获取验证码

  通过各种方法,将含有验证码的图片获取并存贮在本地。

  本次的方法是:截取当前web页面,然后获取验证码在web页面中的位置,通过位置定位验证码图片再次截取。

  以163邮箱注册页面为例

  用到的库:selenium、PIL

  如果是python2.x,pip install PIL;在python3.x中PIL被移植到pillow 中,所以导入时需要导入pillow,pip install pillow  

  1. from PIL import Image
  2.  
  3. import time
  4. from selenium import webdriver
  5.  
  6. def get_code_img(driver):
  7.  
  8. time.sleep(1)
  9.  
  10. # 截取整个浏览器图
  11. driver.save_screenshot('webImg.png')
  12.  
  13. # 获取code元素坐标
  14. code_element = driver.find_element_by_id('vcodeImg')
  15.  
  16. # 获取code图片坐标值
  17. left_location = code_element.location['x']
  18. top_location = code_element.location['y']
  19.  
  20. right_location = code_element.size['width'] + left_location
  21. below_location = code_element.size['height'] + top_location
  22.  
  23. # 通过坐标值得到code image图
  24. web_img = Image.open("webImg.png")
  25. code_img = web_img.crop((left_location,top_location,right_location,below_location))
  26. code_img.save("codeImg.png")

  save_screenshot:webdriver中提供的一个方法,截取整个web页面

  code_element.location:获取某个的位置

  例如:print(code_element.location)的结果为:{'x': 632, 'y': 511}

  他是以图片的左上角为基准点,向右为x,向下为y

  code_element.size:获取图片的尺寸

  crop:是通过四个坐标点获取位置截图并且生成一张新图,他是Image 中的一个方法。

运行代码

  1. if __name__ == '__main__':
  2.  
  3. base_url = 'http://reg.email.163.com/unireg/call.do?cmd=register.entrance&from=126mail'
  4.  
  5. driver = webdriver.Chrome()
  6. driver.maximize_window()
  7. driver.get(base_url)
  8. get_code_img(driver)
  9. driver.close()

运行后获得两张图片webImg.png和codeImg.png。codeImg如下:

>>>>灰度处理/增加对比色

  将图片的颜色变成灰色并且增加对比色,识别时减少不必要的干扰。

  1. def gray_img(img):
  2. code_img = Image.open(img)
  3. # 转换为灰度
  4. gray_img = code_img.convert('L')
  5. # 增强亮度
  6. enhance_img = ImageEnhance.Contrast(gray_img)
  7. enhance_img = enhance_img.enhance(3)
  8. return enhance_img
  9.  
  10. if __name__ == '__main__':
  11.  
  12. gray_img('codeImg.png').show()

  运行后结果

>>>>降噪

  根据一个点A的RGB值,与周围的4个点的RGB值进行比较,最初设定一个值N即判断数量(0<N<4),当A的RGB值与周围4个点的RGB相等数小于N时会被视为燥点,被消除。

  1. def clear_noise(img):
  2.  
  3. noise_img = img.load()
  4. # 获取图片的尺寸
  5. w,h = img.size
  6.  
  7. for y in range(1,h-1):
  8. for x in range(1,w-1):
  9. count = 0
  10. if noise_img[x,y-1] > 245:
  11. count = count + 1
  12. if noise_img[x,y+1] > 245:
  13. count = count + 1
  14. if noise_img[x-1,y] > 245:
  15. count = count + 1
  16. if noise_img[x+1,y] > 245:
  17. count = count + 1
  18. if noise_img[x-1,y-1] > 245:
  19. count = count + 1
  20. if noise_img[x-1,y+1] > 245:
  21. count = count + 1
  22. if noise_img[x+1,y-1] > 245:
  23. count = count + 1
  24. if noise_img[x+1,y+1] > 245:
  25. count = count + 1
  26. if count > 4:
  27. noise_img[x,y] = 255
  28. return img
  29.  
  30. if __name__ == '__main__':
  31. img = gray_img('codeImg.png')
  32. clear_noise(img).show()

运行后结果

>>>>识别

  识别使用的是pytesseract包。

  Pytesseract包依赖于tesseract,安装的时候两个都需安装

  详情参考

    tesseract: https://github.com/sirfz/tesserocr

    pytesseract:https://github.com/madmaze/pytesseract

  1. text = pytesseract.image_to_string(img)
  2. print(text)

  很遗憾,上面的图没有识别出来。

完整代码运行识别

以下图验证码为例

  1. from PIL import Image, ImageEnhance
  2. import time
  3. import pytesseract
  4. from selenium import webdriver
  5.  
  6. def clear_noise(img):
  7. noise_img = img.load()
  8. # 获取图片的尺寸
  9. w,h = img.size
  10.  
  11. for y in range(1,h-1):
  12. for x in range(1,w-1):
  13. count = 0
  14. if noise_img[x,y-1] > 245:
  15. count = count + 1
  16. if noise_img[x,y+1] > 245:
  17. count = count + 1
  18. if noise_img[x-1,y] > 245:
  19. count = count + 1
  20. if noise_img[x+1,y] > 245:
  21. count = count + 1
  22. if noise_img[x-1,y-1] > 245:
  23. count = count + 1
  24. if noise_img[x-1,y+1] > 245:
  25. count = count + 1
  26. if noise_img[x+1,y-1] > 245:
  27. count = count + 1
  28. if noise_img[x+1,y+1] > 245:
  29. count = count + 1
  30. if count > 4:
  31. noise_img[x,y] = 255
  32. return img
  33.  
  34. def get_code_img(driver):
  35.  
  36. time.sleep(1)
  37.  
  38. # 截取整个浏览器图
  39. driver.save_screenshot('webImg.png')
  40.  
  41. # 获取code元素坐标
  42. code_element = driver.find_element_by_id('vcodeImg')
  43.  
  44. # 获取code图片坐标值
  45. left_location = code_element.location['x']
  46. top_location = code_element.location['y']
  47.  
  48. right_location = code_element.size['width'] + left_location
  49. below_location = code_element.size['height'] + top_location
  50.  
  51. # 通过坐标值得到code image图
  52. web_img = Image.open("webImg.png")
  53. code_img = web_img.crop((left_location,top_location,right_location,below_location))
  54. code_img.save("codeImg.png")
  55.  
  56. def gray_img(img):
  57. code_img = Image.open(img)
  58. # 转换为灰度
  59. gray_img = code_img.convert('L')
  60. # 增强亮度
  61. enhance_img = ImageEnhance.Contrast(gray_img)
  62. enhance_img = enhance_img.enhance(3)
  63. return enhance_img
  64.  
  65. if __name__ == '__main__':
  66.  
  67. # base_url = 'http://reg.email.163.com/unireg/call.do?cmd=register.entrance&from=126mail'
  68. #
  69. # driver = webdriver.Chrome()
  70. # driver.maximize_window()
  71. # driver.get(base_url)
  72. # get_code_img(driver)
  73. # driver.close()
  74. img = gray_img('d.png')
  75. img = clear_noise(img)
  76. img.show()
  77. text = pytesseract.image_to_string(img)
  78. print(text)

  运行结果

  虽然还是失败的。但至少已经接近了...

  此次只是对验证码的识别做简单的尝试。虽然此方法识别率不是很高。当然网上有很多收费的识别平台,通过大量联系识别率是很高的,有兴趣的可以去了解下。

  在认识验证码后我又来兴趣了,想去探个究竟验证码是怎样生成的...下次分享(皮一下)

python之验证码的生成

  在识别验证码的玩虐后,决定去看看他是怎么生成的。

 大致步骤:

1.创建图片

2.对背景像素处理

3.写入识别码

4.增加干扰线

5.滤镜处理

用到的库

  1. import random
  2.  
  3. from PIL import Image, ImageFont, ImageDraw,ImageFilter

  在开始之前,了解下Image下图片的基本属性

  print(Image.open('img.jpeg'))

  结果:<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x291 at 0x103BA3FD0>

    打印的是:图片格式、mode:彩色值、size:尺寸

  也可以直接获取该图片的相关属性

  img = Image.open('img.jpeg')

  print(img.size, img.format, img.mode)

    结果: (500, 291) JPEG RGB

现在开始生成验证码

>>>>创建图片

  1. from PIL import Image
  2.  
  3. width = 240
  4. height = 60
  5.  
  6. # 图像生成
  7. image = Image.new('RGB', (width,height), color='red')
  8. image.show()

  new()是创建一个图片,第一个参数为图片mode也就是色彩值;

  第二个参数为图片的大小;

  第三个参数是图片颜色。

  show()方法是展示图片

  运行后结果

>>>>对背景像素处理

  1. # 填充每个像素点
  2. for i in range(width):
  3. for j in range(height
  4.  
  5. ):
  6. draw.point((i,j), fill=random_bgcolor())

  random_bgcolor():也是自定义的方法,随机产生颜色。

  1. def random_bgcolor():
       return (random.randint(60,200), random.randint(60,200),random.randint(60,200))

  返回一个RGB色彩值,其中的颜色取值根据需要设置吧。

打印结果

>>>>写入识别码

  1. draw = ImageDraw.Draw(image)
  2. # 写入信息
  3. for i in range(4):
  4. draw.text((60*i+10, 10), get_random(1,4), font=font, fill=random_color())

  ImageDraw.Draw(image)是在图片image上创建一个画笔

  For循环:循环产生4个数字或字母

  draw.text()方法是写入的内容,

    第一个参数是坐标,坐标自己通过图片尺寸稍为计算下,合理布局;

    第二个参数是写入的内容值,这里传入的是让系统随机产生一个数,方法可以自己定义;

    第三个font为字体,设置的字体必须存在

    第四个是对写入的内容附上颜色,这里传入的是让系统随机产生一个颜色,方法可以自己定义;

第二个参数的方法如下:

  1. def get_random(num,many):
  2. for i in range(many):
  3. s = ""
  4. for j in range(num):
  5. n = random.randint(1,2) # n==1生成数字,n=2生成字母
  6. if n == 1:
  7. num1 = random.randint(0, 9)
  8. s +=str(num1)
  9. else:
  10. s +=str(random.choice(string.ascii_letters))
  11.  
  12. return s

第三个参数字体:

  1. font = ImageFont.truetype('Arial.ttf',36)

第四个参数的方法如下:

  直接返回RGB颜色值

  1. def random_color():
  2. return (random.randint(64,255), random.randint(64,255), random.randint(64,255))

  运行上面代码结果:

 

>>>>增加干扰线

  在生成的验证码图片上添加一条干扰线

  1. for i in range(2):
  2. x1 = random.randint(0, width)
  3. y1 = random.randint(0, height)
  4. x2 = random.randint(0, width)
  5. y2 = random.randint(0, height)
  6. draw.line((x1, y1, x2, y2), fill=random_bgcolor(),width=3)

  draw.line()是画线方法

  第一个参数:线条坐标,即位置。如上是在图片范围内位置随机

  第二个参数:线条的颜色,还是让随机产生

  第三个参数:线条的宽度,不设置的话默认为0

  运行结果

>>>>滤镜处理

  增加滤镜,可以增加颜色的不同

  很简单,一行代码搞定

  1. image = image.filter(ImageFilter.BLUR)

结果如下:

  非常抱歉,我设置产生的随机色颜色值没有调对,导致背景色和字体色颜色太接近,效果看起来不是很好。

  但是滤镜不是必须项,可以不设置。

完整代码如下

  1. import string
  2.  
  3. import random
  4. from PIL import Image, ImageFont, ImageDraw,ImageFilter
  5.  
  6. # 生成随机大小数字
  7. def get_random(num,many):
  8. for i in range(many):
  9. s = ""
  10. for j in range(num):
  11. n = random.randint(1,2) # n==1生成数字,n=2生成字母
  12. if n == 1:
  13. num1 = random.randint(0, 9)
  14. s +=str(num1)
  15. else:
  16. s +=str(random.choice(string.ascii_letters))
  17. return s
  18.  
  19. # 随机颜色RGB
  20. def random_color():
  21. return (random.randint(64,255), random.randint(64,255), random.randint(64,255))
  22.  
  23. # 随机颜色RGB
  24. def random_bgcolor():
  25. return (random.randint(60,200), random.randint(60,200), random.randint(60,200))
  26.  
  27. # 字体,字体大小
  28. font = ImageFont.truetype('Arial.ttf',36)
  29.  
  30. # 图片尺寸
  31. width = 240
  32. height = 60
  33.  
  34. # 图像生成
  35. image = Image.new('RGB', (width,height), color='red')
  36.  
  37. # 创建绘图对象
  38. draw = ImageDraw.Draw(image)
  39.  
  40. # 填充背景色
  41. for i in range(width):
  42. for j in range(height):
  43. draw.point((i,j), fill=random_bgcolor())
  44.  
  45. # 写入信息
  46. for i in range(4):
  47. draw.text((60*i+10, 10), get_random(1,4), font=font, fill=random_color())
  48.  
  49. # 插入干扰线
  50. for i in range(2):
  51. x1 = random.randint(0, width)
  52. y1 = random.randint(0, height)
  53. x2 = random.randint(0, width)
  54. y2 = random.randint(0, height)
  55. draw.line((x1, y1, x2, y2), fill=random_bgcolor(),width=3)
  56.  
  57. # 添加滤镜
  58. image = image.filter(ImageFilter.BLUR)
  59.  
  60. # 展示图片
  61. image.show()
  62.  
  63. # 保存
  64. image.save('code.png')

原文发布在 自动化软件测试 微信公众号,欢迎关注

原文地址:https://mp.weixin.qq.com/s/x3QT8njMX2wKPXKxqDPRyg

太嚣张了!他竟用Python绕过了“验证码”的更多相关文章

  1. pyinstaller打包的exe太大?你需要嵌入式python玄学 探索篇

    上篇我们讲到pip的安装以及普通库用pip的安装方法 CodingDog:pyinstaller打包的exe太大?你需要嵌入式python玄学 拓展篇​zhuanlan.zhihu.com 问题纷沓而 ...

  2. pyinstaller打包的exe太大?你需要嵌入式python玄学 拓展篇

    上篇我们讲到embedded版本的基础操作 CodingDog:pyinstaller打包的exe太大?你需要嵌入式python玄学 惊喜篇​zhuanlan.zhihu.com 可是却没有办法用pi ...

  3. pyinstaller打包的exe太大?你需要嵌入式python玄学 惊喜篇

    上篇讲到 pyinstaller打包exe太大的问题 CodingDog:pyinstaller打包的exe太大?你需要嵌入式python玄学 前提篇​zhuanlan.zhihu.com 那既然py ...

  4. Python随机生成验证码的两种方法

    Python随机生成验证码的方法有很多,今天给大家列举两种,大家也可以在这个基础上进行改造,设计出适合自己的验证码方法方法一:利用range Python随机生成验证码的方法有很多,今天给大家列举两种 ...

  5. Python识别网站验证码

    http://drops.wooyun.org/tips/6313 Python识别网站验证码 Manning · 2015/05/28 10:57 0x00 识别涉及技术 验证码识别涉及很多方面的内 ...

  6. python随机图片验证码的生成

    Python生成随机验证码,需要使用PIL模块. 安装: 1 pip3 install pillow 基本使用 1. 创建图片 1 2 3 4 5 6 7 8 9 from PIL import Im ...

  7. Python 生成随机验证码

    Python生成随机验证码  Python生成随机验证码,需要使用PIL模块. 安装: 1 pip3 install pillow 基本使用 1. 创建图片 1 2 3 4 5 6 7 8 9 fro ...

  8. Python生成随机验证码

    Python生成随机验证码,需要使用PIL模块. 安装: pip3 install pillow 基本使用 1.创建图片 from PIL import Image img = Image.new(m ...

  9. python 简单图像识别--验证码

    python  简单图像识别--验证码 记录下,准备工作安装过程很是麻烦. 首先库:pytesseract,image,tesseract,PIL windows安装PIL,直接exe进行安装更方便( ...

随机推荐

  1. VS2017、VS2019没有Setup安装项目(Visual Studio Installer)_解决方案

    前言: VS2010中有一个自带的安装部署项目,叫:Visual Studio Installer ,我们通常称为:setup项目,是一个用于自定义安装部署的项目方案.但是在VS2017,VS2019 ...

  2. MIP开发教程(三) 使用MIP-CLI工具调试组件

    一 . 在 mip-extensions 仓库中创建新的组件 二 . 预览调试组件 三 . 在 MIP 页中引用自己编写的 MIP 组件 四 . 组件提交到 GitHub 仓库时需要进行校验 站长开发 ...

  3. Android开发:UI相关(一)自定义样式资源

    一.自定义样式资源:   1.在drawble中新建xml资源文件:     如果新建的xml文件没有自动放置在drawable文件夹下,就手动移动到drawable下. 2.编写样式代码: < ...

  4. C语言随机数使用方法

    随机数在编程中还是有所应用,最近从网上学习到这方面一点知识,想把它写下来.一.使用随机数所需要的头文件和函数:        头文件:cstdlib(C++ 的 standard libraray)  ...

  5. webpack4升级指南

    webpack4升级指南 鉴于图书项目编译速度极慢的情况(项目里面module太多了,编译慢很正常)且最近需求不多(很少出现的空挡期).所以我觉得搞一波webpack升级,看看有没有帮助.webpac ...

  6. mac 下常用命令备忘录

    1.查看端口号 lsof -i: 2.杀死进程 kill 41321 3.查看文件夹文件 ls ls -l //看到文件及文件夹更多的内容 ls -a //隐藏的文件 ls -la //上面的组合 4 ...

  7. qml demo分析(threading-线程任务)

    一.关键类说明 qml内置了WorkerScript组件,该组件有一个source属性,可以加载js文件,含有一个名为message的信号,意味着他有一个默认的onMessage槽函数,除此之外他还有 ...

  8. C# 《编写高质量代码改善建议》整理&笔记 --(五)成员设计

    1.可以字段应该重构为属性 2.谨慎将数组或集合作为属性 数组和集合作为属性存在会引起这样的一个分歧:如果属性是只读的,我们通常会认为他是不可改变的.但是如果将只读属性应用于数组和集合,而元素的内容和 ...

  9. eclipse升级Android SDK Tool版本到25.2.5后运行项目报错Unable to build: the file dx.jar was not loaded from the SDK folder

    概述 由于最近通过SDK-Manager更新了build-tools,当要用到dx.jar这个包时,自动调用最新版本Android SDK build-tools中dx.jar,但是运行android ...

  10. Linux~学习笔记目录索引

    回到占占推荐博客索引 本篇文章是对自己学习Linux及在它的环境下部署工具的一个总结,以方便自己查阅,也给他人一个帮助,本文章同时会不断的更新,欢迎大家订阅! 本目录包括的内容会包括linux基础命令 ...