一、写在前面
现在无论大大小小的网站,基本上都会使用验证码,登录的时候要验证,下载的时候要验证,而使用的验证码也从那些简简单单的字符图形验证码“进化”成了需要进行图文识别的验证码、需要拖动滑块的滑动验证码、甚至还有手机验证码。当你与之打交道的时候,有没有考虑过其背后的原理呢?当然了,对于那些复杂的验证码我们想要弄得一清二楚还是很难的,但是可以挑软柿子捏嘛--字符图形验证码,就这样,我决定用 Python + Flask 制作出一个简单的验证码系统来,话不多说,撸起袖子加油干!
二、基本思路
一个简单的验证码系统,要实现的目标包括能够不断刷新验证码和对用户输入的内容进行验证,若验证成功则进行后续操作,若失败则给出提示信息并要求重新输入。
但是没有大量验证码图片怎么办呢?正所谓“自己动手,丰衣足食”,Python 所具有的丰富的第三方库使得产生大量验证码图片这一需求变得甚是简单了,这里主要使用的模块是 pillow。
有了验证码图片之后,要做的就是将其显示在前端页面上,并且要能够更新验证码,这利用 Flask 可以很方便地实现。然后就是输入验证码和对输入的内容进行验证了,这里我是用 JS 实现验证的。
三、具体步骤
1.生成验证码图片
前面已经提过这一步主要使用的模块是 pillow,没有安装的话可以使用 pip install pillow 进行安装。
PIL:Python Image Library,是 Python 处理图片的标准库,不过 PIL 仅支持到 Python2.7,之后有人在其基础上创建了兼容的版本,名字就叫做 pillow。
新建一个 Flask 项目:CaptchaTest,然后创建一个 generate.py。要生成一个验证码图片,首先得创建一张图片,可以用 pillow 模块中的 Image.new() 实现。然后需要生成验证码文本并将其写入到前面生成的图片上,除此之外,我们还可以加入一些干扰元素增加识别的难度。下面是几张生成的验证码图片:
最终得到的生成验证码图片的代码如下:
1 from random import randint 2 from PIL import Image, ImageDraw, ImageFont 3 4 5 def get_random_color(): 6 # 随机颜色RGB 7 return randint(120, 200), randint(120, 200), randint(120, 200) 8 9 10 def get_random_code(): 11 # 随机字符 12 codes = [[chr(i) for i in range(48, 58)], [chr(i) for i in range(65, 91)], [chr(i) for i in range(97, 123)]] 13 codes = codes[randint(0, 2)] 14 return codes[randint(0, len(codes)-1)] 15 16 17 def generate_captcha(width=140, height=60, length=4): 18 # 生成验证码 19 img = Image.new("RGB", (width, height), (250, 250, 250)) 20 draw = ImageDraw.Draw(img) 21 font = ImageFont.truetype("static/font/font.ttf", size=36) 22 # 验证码文本 23 text = "" 24 for i in range(length): 25 c = get_random_code() 26 text += c 27 28 rand_len = randint(-5, 5) 29 draw.text((width * 0.2 * (i+1) + rand_len, height * 0.2 + rand_len), c, font=font, fill=get_random_color()) 30 # 加入干扰线 31 for i in range(3): 32 x1 = randint(0, width) 33 y1 = randint(0, height) 34 x2 = randint(0, width) 35 y2 = randint(0, height) 36 draw.line((x1, y1, x2, y2), fill=get_random_color()) 37 # 加入干扰点 38 for i in range(16): 39 draw.point((randint(0, width), randint(0, height)), fill=get_random_color()) 40 # 保存图片 41 img.save("static/captcha/" + text + ".jpg") 42 return text + ".jpg" 43 44 45 if __name__ == "__main__": 46 for i in range(1000): 47 generate_captcha()
2.显示验证码图片
在进行完上一步之后,我们已经得到了1000张验证码图片,都保存在 static 下的 captcha 文件夹下。那么现在的问题就是如何将验证码图片显示在页面上,要解决这个问题,首先要定义一个路由,用于随机选取验证码图片并返回路径。
在 Flask 中 route() 装饰器把一个函数绑定到 URL 上,不仅能配置静态 URL,而且能配置动态 URL,不过这里使用静态 URL 就行了。定义该路由的代码如下:
1 @app.route('/get_captcha', methods=['GET']) 2 def get_captcha(): 3 img_list = os.listdir("static/captcha") 4 img = img_list[random.randint(0, 1000)] 5 return os.path.join("static/captcha", img)
其中 os.listdir() 用于列举文件夹下的内容,os.path.join() 用于返回图片路径。
3.刷新验证码图片
刷新验证码图片的功能可以通过使用 Ajax 来实现,主要过程是先向后端发送请求,请求成功之后会得到一个验证码图片路径, 然后再设置图片的 src 属性,达到刷新验证码的目的。在 Ajax 中的 URL 可以直接写静态 URL,还能使用 url_for 来反向解析获取对应的 URL,使用方法如下:
1
4.验证码内容验证
在输入验证码内容后,需要对输入的内容进行验证。因为前面生成验证码图片的时候直接用的图片内容来命名的,所以这里就可以用 JavaScript 来获取图片名称,再将输入框中的内容获取到,把两者进行比对,这一步还可以做一个忽略大小写,至于具体代码就不放了。
四、运行截图
首先是一张运行页面的截图,点击“看不清楚,换一张”可以刷新验证码,点击“确认”可以验证输入的内容是否正确:
当输入的内容正确的时候,给出一个验证成功的提示:
到这里为止,一个简单的验证码系统就做出来了,当然还有很多可以去完善的地方,比如使用更复杂的验证码,对验证次数进行限制等等。
完整代码已上传到 GitHub!