文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何通过 Serverless 轻松识别验证码?

2024-12-03 14:48

关注

本文转载自微信公众号「Serverless」,作者江昱。转载本文请联系Serverless公众号。

前言

Serverless 概念自被提出就倍受关注,尤其是近些年来 Serverless 焕发出了前所未有的活力,各领域的工程师都在试图将 Serverless 架构与自身工作相结合,以获取到 Serverless 架构所带来的“技术红利”。

验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断地登陆尝试。实际上验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。CAPTCHA 的问题由计算机生成并评判,但是这个问题只有人类才能解答,计算机是无法解答的,所以回答出问题的用户就可以被认为是人类。说白了,验证码就是用来验证的码,验证是人访问的还是机器访问的“码”。

那么人工智能领域中的验证码识别与 Serverless 架构会碰撞出哪些火花呢?本文将通过 Serverless 架构和卷积神经网络(CNN)算法,实现验证码识别功能。

浅谈验证码

验证码的发展,可以说是非常迅速的,从开始的单纯数字验证码,到后来的数字+字母验证码,再到后来的数字+字母+中文的验证码以及图形图像验证码,单纯的验证码素材已经越来越多了。从验证码的形态来看,也是各不相同,输入、点击、拖拽以及短信验证码、语音验证码……

Bilibili 的登录验证码就包括了多种模式,例如滑动滑块进行验证:

 

例如,通过依次点击文字进行验证:

 

而百度贴吧、知乎、以及 Google 等相关网站的验证码又各不相同,例如选择正着写的文字、选择包括指定物体的图片以及按顺序点击图片中的字符等。

验证码的识别可能会根据验证码的类型而不太一致,当然最简单的验证码可能就是最原始的文字验证码了:

 

即便是文字验证码,也是存在很多差异的,例如简单的数字验证码、简单的数字+字母验证码、文字验证码、验证码中包括计算、简单验证码中增加一些干扰成为复杂验证码等。

验证码识别

1. 简单验证码识别

验证码识别是一个古老的研究领域,简单说就是把图片上的文字转化为文本的过程。最近几年,随着大数据的发展,广大爬虫工程师在对抗反爬策略时,对验证码的识别要求也越来越高。在简单验证码的时代,验证码的识别主要是针对文本验证码,通过图像的切割,对验证码每一部分进行裁剪,然后再对每个裁剪单元进行相似度对比,获得最可能的结果,最后进行拼接,例如将验证码:

 

进行二值化等操作:

 

完成之后再进行切割:

 

切割完成再进行识别,最后进行拼接,这样的做法是,针对每个字符进行识别,相对来说是比较容易的。

但是随着时间的发展,在这种简单验证码逐渐无法满足判断“是人还是机器”的问题时,验证码进行了一次小升级,即验证码上面增加了一些干扰线,或者验证码进行了严重的扭曲,增加了强色块干扰,例如 Dynadot 网站的验证码:

 

不仅有图像扭曲重叠,还有干扰线和色块干扰。这个时候想要识别验证码,简单的切割识别就很难获得良好的效果了,这时通过深度学习反而可以获得不错的效果。

2. 基于 CNN 的验证码识别

卷积神经网络(Convolutional Neural Network,简称 CNN),是一种前馈神经网络,人工神经元可以响应周围单元,进行大型图像处理。卷积神经网络包括卷积层和池化层。

 

如图所示,左图是传统的神经网络,其基本结构是:输入层、隐含层、输出层。右图则是卷积神经网络,其结构由输入层、输出层、卷积层、池化层、全连接层构成。卷积神经网络其实是神经网络的一种拓展,而事实上从结构上来说,朴素的 CNN 和朴素的 NN 没有任何区别(当然,引入了特殊结构的、复杂的 CNN 会和 NN 有着比较大的区别)。相对于传统神经网络,CNN 在实际效果中让我们的网络参数数量大大地减少,这样我们可以用较少的参数,训练出更加好的模型,典型的事半功倍,而且可以有效地避免过拟合。同样,由于 filter 的参数共享,即使图片进行了一定的平移操作,我们照样可以识别出特征,这叫做 “平移不变性”。因此,模型就更加稳健了。

1)验证码生成

验证码的生成是非常重要的一个步骤,因为这一部分的验证码将会作为我们的训练集和测试集,同时最终我们的模型可以识别什么类型的验证码,也是和这部分有关。

  1. # coding:utf-8 
  2.  
  3. import random 
  4. import numpy as np 
  5. from PIL import Image 
  6. from captcha.image import ImageCaptcha 
  7.  
  8. CAPTCHA_LIST = [eve for eve in "0123456789abcdefghijklmnopqrsruvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ"
  9. CAPTCHA_LEN = 4  # 验证码长度 
  10. CAPTCHA_HEIGHT = 60  # 验证码高度 
  11. CAPTCHA_WIDTH = 160  # 验证码宽度 
  12.  
  13. randomCaptchaText = lambda char=CAPTCHA_LIST, size=CAPTCHA_LEN: "".join([random.choice(charfor _ in range(size)]) 
  14.  
  15.  
  16. def genCaptchaTextImage(width=CAPTCHA_WIDTH, height=CAPTCHA_HEIGHT, save=None): 
  17.     image = ImageCaptcha(width=width, height=height) 
  18.     captchaText = randomCaptchaText() 
  19.     if save: 
  20.         image.write(captchaText, './img/%s.jpg' % captchaText) 
  21.     return captchaText, np.array(Image.open(image.generate(captchaText))) 
  22.  
  23.  
  24. print(genCaptchaTextImage(save=True)) 

通过上述代码,可以生成简单的中英文验证码:

 

2)模型训练

模型训练的代码如下(部分代码来自网络)。

util.py 文件,主要是一些提取出来的公有方法:

  1. # -*- coding:utf-8 -*- 
  2.  
  3. import numpy as np 
  4. from captcha_gen import genCaptchaTextImage 
  5. from captcha_gen import CAPTCHA_LIST, CAPTCHA_LEN, CAPTCHA_HEIGHT, CAPTCHA_WIDTH 
  6.  
  7. # 图片转为黑白,3维转1维 
  8. convert2Gray = lambda img: np.mean(img, -1) if len(img.shape) > 2 else img 
  9. # 验证码向量转为文本 
  10. vec2Text = lambda vec, captcha_list=CAPTCHA_LIST: ''.join([captcha_list[int(v)] for v in vec]) 
  11.  
  12.  
  13. def text2Vec(text, captchaLen=CAPTCHA_LEN, captchaList=CAPTCHA_LIST): 
  14.     ""
  15.     验证码文本转为向量 
  16.     ""
  17.     vector = np.zeros(captchaLen * len(captchaList)) 
  18.     for i in range(len(text)): 
  19.         vector[captchaList.index(text[i]) + i * len(captchaList)] = 1 
  20.     return vector 
  21.  
  22.  
  23. def getNextBatch(batchCount=60, width=CAPTCHA_WIDTH, height=CAPTCHA_HEIGHT): 
  24.     ""
  25.     获取训练图片组 
  26.     ""
  27.     batchX = np.zeros([batchCount, width * height]) 
  28.     batchY = np.zeros([batchCount, CAPTCHA_LEN * len(CAPTCHA_LIST)]) 
  29.     for i in range(batchCount): 
  30.         text, image = genCaptchaTextImage() 
  31.         image = convert2Gray(image) 
  32.         # 将图片数组一维化 同时将文本也对应在两个二维组的同一行 
  33.         batchX[i, :] = image.flatten() / 255 
  34.         batchY[i, :] = text2Vec(text) 
  35.     return batchX, batchY 
  36.  
  37. # print(getNextBatch(batch_count=1)) 

model_train.py 文件,主要是进行模型训练。在该文件中,定义了模型的基本信息,例如该模型是三层卷积神经网络,原始图像大小是 60*160,在第一次卷积后变为 60*160, 第一池化后变为 30*80;第二次卷积后变为 30*80 ,第二次池化后变为 15*40;第三次卷积后变为 15*40 ,第三次池化后变为7*20。经过三次卷积和池化后,原始图片数据变为 7*20 的平面数据,同时项目在进行训练的时候,每隔 100 次进行一次数据测试,计算一次准确度:

  1. # -*- coding:utf-8 -*- 
  2.  
  3. import tensorflow.compat.v1 as tf 
  4. from datetime import datetime 
  5. from util import getNextBatch 
  6. from captcha_gen import CAPTCHA_HEIGHT, CAPTCHA_WIDTH, CAPTCHA_LEN, CAPTCHA_LIST 
  7.  
  8. tf.compat.v1.disable_eager_execution() 
  9.  
  10. variable = lambda shape, alpha=0.01: tf.Variable(alpha * tf.random_normal(shape)) 
  11. conv2d = lambda x, w: tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME'
  12. maxPool2x2 = lambda x: tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME'
  13. optimizeGraph = lambda y, y_conv: tf.train.AdamOptimizer(1e-3).minimize( 
  14.     tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=y_conv))) 
  15. hDrop = lambda image, weight, bias, keepProb: tf.nn.dropout( 
  16.     maxPool2x2(tf.nn.relu(conv2d(image, variable(weight, 0.01)) + variable(bias, 0.1))), keepProb) 
  17.  
  18.  
  19. def cnnGraph(x, keepProb, size, captchaList=CAPTCHA_LIST, captchaLen=CAPTCHA_LEN): 
  20.     ""
  21.     三层卷积神经网络 
  22.     ""
  23.     imageHeight, imageWidth = size 
  24.     xImage = tf.reshape(x, shape=[-1, imageHeight, imageWidth, 1]) 
  25.  
  26.     hDrop1 = hDrop(xImage, [3, 3, 1, 32], [32], keepProb) 
  27.     hDrop2 = hDrop(hDrop1, [3, 3, 32, 64], [64], keepProb) 
  28.     hDrop3 = hDrop(hDrop2, [3, 3, 64, 64], [64], keepProb) 
  29.  
  30.     # 全连接层 
  31.     imageHeight = int(hDrop3.shape[1]) 
  32.     imageWidth = int(hDrop3.shape[2]) 
  33.     wFc = variable([imageHeight * imageWidth * 64, 1024], 0.01)  # 上一层有64个神经元 全连接层有1024个神经元 
  34.     bFc = variable([1024], 0.1) 
  35.     hDrop3Re = tf.reshape(hDrop3, [-1, imageHeight * imageWidth * 64]) 
  36.     hFc = tf.nn.relu(tf.matmul(hDrop3Re, wFc) + bFc) 
  37.     hDropFc = tf.nn.dropout(hFc, keepProb) 
  38.  
  39.     # 输出层 
  40.     wOut = variable([1024, len(captchaList) * captchaLen], 0.01) 
  41.     bOut = variable([len(captchaList) * captchaLen], 0.1) 
  42.     yConv = tf.matmul(hDropFc, wOut) + bOut 
  43.     return yConv 
  44.  
  45.  
  46. def accuracyGraph(y, yConv, width=len(CAPTCHA_LIST), height=CAPTCHA_LEN): 
  47.     ""
  48.     偏差计算图,正确值和预测值,计算准确度 
  49.     ""
  50.     maxPredictIdx = tf.argmax(tf.reshape(yConv, [-1, height, width]), 2) 
  51.     maxLabelIdx = tf.argmax(tf.reshape(y, [-1, height, width]), 2) 
  52.     correct = tf.equal(maxPredictIdx, maxLabelIdx)  # 判断是否相等 
  53.     return tf.reduce_mean(tf.cast(correct, tf.float32)) 
  54.  
  55.  
  56. def train(height=CAPTCHA_HEIGHT, width=CAPTCHA_WIDTH, ySize=len(CAPTCHA_LIST) * CAPTCHA_LEN): 
  57.     ""
  58.     cnn训练 
  59.     ""
  60.     accRate = 0.95 
  61.     x = tf.placeholder(tf.float32, [None, height * width]) 
  62.     y = tf.placeholder(tf.float32, [None, ySize]) 
  63.     keepProb = tf.placeholder(tf.float32) 
  64.     yConv = cnnGraph(x, keepProb, (height, width)) 
  65.     optimizer = optimizeGraph(y, yConv) 
  66.     accuracy = accuracyGraph(y, yConv) 
  67.     saver = tf.train.Saver() 
  68.     with tf.Session() as sess: 
  69.         sess.run(tf.global_variables_initializer())  # 初始化 
  70.         step = 0  # 步数 
  71.         while True
  72.             batchX, batchY = getNextBatch(64) 
  73.             sess.run(optimizer, feed_dict={x: batchX, y: batchY, keepProb: 0.75}) 
  74.             # 每训练一百次测试一次 
  75.             if step % 100 == 0: 
  76.                 batchXTest, batchYTest = getNextBatch(100) 
  77.                 acc = sess.run(accuracy, feed_dict={x: batchXTest, y: batchYTest, keepProb: 1.0}) 
  78.                 print(datetime.now().strftime('%c'), ' step:', step, ' accuracy:', acc) 
  79.                 # 准确率满足要求,保存模型 
  80.                 if acc > accRate: 
  81.                     modelPath = "./model/captcha.model" 
  82.                     saver.save(sess, modelPath, global_step=step) 
  83.                     accRate += 0.01 
  84.                     if accRate > 0.90: 
  85.                         break 
  86.             step = step + 1 
  87.  
  88.  
  89. train() 

当完成了这部分之后,我们可以通过本地机器对模型进行训练,为了提升训练速度,我将代码中的 accRate 部分设置为:

  1. if accRate > 0.90: 
  2.     break 

也就是说,当准确率超过 90% 之后,系统就会自动停止,并且保存模型。

接下来可以进行训练:

 

训练时间可能会比较长,训练完成之后,可以根据结果绘图,查看随着 Step 的增加,准确率的变化曲线:

 

横轴表示训练的 Step,纵轴表示准确率

3. 基于 Serverless 架构的验证码识别

将上面的代码部分进行进一步整合,按照函数计算的规范进行编码:

  1. # -*- coding:utf-8 -*- 
  2. # 核心后端服务 
  3.  
  4. import base64 
  5. import json 
  6. import uuid 
  7. import tensorflow as tf 
  8. import random 
  9. import numpy as np 
  10. from PIL import Image 
  11. from captcha.image import ImageCaptcha 
  12.  
  13.  
  14. # Response 
  15. class Response: 
  16.     def __init__(self, start_response, response, errorCode=None): 
  17.         self.start = start_response 
  18.         responseBody = { 
  19.             'Error': {"Code": errorCode, "Message": response}, 
  20.         } if errorCode else { 
  21.             'Response': response 
  22.         } 
  23.         # 默认增加uuid,便于后期定位 
  24.         responseBody['ResponseId'] = str(uuid.uuid1()) 
  25.         print("Response: ", json.dumps(responseBody)) 
  26.         self.response = json.dumps(responseBody) 
  27.  
  28.     def __iter__(self): 
  29.         status = '200' 
  30.         response_headers = [('Content-type''application/json; charset=UTF-8')] 
  31.         self.start(status, response_headers) 
  32.         yield self.response.encode("utf-8"
  33.  
  34.  
  35. CAPTCHA_LIST = [eve for eve in "0123456789abcdefghijklmnopqrsruvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ"
  36. CAPTCHA_LEN = 4  # 验证码长度 
  37. CAPTCHA_HEIGHT = 60  # 验证码高度 
  38. CAPTCHA_WIDTH = 160  # 验证码宽度 
  39.  
  40. # 随机字符串 
  41. randomStr = lambda num=5: "".join(random.sample('abcdefghijklmnopqrstuvwxyz', num)) 
  42.  
  43. randomCaptchaText = lambda char=CAPTCHA_LIST, size=CAPTCHA_LEN: "".join([random.choice(charfor _ in range(size)]) 
  44. # 图片转为黑白,3维转1维 
  45. convert2Gray = lambda img: np.mean(img, -1) if len(img.shape) > 2 else img 
  46. # 验证码向量转为文本 
  47. vec2Text = lambda vec, captcha_list=CAPTCHA_LIST: ''.join([captcha_list[int(v)] for v in vec]) 
  48.  
  49. variable = lambda shape, alpha=0.01: tf.Variable(alpha * tf.random_normal(shape)) 
  50. conv2d = lambda x, w: tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME'
  51. maxPool2x2 = lambda x: tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME'
  52. optimizeGraph = lambda y, y_conv: tf.train.AdamOptimizer(1e-3).minimize( 
  53.     tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=y_conv))) 
  54. hDrop = lambda image, weight, bias, keepProb: tf.nn.dropout( 
  55.     maxPool2x2(tf.nn.relu(conv2d(image, variable(weight, 0.01)) + variable(bias, 0.1))), keepProb) 
  56.  
  57.  
  58. def genCaptchaTextImage(width=CAPTCHA_WIDTH, height=CAPTCHA_HEIGHT, save=None): 
  59.     image = ImageCaptcha(width=width, height=height) 
  60.     captchaText = randomCaptchaText() 
  61.     if save: 
  62.         image.write(captchaText, save) 
  63.     return captchaText, np.array(Image.open(image.generate(captchaText))) 
  64.  
  65.  
  66. def text2Vec(text, captcha_len=CAPTCHA_LEN, captcha_list=CAPTCHA_LIST): 
  67.     ""
  68.     验证码文本转为向量 
  69.     ""
  70.     vector = np.zeros(captcha_len * len(captcha_list)) 
  71.     for i in range(len(text)): 
  72.         vector[captcha_list.index(text[i]) + i * len(captcha_list)] = 1 
  73.     return vector 
  74.  
  75.  
  76. def getNextBatch(batch_count=60, width=CAPTCHA_WIDTH, height=CAPTCHA_HEIGHT): 
  77.     ""
  78.     获取训练图片组 
  79.     ""
  80.     batch_x = np.zeros([batch_count, width * height]) 
  81.     batch_y = np.zeros([batch_count, CAPTCHA_LEN * len(CAPTCHA_LIST)]) 
  82.     for i in range(batch_count): 
  83.         text, image = genCaptchaTextImage() 
  84.         image = convert2Gray(image) 
  85.         # 将图片数组一维化 同时将文本也对应在两个二维组的同一行 
  86.         batch_x[i, :] = image.flatten() / 255 
  87.         batch_y[i, :] = text2Vec(text) 
  88.     return batch_x, batch_y 
  89.  
  90.  
  91. def cnnGraph(x, keepProb, size, captchaList=CAPTCHA_LIST, captchaLen=CAPTCHA_LEN): 
  92.     ""
  93.     三层卷积神经网络 
  94.     ""
  95.     imageHeight, imageWidth = size 
  96.     xImage = tf.reshape(x, shape=[-1, imageHeight, imageWidth, 1]) 
  97.  
  98.     hDrop1 = hDrop(xImage, [3, 3, 1, 32], [32], keepProb) 
  99.     hDrop2 = hDrop(hDrop1, [3, 3, 32, 64], [64], keepProb) 
  100.     hDrop3 = hDrop(hDrop2, [3, 3, 64, 64], [64], keepProb) 
  101.  
  102.     # 全连接层 
  103.     imageHeight = int(hDrop3.shape[1]) 
  104.     imageWidth = int(hDrop3.shape[2]) 
  105.     wFc = variable([imageHeight * imageWidth * 64, 1024], 0.01)  # 上一层有64个神经元 全连接层有1024个神经元 
  106.     bFc = variable([1024], 0.1) 
  107.     hDrop3Re = tf.reshape(hDrop3, [-1, imageHeight * imageWidth * 64]) 
  108.     hFc = tf.nn.relu(tf.matmul(hDrop3Re, wFc) + bFc) 
  109.     hDropFc = tf.nn.dropout(hFc, keepProb) 
  110.  
  111.     # 输出层 
  112.     wOut = variable([1024, len(captchaList) * captchaLen], 0.01) 
  113.     bOut = variable([len(captchaList) * captchaLen], 0.1) 
  114.     yConv = tf.matmul(hDropFc, wOut) + bOut 
  115.     return yConv 
  116.  
  117.  
  118. def captcha2Text(image_list): 
  119.     ""
  120.     验证码图片转化为文本 
  121.     ""
  122.     with tf.Session() as sess: 
  123.         saver.restore(sess, tf.train.latest_checkpoint('model/')) 
  124.         predict = tf.argmax(tf.reshape(yConv, [-1, CAPTCHA_LEN, len(CAPTCHA_LIST)]), 2) 
  125.         vector_list = sess.run(predict, feed_dict={x: image_list, keepProb: 1}) 
  126.         vector_list = vector_list.tolist() 
  127.         text_list = [vec2Text(vector) for vector in vector_list] 
  128.         return text_list 
  129.  
  130.  
  131. x = tf.placeholder(tf.float32, [None, CAPTCHA_HEIGHT * CAPTCHA_WIDTH]) 
  132. keepProb = tf.placeholder(tf.float32) 
  133. yConv = cnnGraph(x, keepProb, (CAPTCHA_HEIGHT, CAPTCHA_WIDTH)) 
  134. saver = tf.train.Saver() 
  135.  
  136.  
  137. def handler(environ, start_response): 
  138.     try: 
  139.         request_body_size = int(environ.get('CONTENT_LENGTH', 0)) 
  140.     except (ValueError): 
  141.         request_body_size = 0 
  142.     requestBody = json.loads(environ['wsgi.input'].read(request_body_size).decode("utf-8")) 
  143.  
  144.     imageName = randomStr(10) 
  145.     imagePath = "/tmp/" + imageName 
  146.  
  147.     print("requestBody: ", requestBody) 
  148.  
  149.     reqType = requestBody.get("type", None) 
  150.     if reqType == "get_captcha"
  151.         genCaptchaTextImage(save=imagePath) 
  152.         with open(imagePath, 'rb'as f: 
  153.             data = base64.b64encode(f.read()).decode() 
  154.         return Response(start_response, {'image': data}) 
  155.  
  156.     if reqType == "get_text"
  157.         # 图片获取 
  158.         print("Get pucture"
  159.         imageData = base64.b64decode(requestBody["image"]) 
  160.         with open(imagePath, 'wb'as f: 
  161.             f.write(imageData) 
  162.  
  163.         # 开始预测 
  164.         img = Image.open(imageName) 
  165.         img = img.resize((160, 60), Image.ANTIALIAS) 
  166.         img = img.convert("RGB"
  167.         img = np.asarray(img) 
  168.         image = convert2Gray(img) 
  169.         image = image.flatten() / 255 
  170.         return Response(start_response, {'result': captcha2Text([image])}) 

在这个函数部分,主要包括两个接口:

这部分代码,所需要的依赖内容如下:

  1. tensorflow==1.13.1 
  2. numpy==1.19.4 
  3. scipy==1.5.4 
  4. pillow==8.0.1 
  5. captcha==0.3 

另外,为了更加简单的来体验,提供测试页面,测试页面的后台服务使用 Python Web Bottle 框架:

  1. # -*- coding:utf-8 -*- 
  2.  
  3. import os 
  4. import json 
  5. from bottle import route, run, static_file, request 
  6. import urllib.request 
  7.  
  8. url = "http://" + os.environ.get("url"
  9.  
  10.  
  11. @route('/'
  12. def index(): 
  13.     return static_file("index.html", root='html/'
  14.  
  15.  
  16. @route('/get_captcha'
  17. def getCaptcha(): 
  18.     data = json.dumps({"type""get_captcha"}).encode("utf-8"
  19.     reqAttr = urllib.request.Request(data=data, url=url) 
  20.     return urllib.request.urlopen(reqAttr).read().decode("utf-8"
  21.  
  22.  
  23. @route('/get_captcha_result', method='POST'
  24. def getCaptcha(): 
  25.     data = json.dumps({"type""get_text""image": json.loads(request.body.read().decode("utf-8"))["image"]}).encode( 
  26.         "utf-8"
  27.     reqAttr = urllib.request.Request(data=data, url=url) 
  28.     return urllib.request.urlopen(reqAttr).read().decode("utf-8"
  29.  
  30.  
  31. run(host='0.0.0.0', debug=False, port=9000) 

该后端服务,所需依赖:

  1. bottle==0.12.19 

前端页面代码:

  1.  
  2. "en"
  3.  
  4.     "UTF-8"
  5.     验证码识别测试系统 
  6.     "https://www.bootcss.com/p/layoutit/css/bootstrap-combined.min.css" rel="stylesheet"
  7.      
  8.  
  9.  
  10. "container-fluid" style="margin-top: 10px"
  11.  
  12.     "row-fluid"
  13.         "span12"
  14.             
     
  15.                 

     

  16.                     验证码识别测试系统 
  17.                  
  18.              
  19.         
 
  •     
  •  
  •     "row-fluid"
  •         "span2"
  •          
  •         "span8"
  •             
     
  •                 "" id="captcha"/> 
  •                 

     
  •                 "result">

     
  •              
  •             
     
  •                 操作: 
  •                 "btn" onclick="getCaptcha()">获取验证码 
  •                 "btn" onclick="getCaptchaResult()" id="getResult" style="visibility: hidden">识别验证码 
  •                  
  •              
  •  
  •          
  •         "span2"
  •          
  •      
  •  
  •  
  •  
  •  
     

     

    准备好代码之后,开始编写部署文件:

    1. Global
    2.   Service: 
    3.       Name: ServerlessBook 
    4.       Description: Serverless图书案例 
    5.       Log: Auto 
    6.       Nas: Auto 
    7.  
    8. ServerlessBookCaptchaDemo: 
    9.   Component: fc 
    10.   Provider: alibaba 
    11.   Access: release 
    12.   Extends: 
    13.     deploy: 
    14.       - Hook: s install docker 
    15.         Path: ./ 
    16.         Pre: true 
    17.   Properties: 
    18.     Region: cn-beijing 
    19.     Service: ${Global.Service} 
    20.     Function
    21.       Name: serverless_captcha 
    22.       Description: 验证码识别 
    23.       CodeUri: 
    24.         Src: ./src/backend 
    25.         Excludes: 
    26.           - src/backend/.fun 
    27.           - src/backend/model 
    28.       Handler: index.handler 
    29.       Environment: 
    30.         - Key: PYTHONUSERBASE 
    31.           Value: /mnt/auto/.fun/python 
    32.       MemorySize: 3072 
    33.       Runtime: python3 
    34.       Timeout: 60 
    35.       Triggers: 
    36.         - Name: ImageAI 
    37.           Type: HTTP 
    38.           Parameters: 
    39.             AuthType: ANONYMOUS 
    40.             Methods: 
    41.               - GET 
    42.               - POST 
    43.               - PUT 
    44.             Domains: 
    45.               - Domain: Auto 
    46.  
    47. ServerlessBookCaptchaWebsiteDemo: 
    48.   Component: bottle 
    49.   Provider: alibaba 
    50.   Access: release 
    51.   Extends: 
    52.     deploy: 
    53.       - Hook: pip3 install -r requirements.txt -t ./ 
    54.         Path: ./src/website 
    55.         Pre: true 
    56.   Properties: 
    57.     Region: cn-beijing 
    58.     CodeUri: ./src/website 
    59.     App: index.py 
    60.     Environment: 
    61.       - Key: url 
    62.         Value: ${ServerlessBookCaptchaDemo.Output.Triggers[0].Domains[0]} 
    63.     Detail: 
    64.       Service: ${Global.Service} 
    65.       Function
    66.         Name: serverless_captcha_website 

    整体的目录结构:

    1. | - src # 项目目录 
    2. |   | - backend # 项目后端,核心接口 
    3. |       | - index.py # 后端核心代码 
    4. |       | - requirements.txt # 后端核心代码依赖 
    5. |   | - website # 项目前端,便于测试使用 
    6. |       | - html # 项目前端页面 
    7. |           | - index.html # 项目前端页面 
    8. |       | - index.py # 项目前端的后台服务(bottle框架) 
    9. |       | - requirements.txt # 项目前端的后台服务依赖 

    完成之后,我们可以在项目目录下,进行项目的部署:

    1. s deploy 

    部署完成之后,打开返回的页面地址:

     

     

    点击获取验证码,即可在线生成一个验证码:

     

    此时点击识别验证码,即可进行验证码识别:

     

    由于模型在训练的时候,填写的目标准确率是 90%,所以可以认为在海量同类型验证码测试之后,整体的准确率在 90% 左右。

    总结

     

    Serverless 发展迅速,通过 Serverless 做一个验证码识别工具,我觉得这是一个非常酷的事情。在未来的数据采集等工作中,有一个优美的验证码识别工具是非常必要的。当然验证码种类很多,针对不同类型的验证码识别,也是一项非常有挑战性的工作。

     

    来源:Serverless内容投诉

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    软考中级精品资料免费领

    • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

      难度     813人已做
      查看
    • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

      难度     354人已做
      查看
    • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

      难度     318人已做
      查看
    • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

      难度     435人已做
      查看
    • 2024年上半年系统架构设计师考试综合知识真题

      难度     224人已做
      查看

    相关文章

    发现更多好内容

    猜你喜欢

    AI推送时光机
    位置:首页-资讯-后端开发
    咦!没有更多了?去看看其它编程学习网 内容吧
    首页课程
    资料下载
    问答资讯