如何在Django框架中实现HTML表单与Python MBTI分析脚本的对接
实现方案
步骤1:重构原有MBTI分析脚本,封装为可调用模块
首先移除原脚本的全局执行逻辑,封装为独立可调用函数,同时优化不必要的本地文件写入逻辑,避免多请求冲突。将重构后的文件命名为mbti_analyzer.py,放到你的Django应用根目录下,代码如下:
# -*- coding: utf-8 -*- import csv import os import pickle import re import string from collections import Counter import pandas as pd import tweepy from nltk.corpus import stopwords from nltk.stem import * from nltk.stem.snowball import SnowballStemmer from nltk.tokenize import word_tokenize from sklearn.feature_extraction.text import TfidfVectorizer from unidecode import unidecode from django.conf import settings # 全局初始化资源,仅启动时加载一次,避免重复加载损耗性能 # 初始化Twitter API ckey = settings.TWITTER_CKEY csecret = settings.TWITTER_CSECRET atoken = settings.TWITTER_ATOKEN asecret = settings.TWITTER_ASECRET auth = tweepy.OAuthHandler(ckey, csecret) auth.set_access_token(atoken, asecret) api = tweepy.API(auth) # 加载词表 freq_path = os.path.join(settings.BASE_DIR, '你的应用名称', 'newfrequency300.csv') with open(freq_path, 'rt') as f: csvReader = csv.reader(f) mydict = {rows[1]: int(rows[0]) for rows in csvReader} vectorizer = TfidfVectorizer(vocabulary=mydict, min_df=1) # 加载模型 model_IE = pickle.load(open(os.path.join(settings.BASE_DIR, '你的应用名称', "BNIEFinal.sav"), 'rb')) model_SN = pickle.load(open(os.path.join(settings.BASE_DIR, '你的应用名称', "BNSNFinal.sav"), 'rb')) model_TF = pickle.load(open(os.path.join(settings.BASE_DIR, '你的应用名称', 'BNTFFinal.sav'), 'rb')) model_PJ = pickle.load(open(os.path.join(settings.BASE_DIR, '你的应用名称', 'BNPJFinal.sav'), 'rb')) # 原有预处理逻辑保留 emoticons_str = r""" (?: [:=;] # Eyes [oO\-]? # Nose (optional) [D\)\]\(\]/\\OpP] # Mouth )""" emoji_pattern = re.compile("[" u"\U0001F600-\U0001F64F" # emoticons u"\U0001F300-\U0001F5FF" # symbols & pictographs u"\U0001F680-\U0001F6FF" # transport & map symbols u"\U0001F1E0-\U0001F1FF" # flags (iOS) "]+", flags=re.UNICODE) regex_str = [ emoticons_str, r'<[^>]+>', # HTML tags r'(?:@[\w_]+)', # @-mentions r"(?:\#+[\w_]+[\w\'_\-]*[\w_]+)", # hash-tags r'http[s]?://(?:[a-z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+', # URLs r'(?:(?:\d+,?)+(?:\.?\d+)?)', # numbers r"(?:[a-z][a-z'\-_]+[a-z])", # words with - and ' r'(?:[\w_]+)', # other words r'(?:\S)' # anything else ] tokens_re = re.compile(r'(' + '|'.join(regex_str) + ')', re.VERBOSE | re.IGNORECASE) emoticon_re = re.compile(r'^' + emoticons_str + '$', re.VERBOSE | re.IGNORECASE) def tokenize(s): return tokens_re.findall(s) def preprocess(s, lowercase=False): tokens = tokenize(s) if lowercase: tokens = [token if emoticon_re.search(token) else token.lower() for token in tokens] return tokens def preproc(s): s = unidecode(s) POSTagger = preprocess(s) tweet = ' '.join(POSTagger) stop_words = set(stopwords.words('english')) filtered_sentence = [] for w in POSTagger: if w not in stop_words: filtered_sentence.append(w) stemmed_sentence = [] stemmer2 = SnowballStemmer("english", ignore_stopwords=True) for w in filtered_sentence: stemmed_sentence.append(stemmer2.stem(w)) temp = ' '.join(c for c in stemmed_sentence if c not in string.punctuation) preProcessed = temp.split(" ") final = [] for i in preProcessed: if i not in final: if i.isdigit(): pass else: if 'http' not in i: final.append(i) temp1 = ' '.join(c for c in final) return temp1 def get_tweet_list(user): tweet_list = [] try: for i in range(0, 4): tweets = api.user_timeline(screen_name=user, count=1000, include_rts=True, page=i) for status in tweets: tw = preproc(status.text) if tw.find(" ") == -1: tw = "blank" tweet_list.append(tw) return tweet_list, None except tweepy.TweepError as e: return None, "账号不存在、账号私有或Twitter接口请求失败,请检查输入后重试" # 核心分析逻辑封装为函数 def get_mbti(username): tweet_list, err = get_tweet_list(username) if err: return None, err x = vectorizer.fit_transform(tweet_list).toarray() df = pd.DataFrame(x) answer = [] IE = model_IE.predict(df) SN = model_SN.predict(df) TF = model_TF.predict(df) PJ = model_PJ.predict(df) b = Counter(IE) value = b.most_common(1) if value[0][0] == 1.0: answer.append("I") else: answer.append("E") b = Counter(SN) value = b.most_common(1) if value[0][0] == 1.0: answer.append("S") else: answer.append("N") b = Counter(TF) value = b.most_common(1) if value[0][0] == 1: answer.append("T") else: answer.append("F") b = Counter(PJ) value = b.most_common(1) if value[0][0] == 1: answer.append("P") else: answer.append("J") mbti = "".join(answer) return mbti, None
步骤2:Django端功能实现
2.1 配置基础参数
在Django项目的settings.py中新增Twitter API配置,避免硬编码密钥:
# settings.py末尾添加 TWITTER_CKEY = '你的ckey' TWITTER_CSECRET = '你的csecret' TWITTER_ATOKEN = '你的atoken' TWITTER_ASECRET = '你的asecret'
同时把原脚本依赖的newfrequency300.csv、4个.sav模型文件放到Django应用的根目录下。
2.2 编写表单类
在应用的forms.py中新增表单,用于校验用户输入的Twitter账号:
from django import forms class TwitterHandleForm(forms.Form): username = forms.CharField(label='Twitter账号Handle', max_length=100, required=True, widget=forms.TextInput(attrs={'placeholder': '例如:elonmusk'}))
2.3 编写视图逻辑
在应用的views.py中编写请求处理逻辑,对接表单和分析模块:
from django.shortcuts import render from .forms import TwitterHandleForm from .mbti_analyzer import get_mbti def mbti_analyze(request): mbti_result = None error_msg = None if request.method == 'POST': form = TwitterHandleForm(request.POST) if form.is_valid(): username = form.cleaned_data['username'] mbti_result, error_msg = get_mbti(username) else: form = TwitterHandleForm() return render(request, '你的原有HTML模板路径.html', { 'form': form, 'mbti_result': mbti_result, 'error_msg': error_msg })
记得在应用的urls.py中新增对应路由绑定该视图。
2.4 修改HTML模板
在原有HTML页面中新增表单提交和结果展示区域:
<!-- 表单区域 --> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">开始分析</button> </form> <!-- 结果展示区域 --> {% if error_msg %} <p style="color: red;">{{ error_msg }}</p> {% endif %} {% if mbti_result %} <div style="margin-top: 20px; padding: 10px; border: 1px solid #eee;"> <h3>分析结果:{{ mbti_result }}</h3> </div> {% endif %}
注意事项
- 若分析耗时较长,建议在前端添加加载动画,避免用户重复提交表单
- 可根据需求扩展MBTI对应性格描述的展示逻辑
- 生产环境建议将Twitter API密钥通过环境变量注入,不要直接写在配置文件中
内容的提问来源于stack exchange,提问作者Shahzaib Sarwar
相关产品推荐
相关产品推荐

