<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Django敏感詞檢測(cè)

          共 5245字,需瀏覽 11分鐘

           ·

          2022-08-10 01:29

          作者:vk

          鏈接:https://0vk.top/zh-hans/article/details/65

          來(lái)源:愛(ài)尚購(gòu)?

          點(diǎn)擊閱讀更多獲取極致閱讀體驗(yàn)


          c5af07a218854ee7e8c082caace72da6.webp

          為了識(shí)別和過(guò)濾用戶提交的惡意內(nèi)容,每一條人工檢查的成本又太大,需要開(kāi)發(fā)一個(gè)自動(dòng)檢測(cè)敏感詞的程序

          運(yùn)行效果如下:

          2f85c2ef73bcf6056f438c4c6c884e14.webp

          ?

          整體設(shè)計(jì)思路:

          ecf11b30165b5fe3a22f50f6832f344c.webp獲取用戶提交內(nèi)容

          通過(guò)自定義中間件的方式獲取用戶提交內(nèi)容

          要在請(qǐng)求來(lái)的時(shí)候就將惡意內(nèi)容扼殺在搖籃中,使用process_request方法。獲取到內(nèi)容中如果有敏感詞直接在中間件里返回處理內(nèi)容即可。

          新建一個(gè)py文件,自定義一個(gè)類,并且該類必須繼承MiddlewareMixin,然后在process_request方法里寫(xiě)入自己的過(guò)濾方法。這個(gè)方法名字是不能改的

          from?django.utils.deprecation?import?MiddlewareMixin
          # 定義一個(gè)類繼承MiddlewareMixin 并實(shí)現(xiàn)下面的方法,在這兩個(gè)方法 中定義或者攔截對(duì)應(yīng)的請(qǐng)求# 可以在中間件中添加用戶認(rèn)證和登錄設(shè)置等信息class CustomMiddle(MiddlewareMixin): def process_request(self, request): print('過(guò)濾代碼',request)

          然后在settings.py里面注冊(cè)該中間件即可使用,位置最好放在最后面,因?yàn)檎?qǐng)求經(jīng)過(guò)中間件是從上到下的,指不定自定義的中間件要依賴上面哪個(gè)中間件的結(jié)果

          判斷是否屬于敏感詞

          這里有三種方法:

          replace過(guò)濾

          import?time  old = time.time()    with open("1", encoding='utf-8') as f:????????word?=?'可愛(ài)'        for keyword in f:            if keyword == word:                print(word.replace(word, '*'))    now = time.time()????print(now?-?old,'replace方法')

          這個(gè)文件1里存放的就是敏感詞庫(kù)

          正則過(guò)濾

          import?re    old = time.time()    def check_filter(keywords, word):        return re.sub("|".join(keywords), "***", word)    with open("1", encoding='utf-8') as f:        keywords=[]        for i in f:            keywords.append(i.strip('\n'))    print(check_filter(keywords, word))    now = time.time()    print(now - old, '正則方法')

          DFA算法(推薦)

          這個(gè)算法的核心是把敏感詞庫(kù)構(gòu)造成樹(shù)結(jié)構(gòu),比如現(xiàn)在敏感詞庫(kù)有:“大家好,大人,帥氣,大部隊(duì)”

          前兩種方法就是循環(huán)詞庫(kù)每一行,然后對(duì)比,假設(shè)詞庫(kù)很大,這樣逐行對(duì)比效率很低

          DFA算法將敏感詞生成一個(gè)下圖這種結(jié)構(gòu)

          5c307ae83cbd258d6b385af6d6eb7960.webp


          組成樹(shù)形結(jié)構(gòu)的好處就是可以減少索引次數(shù),理論上只需要遍歷?遍代檢測(cè)的?本,看看是否在敏感詞庫(kù)中即可。

          ?如輸?"我感覺(jué)我?分帥?",前?個(gè)均未在詞庫(kù)中匹配,全部pass掉。直到出現(xiàn)”帥”字時(shí)在?樹(shù)中找到了,接下來(lái)繼續(xù)遍歷發(fā)現(xiàn)”?”字出現(xiàn)在?樹(shù)的?節(jié)點(diǎn) 中,就說(shuō)明帥?是敏感詞。

          在python中我們可以?字典儲(chǔ)存敏感詞詞庫(kù)樹(shù)結(jié)構(gòu),理論上字典的查詢時(shí)間復(fù)雜度為 O(1)。

          我們把第?個(gè)字符作為字典的鍵,值為另?個(gè)字典以此類推,字典最后?項(xiàng)定義為{'\x00': 0}?來(lái)表示最后?個(gè)字符

          884b3afbabf061ba16ef092f08cf6744.webp

          定義一個(gè)類,并且初始化變量,生成樹(shù)結(jié)構(gòu):

          882ec1f18e0224b462cab95855ff1055.webp

          制作的字典如下圖763a75c60abeb37733a940774147b5c0.webp

          現(xiàn)在我們需要做的就是編寫(xiě)add?法的具體內(nèi)容:

          f29704500ae578794c8537ee052e5562.webp

          ?

          如“大家好”,循環(huán)結(jié)束后的self.key_chains應(yīng)該變?yōu)?

          ?{大:{家:{好:{}}}}?。當(dāng)“大家好”處理完成后輪到“大人”時(shí),發(fā)現(xiàn)“大”已經(jīng)為字典的鍵,所以進(jìn)入If 判斷,update level 的value。

          使level update為之前“大”對(duì)應(yīng)的值,這仍舊是一個(gè)字典。接著進(jìn)入else將“大”加到和“家”同級(jí)別的dict中

          此時(shí)的結(jié)構(gòu)如下圖:

          59eabb2bf2602c8bf93ebdd2314b25ae.webp

          ?

          樹(shù)字典構(gòu)建好了接下來(lái)需要做的就是過(guò)濾了


          dfb7a27c60dc6725f6b695fd3350d520.webp

          完整代碼
          import?jiebafrom django.conf import settingsimport time
          class DFAFilter(): ''' Filter Messages from keywords
          Use DFA to keep algorithm perform constantly
          f = DFAFilter() f.add("sexy") f.filter("hello sexy baby") hello **** baby '''
          def __init__(self): self.stopwords = ['!'] self.keyword_chains = {} self.delimit = '\x00' with open(settings.FILTER_PATH, encoding='utf-8') as f: for keyword in f: self.add(keyword.strip()) def add(self, keyword):
          if not isinstance(keyword, str): keyword = keyword.decode('utf-8') keyword = keyword.lower() chars = keyword.strip() 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="*"): stop_list1 = [] stop_list2 = [] stop_index = -1 if not isinstance(message, str): message = message.decode('utf-8') message = message.lower()
          wordlist = jieba.lcut(message) stop = set(self.stopwords) for i in wordlist: if i == ' ' or '': stop_index = message.index(i, stop_index + 1, len(message)) stop_list1.append(stop_index) stop_list2.append('') wordlist.remove(i) if i in stop: stop_index = message.index(i, stop_index + 1, len(message)) stop_list1.append(stop_index) stop_list2.append(i) wordlist.remove(i)
          message = ''.join(wordlist) ret = [] start = 0 danger = 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: danger += 1 ret.append(repl * step_ins) start += step_ins - 1 break
          else: ret.append(message[start]) print(ret) break else: ret.append(message[start])
          start += 1 result = list(''.join(ret)) for i, j in zip(stop_list1, stop_list2): result.insert(i, j)
          return ''.join(result), danger

          沒(méi)有數(shù)據(jù)支持的對(duì)比都是詐騙:

          1603611cbc2bd533ea9e8a89943b133c.webp

          c52dc7679b43bd9d71e85679c1c034b9.webp

          401bc0ff603fd2d3101ee6566c001053.webp

          e769f1c5784bce758371a7f18f9b740d.webp


          可以看到:正則方法所用的時(shí)間是隨著詞庫(kù)的擴(kuò)大而增大,replace是詞庫(kù)少于2000個(gè)詞的時(shí)候表現(xiàn)良好,而DFA算法是大于2000時(shí)表現(xiàn)良好

          后臺(tái)控制敏感詞名單的增減

          DFA算法生成字典那里我們可以做出優(yōu)化,不用每次運(yùn)行都生成字典,而是把字典用pickle.dump持久話存儲(chǔ)在內(nèi)存中,用的時(shí)候再讀,這樣就快了很多。

          把敏感詞庫(kù)的詞所對(duì)應(yīng)的字段在admin中注冊(cè)就可以后臺(tái)直接控制詞庫(kù)了,我就不再操作拿IP黑名單字段演示。

          類似下圖,這樣我們就可以在后臺(tái)管理是否啟用特定的敏感詞或者增刪特定的敏感詞了

          5a1c6c672525cab71ab8285740deb99b.webp

          持久化存儲(chǔ)文件更新

          當(dāng)我們?cè)黾踊騽h除了敏感詞的時(shí)候,對(duì)應(yīng)的持久化文件也應(yīng)該發(fā)生改變,可以在model里面重寫(xiě)save和delete方法即可。

          f3cbab2f5f0df16dced65c3ff4352dcb.webp

          不用信號(hào)的原因是無(wú)需操作別的數(shù)據(jù)庫(kù)模型和第三方app,只是重新pickle.dump update了一個(gè)新的持久化文件

          ?單詞數(shù):349字符數(shù):5138

          瀏覽 69
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人成在线网站 | 成人网视频 | 免费在线观看一级片 | 中文字幕免费 | 久青草在在线 |