爬取电影《后来的我们》豆瓣影评进行文本数据机器学习检测恶意评论

0x01前言

前两天在地铁上看公众号,无意中看到有爬取豆瓣影评以及对爬取数据进行数据分析的文章,加上前段时间并未对机器学习进行实践,就打算从文本数据处理开始,后期再写一些CNN或者RNN模型等机器学习文章。然后就是最近《后来的我们》电影比较火,话说我还没去看呢,就以此为目标牛刀小试吧。先是爬取观众的影评,进行文本数据处理,再将文本数据提取特征转化为向量模型,利用机器学习来检查恶意评论,目前代码也只是Demo版本。

0x01代码结构

废话不多说,先看代码结构。

最后的效果图,提供了两种机器学习的模型,一种是SVM,这里SVM模型提供了三个相差较大的参数;另外一种是朴素贝叶斯。因为只是做了一个二分类,所以同样可以使用的分类模型还有很多,像KNN,逻辑回归等等,都可以使用。

这是利用SVM模型进行学习获得的准确率

这是利用朴素贝叶斯进行学习返回的准确率

当然这里关于学习的准确率,与数据集也有很大关系,由于爬虫时获得的数据未展开,只是静态爬虫,加上对文本特征处理的方法不完善,都会对准确率有一定的影响。

0x02实现过程

第一步当然是爬虫了,我这里采取的是静态爬虫,我是昨天爬取的豆瓣《后来的我们》影评,大约有3700条左右数据。爬取完之后发现一些较长的评论需要交互式点击爬虫,方能展开。所以仅利用静态爬虫的数据进行分析了,后期可以再修改爬取的数据吧。

这里爬虫的部分,提取了两个内容。一是影评,二是分值,也就是观众的打分,分1-5分,分别为力荐、推荐、还行、较差、很差。爬的时候发现有些观众只评论并没有打分,考虑到后期还要数据清洗,就将未打分的评论归为还行一栏,然后做了一个二分类问题。3-5分也就是力荐、推荐、还行设置标签为1,1-2分也就是较差、很差设置标签为0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while i < 3700:
i+=20
nums.append(i)
print(nums)
content = []
rank = []
for num in nums:
url = 'https://movie.douban.com/subject/26683723/reviews?start=' + str(num)
res = requests.get(url=url,headers=headers)
#print(res.text)
soup = bs(res.text,'html.parser')
divs = soup.find_all('div',{'class':'short-content'})
spans = soup.find_all('div',{'class':'main review-item'})
#print(divs)
for div in divs:
comment = div.text.strip()
#print(comment)
content.append(comment)

然后爬虫得到的数据保存为csv如下:

然后就是要对数据进行处理

1
2
3
4
5
6
7
8
9
10
11
12
def prepare_data():
df_movie = pd.read_csv('./output/movie_comments.csv',encoding='GB18030')
#print(df_movie[:10])
#添加标签
df_movie['label'] = df_movie['分数'].map(config.text_type_dic)
#文本处理
df_movie['proc_text'] = df_movie['影评'].apply(preprocess_text)
#保存结果
df_movie.to_csv(os.path.join(config.output_path,'new_comments.csv'),encoding="GB18030")
#数据集划分
train_data, test_data = train_test_split(df_movie, test_size=1/4, random_state=0)
return train_data, test_data

这里有一点注意,在将爬取 汉字数据存取为csv时,要注意编码格式,这里用的是GB18030方可正常显示,有时会用gb2312等,用utf-8会显示汉字乱码。

对数据集进行处理,添加两列,一列是label,另一列是对文本数据的处理,这里利用apply函数来转化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def preprocess_text(raw_text):
# 加载停用词表
stop_words_path = './stop_words/'
stopwords1 = [line.rstrip() for line in open(os.path.join(stop_words_path, '中文停用词库.txt'), 'r', encoding='utf-8')]
stopwords2 = [line.rstrip() for line in open(os.path.join(stop_words_path, '哈工大停用词表.txt'), 'r', encoding='utf-8')]
stopwords3 = [line.rstrip() for line in open(os.path.join(stop_words_path, '四川大学机器智能实验室停用词库.txt'), 'r', encoding='utf-8')]
stopwords = stopwords1 + stopwords2 + stopwords3

# 1. 使用正则表达式去除非中文字符
filter_pattern = re.compile('[^\u4E00-\u9FD5]+')
chinese_only = filter_pattern.sub('',raw_text)
# 2. 结巴分词+词性标注
word_list = pseg.cut(chinese_only)
# 3. 去除停用词,保留有意义的词性
# 动词,形容词,副词
used_flags = ['v', 'a', 'ad']
meaninful_words = []
for word, flag in word_list:
if (word not in stopwords) and (flag in used_flags):
meaninful_words.append(word)
return ' '.join(meaninful_words)

这个函数就是刚才的文本处理函数,其中引用一个停用词词库,在代码stop_words文件夹中。

通过过文本数据的处理,接下来便可以进行特征提取,也就是文本数据转化为向量数据进行分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def feature_engineering(train_data,test_data):
train_proc_text = train_data['proc_text'].values
test_proc_text = test_data['proc_text'].values

#TF-IDF特征提取
tfidf_vectorizer = TfidfVectorizer()
train_tfidf_feat = tfidf_vectorizer.fit_transform(train_proc_text).toarray()
test_tfidf_feat = tfidf_vectorizer.transform(test_proc_text).toarray()

# 词袋模型
count_vectorizer = CountVectorizer()
train_count_feat = count_vectorizer.fit_transform(train_proc_text).toarray()
testcount_feat = count_vectorizer.transform(test_proc_text).toarray()

#合并特征
train_X = np.hstack((train_tfidf_feat,train_count_feat))
test_X = np.hstack((test_tfidf_feat,testcount_feat))
return train_X,test_X

利用了TF-IDF特征提取和词袋模型进行特征提取,最后将特征横向合并。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def SVC_model():
train_data,test_data = utils.prepare_data()
print('训练集有{}条记录。'.format(len(train_data)))
print('测试集有{}条记录。'.format(len(test_data)))
X_train, X_test = utils.feature_engineering(train_data, test_data)
print('共有{}维特征。'.format(X_train.shape[1]))
y_train = train_data['label'].values
y_test = test_data['label'].values
#数据建模
c_values = [0.0001, 1, 10000]
for c_value in c_values:
svm_model = SVC(C=c_value)
svm_model.fit(X_train,y_train)
y_pred = svm_model.predict(X_test)
print('准确率:',accuracy_score(y_test,y_pred))

最后也就是简单的构造机器学习模型了,分类问题可用的模型有很多,这里选取了SVM和朴素贝叶斯,也没考虑过拟合等等优化,关于对机器学习模型优化的集成学习后期再实践吧。

0x03总结

关于对爬虫数据的获取,还有很多要需要学习的地方。数据是进行一切分析的基础,有了数据才可进行数据统计分析和机器学习等等。文本数据分析中关于中文和英文的处理还是略有不同,写代码的过程遇到的坑也是需要不断的实践来弥补。最近更博频率有点高,需要克制一下,需要我做的事还有很多,比如说我突发奇想,想做一个电台类似的节目,类似于Dj,我说真的,软件我都搞好了,请看

你们会喜欢吗? 下个路口,不见不散。

代码地址

代码地址:https://github.com/jwx0539/ML_CheckComments

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!