Python识别登录验证码(附完整代码)

【项目介绍】

网络迅速在人类生活中扎根,我们每天都会不可避免地接触大量网站和碎片化的信息,为了保护用户的账号安全和防止信息泄露,很多网站通行的方式是设置登录验证码。生活中,我们在登录微博,邮箱的时候,常常会碰到验证码。在工作时,如果想要爬取一些数据,也会碰到验证码的阻碍。所以,在经过一学期的学习之后,打算体验利用Python工具集实现基本向量空间搜索引擎理论下的简单验证码图片内数字的读取。认识验证码的一些特性,并利用Python中的pillow库完成对验证码的破解。

验证码可以有效防止机器恶意注册,对某个用户帐号使用特定程序暴力破解的方式进行不断地登陆尝试。不少网站为了防止用户利用机器人自动注册、登录、灌水,都采用了验证码技术。基于一串随机产生的数字或符号生成一幅图片,图片中加入一些干扰像素(防止OCP)就生成了简单的验证码。由用户识别其中的信息,输入表单提交网站验证,验证成功后才能使用某项功能。验证码具有以下特性:

  1. 一般用于防止批量注册,还有各大论坛用来避免大规模匿名回帖现象的发生。
  2. 简单易操作,人机交互性好
  3. 安全系数低,容易被破解

【环境搭建】

  1. 使用Pycharm作为开发环境
  2. Python版本:3.9.6
  3. 相关工具包:PIL.Image, math, os, string, hashlib, time(Pilow是一个Python图像处理库)

【项目原理】

首先针对一个验证码图片进行像素颜色统计检测,并人工验证哪些颜色组成了验证码的数字。 利用上一步得到的颜色,通过判断该颜色所在的横坐标,将验证码中每个数字所在的横坐标范围确定下来。 利用单数字图片与Pillow的Image.getdata()方法,得到每种数字或小写字母的有效像素的集合,作为“训练集”。 最后,利用上两步得到的“验证码的数字坐标集”与“训练集”,在VectorCompare.relation()算法下,比较验证码每一位与训练集中每一个字符的数据,选最相似(相同坐标值相同的次数最多)的那个返回,这样就得到了验证码图片中数字及字母的内容。

【框架图】

【程序流程处理图】

【模块详细实现步骤】

准备工作如下:

在windowsx10下安装pillow(PIL)库

win+r,打开“运行”,再输入cmd,打开命令提示符;

输入pip install pillow,回车,等待约2分钟,安装成功;

安装的版本为Pillow-8.4.0-cp310-cp310-win_amd64.whl (3.2 MB);

输入pip list可查看pyhton已安装库的最新版本。

下载实验中用的验证码文件:

http://labfile.oss.aliyuncs.com/courses/364/python_captcha.zip

将实验过程中使用的验证码文件下载到/password/Code目录下,解压后,在python_captcha目录下新建crack.py文件,进行编辑:

启动命令行输入如下指令:

start powershell

在powershell中我们输入一下命令

$client = new-object System.Net.WebClient

$client.DownloadFile(' http://labfile.oss.aliyuncs.com/courses/364/python_captcha.zip', 'D:\python\password\Code\python_captcha.zip')

下载完成后解压缩:(需要下载unzip;地址:http://gnuwin32.sourceforge.net/packages/unzip.htm)

键入命令:unzip python_captcha.zip

新建crack.py文件
type nul>crack.py

至此完成所有准备工作,下面开始正式编写代码

分析图片组成像素

将captcha.gif复制到开发目录下,用Pillow打开这个图片(Image.open()),并转换为8-bit彩色(Image.convert()),并观察哪些像素构成了数字的绝大部分(Image.histogram())。

#-*- coding:utf8 -*-

from PIL import Image

im = Image.open("captcha.gif")

#(将图片转换为8位像素模式)

im.convert("P")

# 打印颜色直方图

print(im.histogram())

输出:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0 , 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 2, 0, 1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 3, 1, 3, 3, 0, 0, 0, 0, 0, 0, 1, 0, 3, 2, 132, 1, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 15, 0 , 1, 0, 1, 0, 0, 8, 1, 0, 0, 0, 0, 1, 6, 0, 2, 0, 0, 0, 0, 18, 1, 1, 1, 1, 1, 2, 365, 115, 0, 1, 0, 0, 0, 135, 186, 0, 0, 1, 0, 0, 0, 116, 3, 0, 0, 0, 0, 0, 21, 1, 1, 0, 0, 0, 2, 10, 2, 0, 0, 0, 0, 2, 10, 0, 0, 0, 0, 1, 0, 625]

若输出颜色直方图,说明上述操作成功。

获取颜色直方图

颜色直方图的每一位数字都代表了在图片中含有对应位的颜色的像素的数量。每个像素点可表现 256种颜色,会发现白点是最多(白色序号255的位置,也就是最后一位,可以看到,有625个白色像素)。红像素在序号200左右,于是可以通过排序得到有用的颜色。

```pythondef getHis(image):#颜色直方图his = im.histogram()values = {}for i in range(256):values[i] = his[i]#默认reverse=False升序排列,reverse=True降序排列#按像素数量降序排列for j,k in sorted(values.items(),key=lambda x:x[1],reverse = True)[:10]:print j, k```

此处打印出图片,表明成功实现

构造一张黑白二值图片:

新建一个图片,同样采用8bit彩色模式,默认全白色,将有数字的部分填涂为黑色。(Image库的new(),getpixel(),putpixel())

```python#-*- coding:utf8 -*-from PIL import Imageimage = Image.open("captcha.gif")def blackWhite(image):# 通过size属性可以获取图片的尺寸。这是一个二元组,包含水平和垂直方向上的像素数im2 = Image.new("P", image.size, 255)# 将图片转换为8位像素模式image.convert("P")temp = {}for x in range(image.size[1]):# 这里y指的是纵向,y = a是点(a,...)构成的直线for y in range(image.size[0]):''' getpixel函数是用来获取图像中某一点的像素的RGB颜色值,getpixel的参数是一个坐标点。对于图像的不同的模式,getpixel函数返回的值有所不同。'''pix = image.getpixel((y, x))temp[pix] = pix# 这些是需要得到的数字if pix == 220 or pix == 227:im2.putpixel((y, x), 0)im2.save('new.gif')return im2im2 = blackWhite(image)im2.show()```

提取单个字符图片接下来获取单个字符的像素集合,对其进行纵向切割

```python# 提取单个字符像素合集
def pixelCollection(blackWhiteCaptcha):inletter = Falsefoundletter = Falsestart = 0end = 0im2 = blackWhiteCaptchaletters = []# 获取每个字符的始末位置# 横向切割for y in range(im2.size[0]):# 纵向切割for x in range(im2.size[1]):pix = im2.getpixel((y, x))if pix != 255:inletter = Trueif foundletter == False and inletter == True:foundletter = Truestart = yif foundletter == True and inletter == False:foundletter = Falseend = yletters.append((start, end))inletter = False# print(letters)return letters# 打开一张验证码图
image = Image.open("captcha.gif")blackWhiteCaptcha = blackWhite(image)print(pixelCollection(blackWhiteCaptcha))```输出[(6, 14), (15, 25), (27, 35), (37, 46), (48, 56), (57, 67)]

此处得到得到每个字符开始和结束的列序号。

接下来对图片进行切割,得到每个字符所在的那部分图片:

利用黑色像素所在的横坐标的位置,设计算法得到每一位字符所在的横坐标范围。该范围可以利用起来对图片进行分割并保存(使用Image.crop())。

```pythonimport hashlib
import time# 识别字符个数
count = 0# 对验证码图片进行切割
for letter in letters:# md5加密生成每个字符图片的名称m = hashlib.md5()# 前两个值为左上角坐标,后两个值为右下角坐标im3 = blackWhiteCaptcha.crop((letter[0], 0, letter[1], blackWhiteCaptcha.size[1]))guess = []im3.save("./%s.gif"%(m.hexdigest()))count += 1```

用 Python 类实现向量空间

参考利用基本向量空间搜索引擎论文(http://ondoc.logand.com/d/2697/pdf),写出向量比较算法。这里涉及到较复杂的知识,需要理解。

在这里使用向量空间搜索引擎来做字符识别,它具有很多优点:

  1. 不需要大量的训练迭代;
  2. 不会训练过度;
  3. 可以随时加入/移除错误的数据查看效果;
  4. 很容易理解和编写成代码;
  5. 提供分级结果,并且可以查看最接近的多个匹配;
  6. 对于无法识别的东西只要加入到搜索引擎中,马上就能识别。

当然它也有缺点,例如分类的速度比神经网络慢很多,也不能找到自己的方法解决问题等等。

```pythonimport mathclass VectorCompare:# 计算矢量大小def magnitude(self,concordance):total = 0for word,count in concordance.items():#返回count的2次幂total += count ** 2return math.sqrt(total)# 计算矢量之间的 cos 值def relation(self,concordance1, concordance2):relevance = 0topvalue = 0for word, count in concordance1.items():if word in concordance2:topvalue += count * concordance2[word]return topvalue / (self.magnitude(concordance1) * self.magnitude(concordance2))```

它会比较两个 python 字典类型并输出它们的相似度(用 0~1 的数字表示)

将之前的内容放在一起,接下来是取大量验证码提取单个字符图片作为训练集合。也可以使用iconset 目录下存放的已有的训练集,将“训练集”中的字符图片的像素数据读入。

识别验证码图片

利用向量比较算法,比较训练集与验证码每一位的相符程度,并保存结果。打印该结果,观察效果。

```python# 将图片转换为矢量
def buildvector(im):d1 = {}count = 0for i in im.getdata():d1[count] = icount += 1return d1# 字符图标集合
def letterIconset():#需要训练的字符
iconset = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
# 加载训练集
imageset = []
for letter in iconset:for img in os.listdir('./iconset/%s/'%(letter)):temp = []if img != "Thumbs.db" and img != ".DS_Store":temp.append(buildvector(Image.open("./iconset/%s/%s"%(letter, img))))imageset.append({letter:temp})return imageset# 识别验证码
def identifyCaptcha(image):# 黑白二值图片中字符的像素信息blackWhiteCaptcha = blackWhite(image)# 单个字符的像素集合letters = pixelCollection(blackWhiteCaptcha)# 字符图标集合imageset = letterIconset()# 向量空间v = VectorCompare()# 识别字符个数
count = 0
# 对验证码图片进行切割
for letter in letters:m = hashlib.md5()im3 = blackWhiteCaptcha.crop((letter[0], 0, letter[1], blackWhiteCaptcha.size[1]))guess = []# 将切割得到的验证码小片段与每个训练片段进行比较for image in imageset:for x,y in image.items():if len(y) != 0:guess.append( ( v.relation(y[0],buildvector(im3)),x) )# 默认reverse=False升序排列,reverse=True降序排列
guess.sort(reverse=True)
print(guess[0])count += 1#打开一张验证码图image = Image.open(“captcha.gif”)#识别验证码并返回结果identifyCaptcha(image)```

接下来运行代码查看结果:

python crack.py

​
输出:(0.9637681159420289, '7') (0.96234028545977, 's') (0.9286884286888929, '9') (0.9835037060984447, 't') (0.9675116507250627, '9') (0.96989711688772623, 'j')​

与验证码中的字符一一对应,成功识别。

实现功能执行代码行:im = Image.open("captcha.gif") ,更改此处即可对其他验证码进行识别。

将以上各模块分装成函数,整理思路并运行代码,检验能否成功识别验证码。完整代码在crack1.py文件中。最终实验结果如图

选取多张图片进行验证,得到的结果均与预期结果均相同。

【项目总结】

该课程项目通过理论联系算法,得到了一种较为容易理解的机器学习算法,可以用来体验较原始的机器学习算法的实质,并为Python读取无干扰无扭曲的简易验证码提供了一套方案。

【心得体会】

Python是一种跨平台的、库相当丰富的、计算机程序设计语言,语法简单,可读性强,应用广泛。

在该课程项目中使用分割图片+向量识别的方式,实现了简易的验证码破解。然而现在的验证码越来越复杂,此方法明显处理不了更加复杂的验证码,这时候就需要在现有的基础上增添新的判别方式,提升系统的适应性。项目仍然有需要改进之处,对python语言的学习将不会停止,能够熟练运用python语言写脚本,提升编程能力和水平。

附全部代码如下:

# -*- coding:utf-8 -*-
from PIL import Image
import hashlib
import time
import os
import math
import string# 向量空间类
class VectorCompare:# 计算矢量大小# magnitude()函数中的self代表类的实例,而非类,类似于this。def magnitude(self, concordance):total = 0for word, count in concordance.items():# 返回count的2次幂total += count ** 2return math.sqrt(total)# 计算矢量之间的cos值def relation(self, concordance1, concordance2):relevance = 0topvalue = 0# 字典的items方法:可以将字典中的所有项,以列表方式返回# 因为字典是无序的,所以用items方法返回字典的所有项,也是没有顺序的。for word, count in concordance1.items():if word in concordance2:topvalue += count * concordance2[word]return topvalue / (self.magnitude(concordance1) * self.magnitude(concordance2))# 将图片转换为矢量
def buildvector(image):d1 = {}count = 0for i in image.getdata():d1[count] = icount += 1return d1# 字符图标集合
def letterIconset():# 需要训练的字符iconset = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k','l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']# 字符训练集目录letterPath = 'iconset'# 加载训练集imageset = []for letter in iconset:for img in os.listdir(letterPath + '/%s/' % (letter)):temp = []# windows check...# if img != "Thumbs.db" and img != ".DS_Store":#     temp.append(buildvector(Image.open("./iconset/%s/%s" % (letter, img))))# imageset.append({letter: temp})# 过滤非gif格式的文件if img.endswith(".gif"):temp.append(buildvector(Image.open(letterPath + '/%s/%s' % (letter, img))))imageset.append({letter: temp})return imageset# 提取单个字符像素合集
def pixelCollection(blackWhiteCaptcha):inletter = Falsefoundletter = Falsestart = 0end = 0im2 = blackWhiteCaptchaletters = []# 获取每个字符的始末位置# 横向切割for y in range(im2.size[0]):# 纵向切割for x in range(im2.size[1]):pix = im2.getpixel((y, x))if pix != 255:inletter = Trueif foundletter == False and inletter == True:foundletter = Truestart = yif foundletter == True and inletter == False:foundletter = Falseend = yletters.append((start, end))inletter = False# print(letters)return letters# 通过size属性可以获取图片的尺寸。这是一个二元组,包含水平和垂直方向上的像素数
# 构造一张黑白二值图片
def blackWhite(image):im2 = Image.new("P", image.size, 255)# 将图片转换为8位像素模式image.convert("P")temp = {}for x in range(image.size[1]):# 这里y指的是纵向,y = a是点(a,...)构成的直线for y in range(image.size[0]):''' getpixel函数是用来获取图像中某一点的像素的RGB颜色值,getpixel的参数是一个坐标点。对于图像的不同的模式,getpixel函数返回的值有所不同。'''pix = image.getpixel((y, x))temp[pix] = pix# 这些是需要得到的数字if pix == 220 or pix == 227:im2.putpixel((y, x), 0)im2.save('new.gif')return im2# 识别验证码
def identifyCaptcha(image):# 黑白二值图片中字符的像素信息blackWhiteCaptcha = blackWhite(image)# 单个字符的像素集合letters = pixelCollection(blackWhiteCaptcha)# 字符图标集合imageset = letterIconset()# 向量空间v = VectorCompare()# 识别字符个数count = 0# 识别验证码guessLetter = ''# 对验证码图片进行切割for letter in letters:# md5加密生成每个字符图片的名称m = hashlib.md5()'''Image.crop(box=None):Returns a rectangular region from this image.The box is a 4-tuple defining the left, upper, right, and lower pixel coordinate.'''# 前两个值为左上角坐标# 后两个值为右下角坐标im3 = blackWhiteCaptcha.crop((letter[0], 0, letter[1], blackWhiteCaptcha.size[1]))guess = []# 将切割得到的验证码小片段与每个训练片段进行比较for image in imageset:for x, y in image.items():if len(y) != 0:guess.append((v.relation(y[0], buildvector(im3)), x))# 默认reverse=False升序排列,reverse=True降序排列guess.sort(reverse=True)print(guess[0])guessLetter += guess[0][1]count += 1return count,guessLetterdef getHis(image):# 颜色直方图his = image.histogram()values = {}for i in range(256):values[i] = his[i]# 按像素数量降序排列valueSeq = {}# 默认reverse=False升序排列,reverse=True降序排列for j, k in sorted(values.items(), key=lambda x: x[1], reverse=True)[:11]:valueSeq[j] = k# print(j, k)# print(valueSeq)return valueSeq# 主函数
if __name__ == '__main__':# 打开一张验证码图image = Image.open("r2lvkd.gif")# 对图像进行处理,获取相关信息# 打印颜色直方图getHis(image)# 识别验证码返回结果result = identifyCaptcha(image)print("识别出%d位验证码:%s" % (result))

Python识别登录验证码相关推荐

  1. Python - WebDriver 识别登录验证码

    Python - WebDriver 识别登录验证码 没什么可说的直接上代码! #-*-coding:utf-8-*- # Time:2017/9/29 7:16 # Author:YangYangJ ...

  2. Python模拟登录,Python识别图形验证码实现自动登陆

    前言 利用Python识别图形验证码,selenium模块实现自动登陆.废话不多说. 让我们愉快地开始吧~ 开发工具 Python版本: 3.6.4 相关模块: re: numpy模块: pytess ...

  3. Python识别网站验证码的几种方式

    Python识别网站验证码的几种方式 1.云打码平台(已完结) 优势:现成的平台,只需要调用即可,成功率较高. 劣势:需要一点软妹币. 这是最简单的运用,国内常用的打码平台有: 云打码(http:// ...

  4. Jmeter识别登录验证码_使用百度AI图片识别技术

    Jmeter识别登录验证码_使用百度AI图片识别技术 一.环境准备 1.下载并引用以下Jar包 2.将下载的jar包放至Jmeter中的lib目录中即可使用 二.使用步骤 1.在获得验证码的请求后使用 ...

  5. python 识别登陆验证码图片(完整代码)_Python 实现简单图片验证码登录

    如何实现,执行代码报错了 from PIL import Image from pytesseract import image_to_string, pytesseract pytesseract. ...

  6. python网页登录验证码不显示_进网页需要验证码?不好意思,Python从来不惧各种验证码!...

    今天 要来说说滑动验证码了 大家应该都很熟悉 点击滑块然后移动到图片缺口进行验证 现在越来越多的网站使用这样的验证方式 为的是增加验证码识别的难度 那么,对于这种验证码应该怎么破呢 接下来就是见证神奇 ...

  7. python 识别图形验证码_Python图片验证码降噪处理实例!此乃识别验证码神技!...

    图片验证码算是网络数据采集上的一道拦路虎,虽然有诸多公开的ORC接口.云打码平台,一旦大规模应用起来,还是内部写程序进行识别处理比较好. 而自己写代码进行识别的话,又有很多种方案,比如最近火热的神经网 ...

  8. 教程 | 用Python识别图片验证码中的文字

    作者 | 老表 来源 | 简说Python(ID:xksnh888xksnh888) [导语]在今天这篇文章中,作者分享给大家一个有趣又干货满满的 Python 项目.通过这份教程,大家不仅又多了一个 ...

  9. python 识别登陆验证码图片(完整代码)

    在编写自动化测试用例的时候,每次登录都需要输入验证码,后来想把让python自己识别图片里的验证码,不需要自己手动登陆,所以查了一下识别功能怎么实现,做一下笔记. 首选导入一些用到的库,re.Imag ...

最新文章

  1. C#调用USER32.DLL的API函数
  2. boost::hana::basic_tuple用法的测试程序
  3. 光纤中继器的安装调试
  4. 狗窝里的小日子- 5 ...
  5. C++中友元函数,友元类数详解
  6. python时间函数详解_Python 日期的转换及计算的具体使用详解
  7. Android 数据访问之External Storage 数据保存在sd卡 demo+笔记
  8. 用JFreeChart 来分析Cassandra/Oracle插入海量数据的性能
  9. 专访ThoughtWorks王磊:从单块架构到微服务架构
  10. 注塑机c语言程序,注塑机PLC程序(完整版).docx
  11. 动易 mysql_动易数据转成dedecms的php程序
  12. WIN7专业版32/64位更换系统语言注意
  13. vscode安装程序员鼓励师插件
  14. 图片怎么批量转换格式?
  15. python中plot是什么意思_讲述python中ubplot的详细用法
  16. Mixly----利用超声波传感器控制LED灯
  17. html文档中的元素分为两部分,云开HTML5开发基础与应用(20秋)形考作业2【标准答案】...
  18. jmeter+csv+ant接口自动化测试--设计jmeter脚本(一)
  19. 内行看门道:看似“佛系”的《QQ炫舞手游》,背后的音频技术一点都不简单
  20. matlab mat文件转fcf,Matlab的FDATool设计滤波器导出

热门文章

  1. 红米note2能刷机没显示无服务器,红米note2刷机变砖了怎么办? 红米note2救砖的方法...
  2. 形态学 - 开运算和闭运算
  3. 服务器预览图片不显示不出来,服务器预览图片不显示
  4. NCD2019 A. Hasan the lazy judge 二分
  5. 运动戴什么耳机好,推荐五款无线运动蓝牙耳机
  6. 惠普Elite蜻笔记本系统损坏怎么U盘重装教学
  7. Spyder连接远程服务器
  8. 模板消息(业务通知)
  9. 无线耳机什么牌子好性价比高?2023年高品质蓝牙耳机盘点
  10. Python数据可视化 Pyecharts 制作 Effectscatter 涟漪散点图