太嚣张了!他竟用Python绕过了“验证码”
在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
- from PIL import Image
- import time
- from selenium import webdriver
- def get_code_img(driver):
- time.sleep(1)
- # 截取整个浏览器图
- driver.save_screenshot('webImg.png')
- # 获取code元素坐标
- code_element = driver.find_element_by_id('vcodeImg')
- # 获取code图片坐标值
- left_location = code_element.location['x']
- top_location = code_element.location['y']
- right_location = code_element.size['width'] + left_location
- below_location = code_element.size['height'] + top_location
- # 通过坐标值得到code image图
- web_img = Image.open("webImg.png")
- code_img = web_img.crop((left_location,top_location,right_location,below_location))
- 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 中的一个方法。
运行代码
- if __name__ == '__main__':
- base_url = 'http://reg.email.163.com/unireg/call.do?cmd=register.entrance&from=126mail'
- driver = webdriver.Chrome()
- driver.maximize_window()
- driver.get(base_url)
- get_code_img(driver)
- driver.close()
运行后获得两张图片webImg.png和codeImg.png。codeImg如下:
>>>>灰度处理/增加对比色
将图片的颜色变成灰色并且增加对比色,识别时减少不必要的干扰。
- def gray_img(img):
- code_img = Image.open(img)
- # 转换为灰度
- gray_img = code_img.convert('L')
- # 增强亮度
- enhance_img = ImageEnhance.Contrast(gray_img)
- enhance_img = enhance_img.enhance(3)
- return enhance_img
- if __name__ == '__main__':
- gray_img('codeImg.png').show()
运行后结果
>>>>降噪
根据一个点A的RGB值,与周围的4个点的RGB值进行比较,最初设定一个值N即判断数量(0<N<4),当A的RGB值与周围4个点的RGB相等数小于N时会被视为燥点,被消除。
- def clear_noise(img):
- noise_img = img.load()
- # 获取图片的尺寸
- w,h = img.size
- for y in range(1,h-1):
- for x in range(1,w-1):
- count = 0
- if noise_img[x,y-1] > 245:
- count = count + 1
- if noise_img[x,y+1] > 245:
- count = count + 1
- if noise_img[x-1,y] > 245:
- count = count + 1
- if noise_img[x+1,y] > 245:
- count = count + 1
- if noise_img[x-1,y-1] > 245:
- count = count + 1
- if noise_img[x-1,y+1] > 245:
- count = count + 1
- if noise_img[x+1,y-1] > 245:
- count = count + 1
- if noise_img[x+1,y+1] > 245:
- count = count + 1
- if count > 4:
- noise_img[x,y] = 255
- return img
- if __name__ == '__main__':
- img = gray_img('codeImg.png')
- clear_noise(img).show()
运行后结果
>>>>识别
识别使用的是pytesseract包。
Pytesseract包依赖于tesseract,安装的时候两个都需安装
详情参考:
tesseract: https://github.com/sirfz/tesserocr
pytesseract:https://github.com/madmaze/pytesseract
- text = pytesseract.image_to_string(img)
- print(text)
很遗憾,上面的图没有识别出来。
完整代码运行识别
以下图验证码为例
- from PIL import Image, ImageEnhance
- import time
- import pytesseract
- from selenium import webdriver
- def clear_noise(img):
- noise_img = img.load()
- # 获取图片的尺寸
- w,h = img.size
- for y in range(1,h-1):
- for x in range(1,w-1):
- count = 0
- if noise_img[x,y-1] > 245:
- count = count + 1
- if noise_img[x,y+1] > 245:
- count = count + 1
- if noise_img[x-1,y] > 245:
- count = count + 1
- if noise_img[x+1,y] > 245:
- count = count + 1
- if noise_img[x-1,y-1] > 245:
- count = count + 1
- if noise_img[x-1,y+1] > 245:
- count = count + 1
- if noise_img[x+1,y-1] > 245:
- count = count + 1
- if noise_img[x+1,y+1] > 245:
- count = count + 1
- if count > 4:
- noise_img[x,y] = 255
- return img
- def get_code_img(driver):
- time.sleep(1)
- # 截取整个浏览器图
- driver.save_screenshot('webImg.png')
- # 获取code元素坐标
- code_element = driver.find_element_by_id('vcodeImg')
- # 获取code图片坐标值
- left_location = code_element.location['x']
- top_location = code_element.location['y']
- right_location = code_element.size['width'] + left_location
- below_location = code_element.size['height'] + top_location
- # 通过坐标值得到code image图
- web_img = Image.open("webImg.png")
- code_img = web_img.crop((left_location,top_location,right_location,below_location))
- code_img.save("codeImg.png")
- def gray_img(img):
- code_img = Image.open(img)
- # 转换为灰度
- gray_img = code_img.convert('L')
- # 增强亮度
- enhance_img = ImageEnhance.Contrast(gray_img)
- enhance_img = enhance_img.enhance(3)
- return enhance_img
- if __name__ == '__main__':
- # base_url = 'http://reg.email.163.com/unireg/call.do?cmd=register.entrance&from=126mail'
- #
- # driver = webdriver.Chrome()
- # driver.maximize_window()
- # driver.get(base_url)
- # get_code_img(driver)
- # driver.close()
- img = gray_img('d.png')
- img = clear_noise(img)
- img.show()
- text = pytesseract.image_to_string(img)
- print(text)
运行结果
虽然还是失败的。但至少已经接近了...
此次只是对验证码的识别做简单的尝试。虽然此方法识别率不是很高。当然网上有很多收费的识别平台,通过大量联系识别率是很高的,有兴趣的可以去了解下。
在认识验证码后我又来兴趣了,想去探个究竟验证码是怎样生成的...下次分享(皮一下)
python之验证码的生成
在识别验证码的玩虐后,决定去看看他是怎么生成的。
大致步骤:
1.创建图片
2.对背景像素处理
3.写入识别码
4.增加干扰线
5.滤镜处理
用到的库
- import random
- 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
现在开始生成验证码
>>>>创建图片
- from PIL import Image
- width = 240
- height = 60
- # 图像生成
- image = Image.new('RGB', (width,height), color='red')
- image.show()
new()是创建一个图片,第一个参数为图片mode也就是色彩值;
第二个参数为图片的大小;
第三个参数是图片颜色。
show()方法是展示图片
运行后结果
>>>>对背景像素处理
- # 填充每个像素点
- for i in range(width):
- for j in range(height
- ):
- draw.point((i,j), fill=random_bgcolor())
random_bgcolor():也是自定义的方法,随机产生颜色。
- def random_bgcolor():
return (random.randint(60,200), random.randint(60,200),random.randint(60,200))
返回一个RGB色彩值,其中的颜色取值根据需要设置吧。
打印结果
>>>>写入识别码
- draw = ImageDraw.Draw(image)
- # 写入信息
- for i in range(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为字体,设置的字体必须存在
第四个是对写入的内容附上颜色,这里传入的是让系统随机产生一个颜色,方法可以自己定义;
第二个参数的方法如下:
- def get_random(num,many):
- for i in range(many):
- s = ""
- for j in range(num):
- n = random.randint(1,2) # n==1生成数字,n=2生成字母
- if n == 1:
- num1 = random.randint(0, 9)
- s +=str(num1)
- else:
- s +=str(random.choice(string.ascii_letters))
- return s
第三个参数字体:
- font = ImageFont.truetype('Arial.ttf',36)
第四个参数的方法如下:
直接返回RGB颜色值
- def random_color():
- return (random.randint(64,255), random.randint(64,255), random.randint(64,255))
运行上面代码结果:
>>>>增加干扰线
在生成的验证码图片上添加一条干扰线
- for i in range(2):
- x1 = random.randint(0, width)
- y1 = random.randint(0, height)
- x2 = random.randint(0, width)
- y2 = random.randint(0, height)
- draw.line((x1, y1, x2, y2), fill=random_bgcolor(),width=3)
draw.line()是画线方法
第一个参数:线条坐标,即位置。如上是在图片范围内位置随机
第二个参数:线条的颜色,还是让随机产生
第三个参数:线条的宽度,不设置的话默认为0
运行结果
>>>>滤镜处理
增加滤镜,可以增加颜色的不同
很简单,一行代码搞定
- image = image.filter(ImageFilter.BLUR)
结果如下:
非常抱歉,我设置产生的随机色颜色值没有调对,导致背景色和字体色颜色太接近,效果看起来不是很好。
但是滤镜不是必须项,可以不设置。
完整代码如下
- import string
- import random
- from PIL import Image, ImageFont, ImageDraw,ImageFilter
- # 生成随机大小数字
- def get_random(num,many):
- for i in range(many):
- s = ""
- for j in range(num):
- n = random.randint(1,2) # n==1生成数字,n=2生成字母
- if n == 1:
- num1 = random.randint(0, 9)
- s +=str(num1)
- else:
- s +=str(random.choice(string.ascii_letters))
- return s
- # 随机颜色RGB
- def random_color():
- return (random.randint(64,255), random.randint(64,255), random.randint(64,255))
- # 随机颜色RGB
- def random_bgcolor():
- return (random.randint(60,200), random.randint(60,200), random.randint(60,200))
- # 字体,字体大小
- font = ImageFont.truetype('Arial.ttf',36)
- # 图片尺寸
- width = 240
- height = 60
- # 图像生成
- image = Image.new('RGB', (width,height), color='red')
- # 创建绘图对象
- draw = ImageDraw.Draw(image)
- # 填充背景色
- for i in range(width):
- for j in range(height):
- draw.point((i,j), fill=random_bgcolor())
- # 写入信息
- for i in range(4):
- draw.text((60*i+10, 10), get_random(1,4), font=font, fill=random_color())
- # 插入干扰线
- for i in range(2):
- x1 = random.randint(0, width)
- y1 = random.randint(0, height)
- x2 = random.randint(0, width)
- y2 = random.randint(0, height)
- draw.line((x1, y1, x2, y2), fill=random_bgcolor(),width=3)
- # 添加滤镜
- image = image.filter(ImageFilter.BLUR)
- # 展示图片
- image.show()
- # 保存
- image.save('code.png')
原文发布在 自动化软件测试 微信公众号,欢迎关注
原文地址:https://mp.weixin.qq.com/s/x3QT8njMX2wKPXKxqDPRyg
太嚣张了!他竟用Python绕过了“验证码”的更多相关文章
- pyinstaller打包的exe太大?你需要嵌入式python玄学 探索篇
上篇我们讲到pip的安装以及普通库用pip的安装方法 CodingDog:pyinstaller打包的exe太大?你需要嵌入式python玄学 拓展篇zhuanlan.zhihu.com 问题纷沓而 ...
- pyinstaller打包的exe太大?你需要嵌入式python玄学 拓展篇
上篇我们讲到embedded版本的基础操作 CodingDog:pyinstaller打包的exe太大?你需要嵌入式python玄学 惊喜篇zhuanlan.zhihu.com 可是却没有办法用pi ...
- pyinstaller打包的exe太大?你需要嵌入式python玄学 惊喜篇
上篇讲到 pyinstaller打包exe太大的问题 CodingDog:pyinstaller打包的exe太大?你需要嵌入式python玄学 前提篇zhuanlan.zhihu.com 那既然py ...
- Python随机生成验证码的两种方法
Python随机生成验证码的方法有很多,今天给大家列举两种,大家也可以在这个基础上进行改造,设计出适合自己的验证码方法方法一:利用range Python随机生成验证码的方法有很多,今天给大家列举两种 ...
- Python识别网站验证码
http://drops.wooyun.org/tips/6313 Python识别网站验证码 Manning · 2015/05/28 10:57 0x00 识别涉及技术 验证码识别涉及很多方面的内 ...
- python随机图片验证码的生成
Python生成随机验证码,需要使用PIL模块. 安装: 1 pip3 install pillow 基本使用 1. 创建图片 1 2 3 4 5 6 7 8 9 from PIL import Im ...
- Python 生成随机验证码
Python生成随机验证码 Python生成随机验证码,需要使用PIL模块. 安装: 1 pip3 install pillow 基本使用 1. 创建图片 1 2 3 4 5 6 7 8 9 fro ...
- Python生成随机验证码
Python生成随机验证码,需要使用PIL模块. 安装: pip3 install pillow 基本使用 1.创建图片 from PIL import Image img = Image.new(m ...
- python 简单图像识别--验证码
python 简单图像识别--验证码 记录下,准备工作安装过程很是麻烦. 首先库:pytesseract,image,tesseract,PIL windows安装PIL,直接exe进行安装更方便( ...
随机推荐
- VS2017、VS2019没有Setup安装项目(Visual Studio Installer)_解决方案
前言: VS2010中有一个自带的安装部署项目,叫:Visual Studio Installer ,我们通常称为:setup项目,是一个用于自定义安装部署的项目方案.但是在VS2017,VS2019 ...
- MIP开发教程(三) 使用MIP-CLI工具调试组件
一 . 在 mip-extensions 仓库中创建新的组件 二 . 预览调试组件 三 . 在 MIP 页中引用自己编写的 MIP 组件 四 . 组件提交到 GitHub 仓库时需要进行校验 站长开发 ...
- Android开发:UI相关(一)自定义样式资源
一.自定义样式资源: 1.在drawble中新建xml资源文件: 如果新建的xml文件没有自动放置在drawable文件夹下,就手动移动到drawable下. 2.编写样式代码: < ...
- C语言随机数使用方法
随机数在编程中还是有所应用,最近从网上学习到这方面一点知识,想把它写下来.一.使用随机数所需要的头文件和函数: 头文件:cstdlib(C++ 的 standard libraray) ...
- webpack4升级指南
webpack4升级指南 鉴于图书项目编译速度极慢的情况(项目里面module太多了,编译慢很正常)且最近需求不多(很少出现的空挡期).所以我觉得搞一波webpack升级,看看有没有帮助.webpac ...
- mac 下常用命令备忘录
1.查看端口号 lsof -i: 2.杀死进程 kill 41321 3.查看文件夹文件 ls ls -l //看到文件及文件夹更多的内容 ls -a //隐藏的文件 ls -la //上面的组合 4 ...
- qml demo分析(threading-线程任务)
一.关键类说明 qml内置了WorkerScript组件,该组件有一个source属性,可以加载js文件,含有一个名为message的信号,意味着他有一个默认的onMessage槽函数,除此之外他还有 ...
- C# 《编写高质量代码改善建议》整理&笔记 --(五)成员设计
1.可以字段应该重构为属性 2.谨慎将数组或集合作为属性 数组和集合作为属性存在会引起这样的一个分歧:如果属性是只读的,我们通常会认为他是不可改变的.但是如果将只读属性应用于数组和集合,而元素的内容和 ...
- 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 ...
- Linux~学习笔记目录索引
回到占占推荐博客索引 本篇文章是对自己学习Linux及在它的环境下部署工具的一个总结,以方便自己查阅,也给他人一个帮助,本文章同时会不断的更新,欢迎大家订阅! 本目录包括的内容会包括linux基础命令 ...