最近最火的电视剧,非《安家》莫属了。这是一部讲述房产中介的故事,有一个中介公司叫做“安家天下”,其中有两个店长,在剧情设定方面,我们就知道,这中间肯定会发生一些有(gou)趣(xue)的故事。因此我用Python爬取了豆瓣《安家》下所有的评论,进行了一波分析,从观众的角度来了解这部电视剧。

Part.1 爬虫部分

先来讲下技术栈,这个项目我用的是Scrapy+JSON的方式实现的。技术难度并不复杂,毕竟豆瓣并不是一个反爬虫很厉害的网站(学爬虫基本上都做过爬取top250),只要设置好User-Agent就行。在这里我就大概的描述一下代码过程,想要代码的可以在评论区评论“安家”,获取
第一步通过Scrapy命令创建一个项目和爬虫:

scrapy startproject anjia_scrapy
cd anjia_scrapy
scrapy genspider anjia "douban.com"

然后开始编写爬虫。爬虫部分可以分开来讲一下,首先找到《安家》的评论页面的链接:https://movie.douban.com/subject/30482003/reviews?sort=time&start=0,这个链接是通过offset来获取评论的,每一页展示20条评论,因此如果要获取下一页的数据,就是设置在当前页面基础上,给start+20就行了,这是第一点。然后总共有38页(后续页数据没有)因此可以生成一个range(0,760,20)了。

第二点是评论内容数据,如果超过一定的字数是会隐藏的,看下截图:

他的这个展开操作,并不是直接在界面上显示一下而已,而是发送了一次网络请求,因此我们还得针对每条评论重新请求一次,链接为:https://movie.douban.com/j/review/12380383/full,其中review后面的是这个评论的id,id可以在源代码中获取,这里就不再赘述了。

搞清楚了以上两点,我们就可以开始写代码了(数据提取规则这里不展开来讲,有兴趣的可以在评论区评论:安家获取源代码):

class AnjiaSpider(scrapy.Spider):name = 'anjia'allowed_domains = ['douban.com']start_urls = ['https://movie.douban.com/subject/30482003/reviews?sort=time&start=0']def parse(self, response):# 获取评论标签列表review_list = response.xpath("//div[contains(@class,'review-list')]/div")for review_div in review_list:# 作者author = review_div.xpath(".//a[@class='name']/text()").get()# 发布时间pub_time = review_div.xpath(".//span[@class='main-meta']/text()").get()# 评分rating = review_div.xpath(".//span[contains(@class,'main-title-rating')]/@title").get() or ""# 标题title = review_div.xpath(".//div[@class='main-bd']/h2/a/text()").get()# 是否有展开按钮is_unfold = review_div.xpath(".//a[@class='unfold']")if is_unfold:# 获取评论idreview_id = review_div.xpath(".//div[@class='review-short']/@data-rid").get()# 获取内容content = self.get_fold_content(review_id)else:content = review_div.xpath(".//div[@class='main-bd']//div[@class='short-content']/text()").get()if content:content = re.sub(r"\s",'',content)# 创建item对象item = AnjiaItem(author=author,pub_time=pub_time,rating=rating,title=title,content=content)yield item# 如果有下一页next_url = response.xpath("//span[@class='next']/a/@href").get()if next_url:# 请求下一页的数据yield scrapy.Request(response.urljoin(next_url),self.parse)

其中发送请求获取完整评论详情用的是requests库,代码如下:

def get_fold_content(self,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

最后就是编写数据存储的pipeline了,这里我是直接存储到json文件中,代码如下:

import json
class AnjiaScrapyPipeline(object):def __init__(self):self.fp = open("reviews.json", 'w', encoding='utf-8')def process_item(self, item, spider):self.fp.write(json.dumps(dict(item))+"\n")return itemdef close_spider(self,spider):self.fp.close()

爬虫比较关键的几个步骤基本上就讲得差不多了,全部代码可以在评论区评论:安家获取。

Part.2 数据分析部分

有了数据,我们就可以进行分析了,通过分析我们会发现很多有意思的点。这里我用到的技术栈是pandas+seaborn的方式进行分析的,然后代码也是在jupyter notebook中写的。以下来进行讲解。(代码获取方式同上)

第一步是读取数据,并将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'])

数据已经处理好了,接下来就可以进行分析了。这里我们从几个维度来分析,第一个是评论时间,第二个是评分,第三个是评论内容。

时间我们分成两个点来做,第一个是根据日期来,看下评论随着日期的变化呈现出怎样的趋势。通过DataFrame对发布时间的min和max,评论最早是在2020/02/20,最晚是在2020/03/14(也就是我写文章的这一天)。安家的播出时间是在02/21,如果我们不知道具体的播出时间,实际上通过数据你可以猜个八九不离十。接下来我们就实际动手,来看看随着播放时间的延长,评论数量呈现出怎样的趋势。代码如下,具体细节大家可以看注释:

# 分析评论日期
import re
from matplotlib import datesplt.figure(figsize=(10,5))# 2. 添加一个新的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]
# # 3. 根据日期分组绘图
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日开始播放,播放第二天评论数量就一下子冲到50+,说明这部剧在刚开始播出时还是受到很大的关注。随之评论量降低,但是在26-29号之间又来了一拨小高潮,具体电视剧我没咋看,不过从我家人看这电视剧的讨论中来看,那几天应该是发生了什么特别让观众气氛的事情。从这以后,这部电视剧就开始广泛在朋友圈(特别是房产中介)中开始刷屏了。

日期分析完了,我们再来看下时间,看下这些用户一般在哪些时间段评论得比较多。这里我从0点到24点,2个小时为一个时间段统计评论数量,代码如下:

# 分析评论时间
import datetime
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=45)

最终生成的图如下:

通过分析我们可以看到,排名前4的时间段中,在晚上8点到凌晨2点是评论最多的时候,完全符合当代年轻人的作息时间。估计那些2点钟还在评论的,是不是12点还在刷剧(说得是不是你☺)。其中有一个比较奇怪的时间,就是下午4点到6点,评论量是排名第三,这段时间还在评论的小伙伴,“摸鱼”大赛应该都是钻石以上段位了吧。哈哈,剩下的大家可以自行观察,接下来我们进入第二轮分析。

时间方向的分析完了,接下来咱们再来看看评论,这部剧我在网上看到很多批评的评价,那这到底是一部怎么样的剧呢,我们看用户的评分就行。大家都知道,豆瓣的评分是5星制,5星是力荐,4星是推荐,3星是还行,2星是较差,1星是很差。当然爬取下来的一些数据,由于用户评价的时候没有给分,因此我们给他归类到放弃这部分。代码如下:

# 看下评论好坏的情况
sns.countplot(x='rating',data=review_df,order=review_df['rating'].value_counts().index)

生成的图如下:

排名第一个的是放弃,我们暂且不讨论。不过还行,前两名都是推荐和力荐,占据了评论的绝大部分。当初我在网上看到的评价全是差评,这也提醒了我,我看到的一些信息不能全信,可能只是一叶障目而已。第三名很差,我具体看了下评价1星的评论,基本上都是说电视剧和现实中的中介差距很大,剧情太狗血之类的。这也能理解,每个人看剧的角度不同,评价也不一样的。

评价分析完了,我们再来看下观众对角色的情绪。除了剧情狗血,对角色设定的反感也是观众给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] += 5elif rating == '推荐':roles[name] += 4elif rating == '还行':roles[name] =3elif rating == '较差':roles[name] += 2elif rating == '很差':roles[name] += 1role_df = pd.DataFrame(list(roles.values()),index=list(roles.keys()),columns=['得分'])
role_df.sort_values('得分',inplace=True,ascending=False)
role_df.plot(kind='bar')

绘制出来的图如下:

朱闪闪得分居然最高?王子健得分最低?完全出乎我的意料,所以观众到底喜欢什么角色,有些时候不通过数据来看,你是真的想象不到…

最后一步,我们来把评论的文字进行分词,然后制作成一个词云,从词云中可以明显的看出文字出现的概率和次数。制作词云的代码如下:

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("停用词库.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) # 对分词做词频统计# 词频展示wc = wordcloud.WordCloud(font_path='C:/Windows/Fonts/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() # 显示图像content_str = ""
for row in review_df.index:content = review_df.loc[row,'content']content_str += contentgenerate_wc(content_str)

生成的词云效果如下(颜色搭配有些鸡肋):

房似锦和孙俪是出现的频率都很高,说明这个演员还是很受关注呀。另外房子,店长,客户,专业,行业,安家等都是高频词汇。不看电视从这个图中八九不离十就能猜到这是一部讲房产中介的电视剧啦。

因为篇幅原因,没有继续分析下去了,大家如果感兴趣,可以在评论区评论:安家即可获得本文所有代码。让我们一起进步吧,加油! 奥里给!!

我用Python爬取了《安家》所有数据,分析后发现它背后的一些秘密相关推荐

  1. python实战|python爬取58同城租房数据并以Excel文件格式保存到本地

    python实战|python爬取58同城租房数据并以Excel文件格式保存到本地 一.分析目标网站url 目标网站:https://cq.58.com/minsuduanzu/ 让我们看看网站长啥样 ...

  2. python爬取微博热搜数据并保存!

    主要用到requests和bf4两个库将获得的信息保存在d://hotsearch.txt下importrequests;importbs4mylist=[]r=requests.get(ur- 很多 ...

  3. Python爬取京东任意商品数据实战总结

    利用Python爬取京东任意商品数据 今天给大家展示爬取京东商品数据 首先呢还是要分思路的,我分为以下几个步骤: 第一步:得到搜索指定商的url 第二步:获得搜索商品列表信息 第三步:对得到的商品数据 ...

  4. python 爬取24小时天气数据

    python 爬取24小时天气数据 1.引入相关库 # -*- coding: utf-8 -*- import requests import numpy as np 关于爬虫,就是在网页上找到自己 ...

  5. 用python爬取基金网信息数据,保存到表格,并做成四种简单可视化。(爬虫之路,永无止境!)

    用python爬取基金网信息数据,保存到表格,并做成四种简单可视化.(爬虫之路,永无止境!) 上次 2021-07-07写的用python爬取腾讯招聘网岗位信息保存到表格,并做成简单可视化. 有的人留 ...

  6. python爬淘宝app数据_一篇文章教会你用Python爬取淘宝评论数据(写在记事本)

    [一.项目简介] 本文主要目标是采集淘宝的评价,找出客户所需要的功能.统计客户评价上面夸哪个功能多,比如防水,容量大,好看等等. [二.项目准备工作] 准备Pycharm,下载安装等,可以参考这篇文章 ...

  7. PYTHON爬取汽车之家数据

    PYTHON爬取汽车之家数据 使用知识 使用BeautifulSoup模块 使用正则表达式 使用到多线程爬取 使用说明 使用前请安装BeauifulSoup 起始页面: https://www.aut ...

  8. Python爬取影评并进行情感分析和数据可视化

    Python爬取影评并进行情感分析和数据可视化 文章目录 Python爬取影评并进行情感分析和数据可视化 一.引言 二.使用requests+BeautifulSoup进行影评的爬取 1.分析界面元素 ...

  9. 利用python爬取58同城简历数据

    利用python爬取58同城简历数据 最近接到一个工作,需要获取58同城上面的简历信息(http://gz.58.com/qzyewu/).最开始想到是用python里面的scrapy框架制作爬虫.但 ...

最新文章

  1. CSP认证201312-2 ISBN号码[C++题解]:简单题
  2. QDoc文字标记textmarkup
  3. C++中auto的用法,说明的是变量的寿命
  4. layer.confirm 询问框 的层遮盖
  5. 《构建实时机器学习系统》一1.8 实时机器学习模型的生存期
  6. Spring Boot (1) 构建第一个Spring Boot工程
  7. Timer定时器Demo
  8. php.c drcom,校园网绕过Drcom安装自动登录程序到路由器
  9. 没事研究下C#虚拟光驱,有所收获!
  10. Dropout也能自动化了,谷歌Quoc Le等人利用强化学习自动找寻模型专用Dropout
  11. HDU 4289 Control
  12. unity3D禁用脚本
  13. 差分编码与译码代码编写
  14. 2021年中国原油产量、需求量及石油原油行业发展趋势分析[图]
  15. 毕业论文速成指南来了!
  16. PHP 中openssl_pkey_get_private函数获取私钥返回 FALSE 的问题
  17. getchar函数详解看这一篇就够了-C语言(函数功能、使用、返回值)
  18. Rendezvous on a Tetrahedron (模拟)
  19. 18个月自学AI,2年写就三万字长文,过来人教你如何掌握这几个AI基础概念
  20. Interpro 安装问题

热门文章

  1. 讲英语者的10个成功秘诀
  2. 眼睛、鼻子、嘴巴如何画?动漫人物侧脸怎么画?
  3. 如何将图片转换成word文字
  4. 个推大数据2019春节瘦身城市排行报告:苏州成“瘦身”最快城市
  5. i7 9700和i7 9700k有什么区别 i7 9700和i7 9700k差多少
  6. 爱奇艺一键完成任务hph源码
  7. jdk其它版本下载链接
  8. 20幅妙不可言的光涂鸦摄影作品
  9. vlc arm linux,VLC播放器推出ARM64应用:Win10 on ARM应用生态获福音
  10. URLs(页面地址)