随着《青春有你2》的热播,你有没有被那些漂亮的小姐姐吸引呢?作为一个发际线已经到后脑勺的程序员,小姐姐的舞姿、歌声那些都是浮云。你想不想知道每期节目,观众评论最多的内容是什么?评论的内容是否健康呢?通过这篇博客,我将手把手教你如何实现。
1、中文分词需要jieba
2、词云绘制需要wordcloud
3、可视化展示中需要的中文字体
4、网上公开资源中找一个中文停用词表
5、根据分词结果自己制作新增词表
6、准备一张词云背景图(必须是白底的图片,可用hub抠图实现)
7、paddlehub配置
pip install jieba
pip install wordcloud
#安装模型
hub install porn_detection_lstm==1.1.0
pip install --upgrade paddlehub
既然是词频统计,肯定是爬取的越多越好。然而,一个页面加载的评论信息量太少,在爱奇艺的中,怎么找出未加载完的评论呢?在这里告诉你一个能快速找到大量评论的方法:在爱奇艺界面单击右键——>检查——>Notebook
当我们在爱奇艺页面点击加载更多评论时,在notebook中我们会看到有个get_comments的请求,由于一个网页界面呈现的内容有限,这个请求就是拉取更多内容。
点开该请求,可以看到:
其中,Request URL就是我们在爬取数据时所需要的 。通过多次点击加载更多评论,我发现每个get_comments请求中的Request URL只有last_id这个参数在变化,其他都没有变动。所以,我们可以直接用一个循环不停的改动last_id这个参数,就可以一直获取加载的更多评论。
from __future__ import print_function
import requests
import json
import re #正则匹配
import time #时间处理模块
import jieba #中文分词
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
from PIL import Image
from wordcloud import WordCloud #绘制词云模块
import paddlehub as hub
#请求爱奇艺评论接口,返回response信息
def getMovieinfo(url):
'''
请求爱奇艺评论接口,返回response信息
参数 url: 评论的url
:return: response信息
'''
session = requests.Session()
headers = {
"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36",
"Accept": "application/json",
"Origin": "http://m.iqiyi.com",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Host": "sns-comment.iqiyi.com",
"Referer": "https://www.iqiyi.com/v_19ryfkiv8w.html",
}
response = session.get(url, headers = headers)
if response.status_code == 200:
return response.text
return None
#解析json数据,获取评论
def saveMovieInfoToFile(lastId, arr):
'''
解析json数据,获取评论
参数 lastId:最后一条评论ID arr:存放文本的list
:return: 新的lastId
'''
url = "https://sns-comment.iqiyi.com/v3/comment/get_comments.action?agent_type=118&agent_version=9.11.5&authcookie=null&business_type=17&content_id=15068699100&hot_size=0&last_id="
url += str(lastId)
responseTxt = getMovieinfo(url)
responseJson = json.loads(responseTxt)
comments = responseJson['data']['comments']
for val in comments:
# print(val.keys())
if 'content' in val.keys():
# print(val['content'])
arr.append(val['content'])
lastId = str(val['id'])
return lastId
def clear_special_char(content):
'''
正则处理特殊字符
参数 content:原文本
return: 清除后的文本
'''
s = re.sub(r'?(.+?)>|$nbsp;|\t|\r', '', content)
s = re.sub(r'\n', ' ', s)
s = re.sub(r'\*', '\\*', s)
s = re.sub('[^\u4e00-\u9fa5^a-z^A-Z^0-0]', '', s)
s = re.sub('[\001\002\003\004\005\006\007\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19]','',s)
s = re.sub('[a-zA-Z]', '', s)
s = re.sub('^\d+(\.\d+)?$','',s)
return s
python 中有一个表情库emoji,也可以通过该库来处理表情字符。在这里我们就直接用正则化来处理。
由于中文语言的特殊性,不同位置进行分词导致语句的语义词义都有很大的差别,我们可以使用Python提供专门的分词库jieba,也可也以自己来定义一个分词规则‘add_words.text’。
def fenci(text):
'''
利用jieba进行分词
参数 text:需要分词的句子或文本
return:分词结果
'''
# jieba.load_userdict('add_words.text')
seq = jieba.lcut(text, cut_all = False)
return seq
在中文语句中,通常会有一些语气词‘吧、啊、阿、哎、哎呀、哎哟、唉’,转折词等,如果我们不将这种词剔除,将会对我们词频统计产生干扰。
def stopwordslist(file_path):
'''
创建停用词表
参数 file_path:停用词文本路径
return:停用词list
'''
stopwords = [line.strip() for line in open(file_path, encoding='UTF-8').readlines()]
return stopwords
def movestopwords(sentence, stopwords, counts):
'''
去除停用词,统计词频
参数 file_path:停用词文本路径 stopwords:停用词list counts: 词频统计结果
return:None
'''
out = []
for word in sentence:
if word not in stopwords:
if len(word) != 1:
counts[word] = counts.get(word,0) + 1
return None
def drawcounts(counts, num):
'''
绘制词频统计表
参数 counts: 词频统计结果 num:绘制topN
return:none
'''
x_aixs = []
y_aixs = []
c_order = sorted(counts.items(),key=lambda x:x[1],reverse=True)
for c in c_order[:num]:
x_aixs.append(c[0])
y_aixs.append(c[1])
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
plt.bar(x_aixs,y_aixs)
plt.title('词频统计结果')
plt.show()
def drawcloud(word_f):
'''
根据词频绘制词云图
参数 word_f:统计出的词频结果
return:none
'''
cloud_mask = np.array(Image.open('cloud.png'))
#忽略显示的词
st = set(['东西‘, ‘这是'])
#生成wordcloud对象
wc = WordCloud(background_color = 'white',
# mask = cloud_mask,
max_words = 150,
font_path='./fonts/simhei.ttf',
min_font_size = 10,
max_font_size = 100,
width = 400,
relative_scaling = 0.3,
stopwords = st)
wc.fit_words(word_f)
wc.to_file('pic.png')
这里主要用百度飞桨的porn_detection_lstm模型,进行情感的判断。
def text_detection(text,file_path):
'''
使用hub对评论进行内容分析
return:分析结果
'''
porn_detection_lstm = hub.Module(name='porn_detection_lstm')
f = open('aqy.txt','r',encoding='utf-8')
for line in f:
if len(line.strip()) == 1:
continue
else:
test_text.append(line)
f.close()
input_dict = {'text':test_text}
results = porn_detection_lstm.detection(data=input_dict,use_gpu=True,batch_size = 1)
for index, item in enumerate(results):
if item['porn_detection_key'] == 'porn':
print(item['text'],':',item['porn_probs'])
#评论是多分页的,得多次请求爱奇艺的评论接口才能获取多页评论,有些评论含有表情、特殊字符之类的
#num 是页数,一页10条评论,假如爬取1000条评论,设置num=100
if __name__ == "__main__":
num = 60
lastId = 0
arr = []
with open('aqy.txt','a',encoding='utf-8') as f:
for i in range(num):
lastId = saveMovieInfoToFile(lastId, arr)
time.sleep(0.5)
for item in arr:
Item = clear_special_char(item)
if Item.strip()!='':
try:
f.write(Item+'\n')
except Exception as e:
print('含有特殊字符')
print('共爬取评论:',len(arr))
f = open('aqy.txt','r',encoding='utf-8')
counts = {}
for line in f:
words = fenci(line)
stopwords = stopwordslist('cn_stopwords.txt')
movestopwords(words,stopwords,counts)
# print(counts)
drawcounts(counts,10)
drawcloud(counts)
f.close()
file_path = 'aqy.txt'
test_text= []
text_detection(test_text,file_path)
这里的num控制爬取数据的循环次数,在这里num=60,我们大概可以爬取1700多条评论数据。
可以看出,当评论为“色色色”之类的时,不健康指数很高。
至此,整个过程已经结束。
主函数中:
........
stopwords = stopwordslist('cn_stopwords.txt')
........
file_path = 'aqy.txt'
需要自己提供的文件:
cn_stopwords.txt为停用词表,我们可以根据常见的停用词进行原文本停用词的剔除;aqy.txt为进行健康审查时的评论文本。