驗證碼識別是搞爬蟲實作自動化腳本避不開的一個問題,通常驗證碼識別程式要么部署在本地,要么部署在服務器端,如果部署在服務器端就需要自己去搭建配置網路環境并撰寫呼叫介面,這是一個極其繁瑣耗時的程序,
本文來自 Serverless 社區用戶「乂乂又又」供稿
但是現在我們通過騰訊云云函式 SCF,就可以快速將本地的驗證碼識別程式發布上線,極大地提高了開發效率,
效果展示


可以看到,識別效果還是蠻好的,甚至超過了肉眼識別率,
操作步驟
傳統的驗證碼識別流程是
- 影像預處理(灰化,去噪,切割,二值化,去干擾線等)
- 驗證碼字符特征提取(SVM,CNN 等)
- 驗證碼識別
下面我就帶大家一起來創建、撰寫并發布上線一個驗證識別云函式
第一步:新建 python 云函式
參見系列文章《萬物皆可Serverless之使用 SCF+COS 快速開發全堆疊應用》
第二步:撰寫驗證識別云函式

Life is short, show me the code.
這里我就以一個最簡單的驗證碼識別程式為例,直接上代碼
import io
import os
import time
from PIL import Image as image
import json
#字符特征
chars = {
'1': [1, 1, 1, 0, 1, ...],
'2': [1, 0, 0, 1, 0, ...],
'3': [0, 1, 0, 0, 1, ...],
# 其他字符特征...
}
# 灰度處理
def covergrey(img):
return img.convert('L')
# 去除驗證碼邊框
def clearedge(img):
for y in range(img.size[1]):
img.putpixel((0, y), 255)
img.putpixel((1, y), 255)
img.putpixel((2, y), 255)
img.putpixel((img.size[0]-1, y), 255)
img.putpixel((img.size[0]-2, y), 255)
img.putpixel((img.size[0]-3, y), 255)
for x in range(img.size[0]):
img.putpixel((x, 0), 255)
img.putpixel((x, 1), 255)
img.putpixel((x, 2), 255)
img.putpixel((x, img.size[1]-1), 255)
img.putpixel((x, img.size[1]-2), 255)
img.putpixel((x, img.size[1]-3), 255)
return img
# 去除干擾線并轉換為黑白照片
def clearline(img):
for y in range(img.size[1]):
for x in range(img.size[0]):
if int(img.getpixel((x, y))) >= 110:
img.putpixel((x, y), 0xff)
else:
img.putpixel((x, y), 0x0)
return img
# 去噪/pnum-去噪效率
def del_noise(im, pnum=3):
w, h = im.size
white = 255
black = 0
for i in range(0, w):
im.putpixel((i, 0), white)
im.putpixel((i, h - 1), white)
for i in range(0, h):
im.putpixel((0, i), white)
im.putpixel((w - 1, i), white)
for i in range(1, w - 1):
for j in range(1, h - 1):
val = im.getpixel((i, j))
if val == black:
cnt = 0
for ii in range(-1, 2):
for jj in range(-1, 2):
if im.getpixel((i + ii, j + jj)) == black:
cnt += 1
if cnt < pnum:
im.putpixel((i, j), white)
else:
cnt = 0
for ii in range(-1, 2):
for jj in range(-1, 2):
if im.getpixel((i + ii, j + jj)) == black:
cnt += 1
if cnt >= 7:
im.putpixel((i, j), black)
return im
# 圖片資料二值化
def two_value(code_data):
table = [serverless]
for i in code_data:
if i < 140: # 二值化分界線140
table.append(0)
else:
table.append(1)
return table
# 圖片預處理
def pre_img(img):
img = covergrey(img) # 去色
img = clearedge(img) # 去邊
img = clearline(img) # 去線
img = del_noise(img) # 去噪
return img
# 處理圖片資料
def data_img(img):
code_data = https://www.cnblogs.com/serverlesscloud/p/[serverless] # 驗證碼資料串列
for i in range(4): # 切割驗證碼
x = 5 + i * 18 # 可用PS確定圖片切割位置
code_data.append(img.crop((x, 9, x + 18, 33)).getdata())
code_data[i] = two_value(code_data[i]) # 二值化資料
return code_data
# 驗證碼識別
def identify(data):
code = ['']*4 # 驗證碼字串列
diff_min = [432]*4 # 初始化最小距離--不符合的資料點個數(共120資料點)
for char in chars: # 遍歷驗證碼字符(每個字符比較一次4個驗證碼)
diff = [0]*4 # 各驗證碼差距值(每個字符判斷前重置此距離)
for i in range(4): # 計算四個驗證碼
for j in range(432): # 逐個像素比較驗證碼特征
if data[i][j] != chars[char][j]:
diff[i] += 1 # 距離+1
for i in range(4):
if diff[i] < diff_min[i]: # 比已有距離還要小(更加符合)
diff_min[i] = diff[i] # 重繪最小距離
code[i] = char # 重繪最佳驗證碼
return ''.join(code) # 輸出結果
def predict(imgs):
code = ''
img = imgs.read()
img = image.open(io.BytesIO(img))
img = pre_img(img) # 預處理圖片
data = https://www.cnblogs.com/serverlesscloud/p/data_img(img) # 獲取圖片資料
code = identify(data) # 識別驗證碼
return code
def apiReply(reply, code=200):
return {
"isBase64Encoded": False,
"statusCode": code,
"headers": {'Content-Type': 'application/json', "Access-Control-Allow-Origin": "*"},
"body": json.dumps(reply, ensure_ascii=False)
}
def main_handler(event, context):
main_start = time.time()
flag = True if 'image' in event['queryString'] else False
code = predict(event['queryString']['image']) if 'image' in event['queryString'] else '無效的請求'
return apiReply({
'ok': flag,
'code': code,
'spendTime': str(time.time()-main_start)
})
老規矩,先捋一下整個云函式的流程,
def main_handler(event, context):
main_start = time.time()
flag = True if 'image' in event['queryString'] else False
code = predict(event['queryString']['image']) if 'image' in event['queryString'] else '無效的請求'
return apiReply({
'ok': flag,
'code': code,
'spendTime': str(time.time()-main_start)
})
首先,我們通過 event 事件拿到 api 請求的驗證碼 image 資料,然后判斷一下 image 引數是否存在,若不存在就回傳請求無效的提示
def predict(imgs):
code = ''
img = imgs.read()
img = image.open(io.BytesIO(img))
img = pre_img(img) # 預處理圖片
data = https://www.cnblogs.com/serverlesscloud/p/data_img(img) # 獲取圖片資料
code = identify(data) # 識別驗證碼
return code
如果 image 請求引數存在就呼叫 predict 函式決議識別驗證碼,流程如下:
- 讀取驗證碼影像
- 驗證碼影像預處理
- 識別處理后的驗證碼
# 圖片預處理
def pre_img(img):
img = covergrey(img) # 去色
img = clearedge(img) # 去邊
img = clearline(img) # 去線
img = del_noise(img) # 去噪
return img
我們來看一下影像預處理程序
- 將驗證碼去色,轉為灰度圖
- 去除驗證碼黑色邊框
- 去除驗證碼干擾線
- 去除驗證碼噪點
#字符特征
chars = {
'1': [1, 1, 1, 0, 1, ...],
'2': [1, 0, 0, 1, 0, ...],
'3': [0, 1, 0, 0, 1, ...],
# 其他字符特征...
}
# 驗證碼識別
def identify(data):
code = ['']*4 # 驗證碼字串列
diff_min = [432]*4 # 初始化最小距離--不符合的資料點個數(共120資料點)
for char in chars: # 遍歷驗證碼字符(每個字符比較一次4個驗證碼)
diff = [0]*4 # 各驗證碼差距值(每個字符判斷前重置此距離)
for i in range(4): # 計算四個驗證碼
for j in range(432): # 逐個像素比較驗證碼特征
if data[i][j] != chars[char][j]:
diff[i] += 1 # 距離+1
for i in range(4):
if diff[i] < diff_min[i]: # 比已有距離還要小(更加符合)
diff_min[i] = diff[i] # 重繪最小距離
code[i] = char # 重繪最佳驗證碼
return ''.join(code) # 輸出結果
PS:文章中的字符特征 chars 并不完整,你可能需要自行提取所有特征,
最后來看一下驗證碼的識別程序:這里我們直接簡單粗暴地取處理后影像資料的所有像素點作為字符的特征(所謂大道至簡),然后將每個待識別字符處理后影像的資料與所有字符的特征逐個比較,取最相似的那個字符作為識別結果,

嗯,沒什么問題的話,你就可以得到正確的識別結果了,
第三步:上線發布云函式、添加 API 網關觸發器、啟用回應集成
參見系列文章《萬物皆可 Serverless 之使用 SCF+COS 快速開發全堆疊應用》
寫在最后
當然,以上只是以一個簡單的驗證碼識別為例,對于一些比較復雜的驗證碼,你也可以使用 Tensorflow,Pytorch 等深度學習計算框架搭建、訓練模型,然后將訓練好的模型借助無服務器云函式快速上線發布使用,
Serverless Framework 30 天試用計劃
我們誠邀您來體驗最便捷的 Serverless 開發和部署方式,在試用期內,相關聯的產品及服務均提供免費資源和專業的技術支持,幫助您的業務快速、便捷地實作 Serverless!
詳情可查閱:Serverless Framework 試用計劃
One More Thing
3 秒你能做什么?喝一口水,看一封郵件,還是 —— 部署一個完整的 Serverless 應用?
復制鏈接至 PC 瀏覽器訪問:https://serverless.cloud.tencent.com/deploy/express
3 秒極速部署,立即體驗史上最快的 Serverless HTTP 實戰開發!
傳送門:
- GitHub: github.com/serverless
- 官網:serverless.com
歡迎訪問:Serverless 中文網,您可以在 最佳實踐 里體驗更多關于 Serverless 應用的開發!
推薦閱讀:《Serverless 架構:從原理、設計到專案實戰》
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/6773.html
標籤:其他
