利用AI Studio,分析《安家》评论
《安家》是一部讲述房产中介的电视剧,剧中房产中介公司叫做“安家天下”,其中有两个店长,在剧情设定方面,我们就知道,这中间肯定会发生一些有趣的故事。因此使用Python爬取了豆瓣《安家》下所有的评论,进行了数据分析,从观众的角度来了解这部电视剧。
在本案例中,主要分为两个部分:
第一部分是数据爬取。爬虫的过程,从总体来说,就是模仿浏览器的行为,往目标站点发送请求,接收服务器的响应数据,提取需要的信息,并进行保存的过程。Python为爬虫的实现提供了工具:requests模块、BeautifulSoup库等。
(1)requests模块是Python实现的简单易用的HTTP库,官网地址:http://cn.python-requests.org/zh_CN/latest/。
(2)BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库。官网地址:https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/。
第二部分是数据分析。本实践中主要使用Pandas和Matplotlib对所爬取的数据进行可视化。
本案例代码运行在一站式开发实训平台AI Studio上,Python版本为3.7.1。
《安家》数据爬取与分析
步骤1:数据爬取
首先找到《安家》的评论页面的链接:https://movie.douban.com/subject/30482003/reviews?sort=time&start=0,这个链接是通过offset来获取评论的,每一页展示20条评论,因此如果要获取下一页的数据,需要发送新的请求。
# 导入必要的包
import json
import re
import requests
from bs4 import BeautifulSoup
def crawl_data(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
}
url = 'https://movie.douban.com/subject/30482003/reviews'+url
try:
response = requests.get(url, headers=headers)
parse(response)
except Exception as e:
print(e)
第二点是评论内容数据,如果超过一定的字数是会隐藏的,如下图所示:
展开操作,并不是直接在界面上显示一下而已,而是发送了一次HTTP请求,因此我们需要针对每条评论重新请求一次,链接为:https://movie.douban.com/j/review/12380383/full,其中review后面的是这个评论的id,id可以在源代码中获取,这里就不再赘述了。
# 对爬取的页面数据进行解析
def parse(response):
item = {}
# 将一段文档传入BeautifulSoup的构造方法,就能得到一个文档的对象, 可以传入一段字符串
soup = BeautifulSoup(response.text, 'lxml')
# 返回的是class为main review-item的<div>所有标签
review_list = soup.find_all('div', {'class': 'main review-item'})
for review_div in review_list:
# 作者
author = review_div.find('a', {'class': 'name'}).text
# 发布时间
pub_time = review_div.find('span', {'class': 'main-meta'}).text
# 评分
rating = review_div.find('span', {'class': 'main-title-rating'})
if rating:
rating = rating.get('title')
else:
rating = ""
# 标题
title = review_div.find('div', {'class': 'main-bd'}).find('a').text
# 是否有展开按钮
is_unfold = review_div.find('a', {'class': 'unfold'})
if is_unfold:
# 获取评论id
review_id = review_div.find('div', {'class': 'review-short'}).get('data-rid')
# 获取内容
content = get_fold_content(review_id)
else:
content = review_div.find('div', {'class': 'short-content'}).text
if content:
content = re.sub(r"\s", '', content)
item = {
"author":author,
"pub_time":pub_time,
"rating":rating,
"title":title,
"content":content
}
fp.write(json.dumps(item) + "\n")
# 如果有下一页
next_url = soup.find('span', {'class': 'next'}).find('a')
if next_url:
# 请求下一页的数据
crawl_data(next_url.get('href'))
else:
return
return
# 获取展开内容
def get_fold_content(review_id):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
}
url = "https://movie.douban.com/j/review/{}/full".format(review_id)
resp = requests.get(url,headers=headers)
data = resp.json()
content = data['html']
content = re.sub(r"(<.+?>)","",content)
return content
步骤2:数据分析
数据准备工作完成之后,我们开始使用Pandas和Matplotlib进行数据可视化。第一步是读取数据,并将json格式的数据转成DataFrame,数据分析用DataFrame格式会方便很多。代码如下:
items = []
with open("reviews.json","r",encoding='utf-8') as fp:
for line in fp:
review = json.loads(line)
items.append(review)
item_list = [[item['author'],item['pub_time'],item['rating'],item['title'],item['content']] for item in items]# 构建DataFrame对象
review_df = pd.DataFrame(item_list,columns=['author','pub_time','rating','title','content'])# 删除缺失数值
review_df.dropna(inplace=True)# 将缺失的评论情况设置为放弃
review_df[review_df['rating']=='']['rating'] = '放弃'# 将字符串格式的时间转换为datatime类型
review_df['pub_time'] = pd.to_datetime(review_df['pub_time'])
这里我们主要从以下几个维度来进行分析,第一个是评论时间,第二个是评分,第三个是评论内容。
1.时间维度
第一个是根据评论日期,分析评论数量随着日期的变化呈现出怎样的趋势。
# 分析评论日期
import re
from matplotlib import dates
plt.figure(figsize=(10,5))
# 添加一个新的pub_date
review_df['pub_date'] = review_df['pub_time'].dt.date
review_df = review_df[pd.to_datetime(review_df['pub_date']).dt.year>2019]
review_df = review_df[pd.to_datetime(review_df['pub_date']).dt.month>1]
review_df = review_df[pd.to_datetime(review_df['pub_date']).dt.month<4]
# 根据日期分组绘图
review_date_df = review_df.groupby(['pub_date']).count()
ax = sns.lineplot(x=review_date_df.index,y=review_date_df.author,marker='o')
# 设置显示所有时间
ax.set(xticks=review_date_df.index)
# 设置x轴旋转
_ = ax.set_xticklabels(review_date_df.index,rotation=45)
# 设置x轴格式
ax.xaxis.set_major_formatter(dates.DateFormatter("%m-%d"))
ax.set_xlabel("发布日期")
ax.set_ylabel("评论数量")
可视化分析结果如上图所示,分析得到:《安家》从2月21日开始播放,第二天评论数量就达到一个高峰,说明这部剧在刚开始播出时还是受到很大的关注。之后评论数量降低,但是在2月26号到29号之间再次经历一拨小高潮。
接下来我们分析下用户在哪些时间段评论比较多。从0点到24点,2个小时为一个时间段统计评论数量,代码如下:
# 分析评论时间
import datetime
plt.figure(figsize=(10,5))
time_range = [0,2,4,6,8,10,12,14,16,18,20,22,24]
review_time_df = review_df['pub_time'].dt.hour
time_range_counts = pd.cut(review_time_df,bins=time_range,include_lowest=True,right=False).value_counts()
ax = time_range_counts.plot(kind="bar")
_ = ax.set_xticklabels(labels=time_range_counts.index,rotation=0)
可视化分析结果如上图所示,通过分析我们可以看到,在22点到24点之间是评论数最多的时候,当然也是跟也当代年轻人的作息时间是密不可分的。
2.评分维度
这部剧有很多不同的评价,那这到底是一部怎么样的剧呢?我们从用户的评分中就可以推断。众所周知,豆瓣的评分是5星制,5星是力荐,4星是推荐,3星是还行,2星是较差,1星是很差。其中爬取下来的一部分数据,由于用户评价的时候没有给分,因此归类到放弃这类。代码如下:
# 看下评论好坏的情况
sns.countplot(x='rating',data=review_df,order=review_df['rating'].value_counts().index)
可视化分析结果如上图所示:排名第一个的是放弃,前两名是推荐和力荐,看来网友对这部剧的评价还是不错的。当然,每个人看剧的角度不同,评价也不一样的。
评价分析完了,我们再来看下观众对角色的情绪。用户评分为1星很大 程度上是源于对角色设定的反感。因此我们根据用户评分和评论内容中出现的角色来进行打分(不是很严谨,但也能说明问题)。比如,用户评分为1星,然后这个评论内容中出现了几次“房似锦”,大概率说明这个观众对“房似锦”这个角色是比较反感的。其次,1星给1分,2星给2分,依次类推,谁的分高,说明谁更受观众喜爱。对内容的分词,用的是jieba分词工具。实现的代码如下:
# 电视剧人物的评分
# 力荐:+5,推荐:+4,还行:3,较差:2,很差:1
roles = {'房似锦':0,'徐文昌':0,'张乘乘':0,'王子健':0,'楼山关':0,'朱闪闪':0,
'谢亭丰':0,'鱼化龙':0,'宫蓓蓓':0,'阚文涛':0}
role_names = list(roles.keys())
for name in role_names:
jieba.add_word(name)
for row in review_df.index:
rating = review_df.loc[row,'rating']
if rating:
content = review_df.loc[row,"content"]
words = list(jieba.cut(content, cut_all=False))
names = set(role_names).intersection(set(words))
for name in names:
if rating == '力荐':
roles[name] += 5
elif rating == '推荐':
roles[name] += 4
elif rating == '还行':
roles[name] +=3
elif rating == '较差':
roles[name] += 2
elif rating == '很差':
roles[name] += 1
可视化分析结果如上图所示,分析发现,宫蓓蓓的得分居然是最高的。
3.评论内容
最后一步,我们把评论的文字进行分词,然后制作成词云,从词云中可以明显的看出文字出现的概率和次数。制作词云的代码如下:
def generate_wc(string_data):
# 文本预处理
pattern = re.compile(u'\t|\n|\.|-|:|;|\)|\(|\?|"') # 定义正则表达式匹配模式
string_data = re.sub(pattern, '', string_data) # 将符合模式的字符去除
# 文本分词
seg_list_exact = jieba.cut(string_data, cut_all = False) # 精确模式分词
object_list = []
remove_words = []
with open("work/停用词库.txt",'r',encoding='utf-8') as fp:
for word in fp:
remove_words.append(word.replace("\n",""))
for word in seg_list_exact: # 循环读出每个分词
if word not in remove_words: # 如果不在去除词库中
object_list.append(word) # 分词追加到列表
# 词频统计
word_counts = collections.Counter(object_list) # 对分词做词频统计
word_counts_top20 = word_counts.most_common(20) # 获取前10最高频的词
# 词频展示
wc = wordcloud.WordCloud(
font_path='work/simhei.ttf', # 设置字体格式
background_color="#000000", # 设置背景图
max_words=150, # 最多显示词数
max_font_size=60, # 字体最大值
width=707,
height=490
)
wc.generate_from_frequencies(word_counts) # 从字典生成词云
plt.imshow(wc) # 显示词云
plt.axis('off') # 关闭坐标轴
plt.show() # 显示图像
可视化分析结果如上图所示,从词云图中可以看出,出现概率较多的有“房子”、“中介”、“老洋房”、“店长”等词,不难推断出,这是一部主题为房产经纪的电视剧。
至此,完成了《安家》评论数据爬取和分析。本实践代码、视频及配套文档已发布在AI Studio课程里面,请扫描下方二维码或点击链接,进入学习:
https://aistudio.baidu.com/aistudio/course/introduce/1436
扫描下方二维码,进入课程学习~