敏感詞過濾是隨著互聯網社區發展一起發展起來的一種阻止網路犯罪和網路暴力的技術手段,通過對可能存在犯罪或網路暴力可能的關鍵詞進行有針對性的篩查和屏蔽,很多時候我們能夠防患于未然,把后果嚴重的犯罪行為扼殺于萌芽之中,
隨著各種社交平臺等的日益火爆,敏感詞過濾逐漸成了非常重要的也是值得重視的功能,那么在 Serverless 架構下,通過Python 語言,敏感詞過濾又有那些新的實作呢?我們能否是用最簡單的方法,實作一個敏感詞過濾的API呢?
了解敏感過濾的幾種方法
Replace方法
如果說敏感詞過濾,其實不如說是文本的替換,以Python為例,說到詞匯替換,不得不想到replace,我們可以準備一個敏感詞庫,然后通過replace進行敏感詞替換:
def worldFilter(keywords, text):
for eve in keywords:
text = text.replace(eve, "***")
return text
keywords = ("關鍵詞1", "關鍵詞2", "關鍵詞3")
content = "這是一個關鍵詞替換的例子,這里涉及到了關鍵詞1還有關鍵詞2,最后還會有關鍵詞3,"
print(worldFilter(keywords, content))
但是動動腦大家就會發現,這種做法在文本和敏感詞庫非常龐大的前提下,會有很嚴重的性能問題,例如我將代碼進行修改,進行基本的性能測驗:
import time
def worldFilter(keywords, text):
for eve in keywords:
text = text.replace(eve, "***")
return text
keywords =[ "關鍵詞" + str(i) for i in range(0,10000)]
content = "這是一個關鍵詞替換的例子,這里涉及到了關鍵詞1還有關鍵詞2,最后還會有關鍵詞3," * 1000
startTime = time.time()
worldFilter(keywords, content)
print(time.time()-startTime)
此時的輸出結果是:0.12426114082336426,可以看到性能非常差,
正則表達方法
與其用replace,還不如通過正則表達re.sub來的更加快速,
import time
import re
def worldFilter(keywords, text):
return re.sub("|".join(keywords), "***", text)
keywords =[ "關鍵詞" + str(i) for i in range(0,10000)]
content = "這是一個關鍵詞替換的例子,這里涉及到了關鍵詞1還有關鍵詞2,最后還會有關鍵詞3," * 1000
startTime = time.time()
worldFilter(keywords, content)
print(time.time()-startTime)
我們同樣增加性能測驗,按照上面的方法進行改造測驗,輸出結果是0.24773502349853516,通過這樣的例子,我們可以發現,其性能磣韓劇并不大,但是實際上隨著文本量增加,正則表達這種做法在性能層面會變高很多,
DFA過濾敏感詞
這種方法相對來說效率會更高一些,例如,我們認為壞人,壞孩子,壞蛋是敏感詞,則他們的樹關系可以表達:

用DFA字典來表示:
{
'壞': {
'蛋': {
'\x00': 0
},
'人': {
'\x00': 0
},
'孩': {
'子': {
'\x00': 0
}
}
}
}
使用這種樹表示問題最大的好處就是可以降低檢索次數,提高檢索效率,基本代碼實作:
import time
class DFAFilter(object):
def __init__(self):
self.keyword_chains = {} # 關鍵詞鏈表
self.delimit = '\x00' # 限定
def parse(self, path):
with open(path, encoding='utf-8') as f:
for keyword in f:
chars = str(keyword).strip().lower() # 關鍵詞英文變為小寫
if not chars: # 如果關鍵詞為空直接回傳
return
level = self.keyword_chains
for i in range(len(chars)):
if chars[i] in level:
level = level[chars[i]]
else:
if not isinstance(level, dict):
break
for j in range(i, len(chars)):
level[chars[j]] = {}
last_level, last_char = level, chars[j]
level = level[chars[j]]
last_level[last_char] = {self.delimit: 0}
break
if i == len(chars) - 1:
level[self.delimit] = 0
def filter(self, message, repl="*"):
message = message.lower()
ret = []
start = 0
while start < len(message):
level = self.keyword_chains
step_ins = 0
for char in message[start:]:
if char in level:
step_ins += 1
if self.delimit not in level[char]:
level = level[char]
else:
ret.append(repl * step_ins)
start += step_ins - 1
break
else:
ret.append(message[start])
break
else:
ret.append(message[start])
start += 1
return ''.join(ret)
gfw = DFAFilter()
gfw.parse( "./sensitive_words")
content = "這是一個關鍵詞替換的例子,這里涉及到了關鍵詞1還有關鍵詞2,最后還會有關鍵詞3," * 1000
startTime = time.time()
result = gfw.filter(content)
print(time.time()-startTime)
這里我們的字典庫是:
with open("./sensitive_words", 'w') as f:
f.write("\n".join( [ "關鍵詞" + str(i) for i in range(0,10000)]))
執行結果:
0.06450581550598145
可以看到性能進一步提升,
AC自動機過濾敏感詞演算法
接下來,我們來看一下 AC自動機過濾敏感詞演算法:
AC自動機:一個常見的例子就是給出n個單詞,再給出一段包含m個字符的文章,讓你找出有多少個單詞在文章里出現過,
簡單地講,AC自動機就是字典樹+kmp演算法+失配指標
代碼實作:
import time
class Node(object):
def __init__(self):
self.next = {}
self.fail = None
self.isWord = False
self.word = ""
class AcAutomation(object):
def __init__(self):
self.root = Node()
# 查找敏感詞函式
def search(self, content):
p = self.root
result = []
currentposition = 0
while currentposition < len(content):
word = content[currentposition]
while word in p.next == False and p != self.root:
p = p.fail
if word in p.next:
p = p.next[word]
else:
p = self.root
if p.isWord:
result.append(p.word)
p = self.root
currentposition += 1
return result
# 加載敏感詞庫函式
def parse(self, path):
with open(path, encoding='utf-8') as f:
for keyword in f:
temp_root = self.root
for char in str(keyword).strip():
if char not in temp_root.next:
temp_root.next[char] = Node()
temp_root = temp_root.next[char]
temp_root.isWord = True
temp_root.word = str(keyword).strip()
# 敏感詞替換函式
def wordsFilter(self, text):
"""
:param ah: AC自動機
:param text: 文本
:return: 過濾敏感詞之后的文本
"""
result = list(set(self.search(text)))
for x in result:
m = text.replace(x, '*' * len(x))
text = m
return text
acAutomation = AcAutomation()
acAutomation.parse('./sensitive_words')
startTime = time.time()
print(acAutomation.wordsFilter("這是一個關鍵詞替換的例子,這里涉及到了關鍵詞1還有關鍵詞2,最后還會有關鍵詞3,"*1000))
print(time.time()-startTime)
詞庫同樣是:
with open("./sensitive_words", 'w') as f:
f.write("\n".join( [ "關鍵詞" + str(i) for i in range(0,10000)]))
使用上面的方法,測驗結果為0.017391204833984375,
敏感詞過濾方法小結
可以看到這個所有演算法中,在上述的基本演算法中DFA過濾敏感詞性能最高,但是實際上,對于后兩者演算法,并沒有誰一定更好,可能某些時候,AC自動機過濾敏感詞演算法會得到更高的性能,所以在生產生活中,推薦時候用兩者,可以根據自己的具體業務需要來做,
實作敏感詞過濾API
將代碼部署到Serverless架構上,可以選擇API網關與函式計算進行結合,以AC自動機過濾敏感詞演算法為例:我們只需要增加是幾行代碼就好,完整代碼如下:
# -*- coding:utf-8 -*-
import json, uuid
class Node(object):
def __init__(self):
self.next = {}
self.fail = None
self.isWord = False
self.word = ""
class AcAutomation(object):
def __init__(self):
self.root = Node()
# 查找敏感詞函式
def search(self, content):
p = self.root
result = []
currentposition = 0
while currentposition < len(content):
word = content[currentposition]
while word in p.next == False and p != self.root:
p = p.fail
if word in p.next:
p = p.next[word]
else:
p = self.root
if p.isWord:
result.append(p.word)
p = self.root
currentposition += 1
return result
# 加載敏感詞庫函式
def parse(self, path):
with open(path, encoding='utf-8') as f:
for keyword in f:
temp_root = self.root
for char in str(keyword).strip():
if char not in temp_root.next:
temp_root.next[char] = Node()
temp_root = temp_root.next[char]
temp_root.isWord = True
temp_root.word = str(keyword).strip()
# 敏感詞替換函式
def wordsFilter(self, text):
"""
:param ah: AC自動機
:param text: 文本
:return: 過濾敏感詞之后的文本
"""
result = list(set(self.search(text)))
for x in result:
m = text.replace(x, '*' * len(x))
text = m
return text
def response(msg, error=False):
return_data = https://www.cnblogs.com/serverlesscloud/p/{"uuid": str(uuid.uuid1()),
"error": error,
"message": msg
}
print(return_data)
return return_data
acAutomation = AcAutomation()
path = './sensitive_words'
acAutomation.parse(path)
def main_handler(event, context):
try:
sourceContent = json.loads(event["body"])["content"]
return response({
"sourceContent": sourceContent,
"filtedContent": acAutomation.wordsFilter(sourceContent)
})
except Exception as e:
return response(str(e), True)
最后,為了方便本地測驗,我們可以增加:
def test():
event = {
"requestContext": {
"serviceId": "service-f94sy04v",
"path": "/test/{path}",
"httpMethod": "POST",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
"identity": {
"secretId": "abdcdxxxxxxxsdfs"
},
"sourceIp": "14.17.22.34",
"stage": "release"
},
"headers": {
"Accept-Language": "en-US,en,cn",
"Accept": "text/html,application/xml,application/json",
"Host": "service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com",
"User-Agent": "User Agent String"
},
"body": "{\"content\":\"這是一個測驗的文本,我也就呵呵了\"}",
"pathParameters": {
"path": "value"
},
"queryStringParameters": {
"foo": "bar"
},
"headerParameters": {
"Refer": "10.0.2.14"
},
"stageVariables": {
"stage": "release"
},
"path": "/test/value",
"queryString": {
"foo": "bar",
"bob": "alice"
},
"httpMethod": "POST"
}
print(main_handler(event, None))
if __name__ == "__main__":
test()
完成之后,我們就可以測驗運行一下,例如我的字典是:
呵呵
測驗
執行之后結果:
{'uuid': '9961ae2a-5cfc-11ea-a7c2-acde48001122', 'error': False, 'message': {'sourceContent': '這是一個測驗的文本,我也就呵呵了', 'filtedContent': '這是一個**的文本,我也就**了'}}
接下來,我們將代碼部署到云端,新建serverless.yaml:
sensitive_word_filtering:
component: "@serverless/tencent-scf"
inputs:
name: sensitive_word_filtering
codeUri: ./
exclude:
- .gitignore
- .git/**
- .serverless
- .env
handler: index.main_handler
runtime: Python3.6
region: ap-beijing
description: 敏感詞過濾
memorySize: 64
timeout: 2
events:
- apigw:
name: serverless
parameters:
environment: release
endpoints:
- path: /sensitive_word_filtering
description: 敏感詞過濾
method: POST
enableCORS: true
param:
- name: content
position: BODY
required: 'FALSE'
type: string
desc: 待過濾的句子
然后通過sls --debug進行部署,部署結果:

最后,通過PostMan進行測驗:

總結
敏感詞過濾是目前非常常見的需求/技術,通過敏感詞過濾,我們可以在一定程度上降低惡意言語或者違規言論的出現,在上述實踐程序,有以下兩點內容:
- 對于敏感詞庫額獲得問題:Github上有很多,可以自行搜索下載,因為敏感詞詞庫里面有很多敏感詞,所以我也不能直接放在這個上面供大家使用,所以還需要大家自行在Github上搜索使用;
- 這個API使用場景的問題:完全可以放在我們的社區跟帖系統/留言評論系統/博客發布系統中,防止出現敏感詞匯,可以降低不必要的麻煩出現,
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/18077.html
標籤:其他
