豆瓣爬虫实战——Angelababy到底是什么风评

  • 研究目的
  • 大体思路
  • 操作
    • 1.数据获取
      • (1)首先是提取所有的电影信息,做成一个表。
      • (2)再获取一些比较细节的节目内容
    • (3)用筛选出来的电影/电视剧ID抓取短评
    • (4)拿到了这些短评之后,做一些数据分析
      • (a)从评分看
      • (b)从评论看
      • (c)从演职人员来看
  • 总结

研究目的

作为一个不经常观看娱乐圈的直男,我对Angelababy这个人的印象飘忽不定:在各个平台非常唯美的一个人,一转战到b站知乎就变成了一个差评如潮的演员。说实在话,我除了看过《奔跑吧》和《寻龙诀》,剩下的对这个明星一无所知。所以惊天我就来满足一下我的好奇心,从演员角度看看在群众眼里他到底是一个什么样的人。

大体思路

作为演员,我们最直观的就是看她参演过的电影或者电视剧反响,所以在这里选择了豆瓣网——信息多且易爬取。在豆瓣上我们搜索“杨颖”就能得到她参演的各种项目。(豆瓣查询链接)


截至目前,搜索页一共有9页,我们需要先拿出这9页的所有节目信息,然后把上映的电影电视剧筛出来,对于每一个节目查询他们的短评,这样就算是拿到了所有的评价信息。

如果我们仔细看页面链接,发现每一个影片都有ID,我们只要按照格式就能进入这个页面的总短评(不管是电视剧还是电影)。
短评格式:https://movie.douban.com/subject/节目ID/comments?start=0&limit=20&sort=new_score&status=P

例:https://movie.douban.com/subject/26980826/comments?start=0&limit=20&sort=new_score&status=P

拿到评价信息之后,我们可以先从评论里看看对杨颖参演的总体评价是如何的。

操作

1.数据获取

(1)首先是提取所有的电影信息,做成一个表。

我们对上边这个页面进行翻页,发现网页的规律如下:
第一页:https://movie.douban.com/celebrity/1033011/movies?start=0&format=pic&sortby=time&
第二页:https://movie.douban.com/celebrity/1033011/movies?start=10&format=pic&sortby=time&

我们发现每十个节目是一页,下一页就在这个位置+10就可以了,所以我们编写code如下

import requests
import pandas as pd
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
from tqdm import trange
from tqdm import tqdm_notebook as tqdm# 建立随机agent 防止页面拒绝访问
ua = UserAgent()
headers = {'User-Agent':ua.random}#提取总页面内容,做一个索引
tbl_baby_movies = pd.DataFrame()
for main_page_num in trange(9):#对于杨颖的9页节目单#设置可随着loop变的urlbaby_movie_url = f'https://movie.douban.com/celebrity/1033011/movies?start={main_page_num*10}&format=pic&sortby=time&'#获取response = requests.get(baby_movie_url, headers=headers)soup = BeautifulSoup(response.text, "html.parser")for movie in range(len(soup.find_all('h6'))):#对于每一个节目baby_movies_dict = {}#节目名称baby_movies_dict['movie_name'] = soup.find_all('h6')[movie].a.text#节目链接(以防万一)baby_movies_dict['movie_link'] = soup.find_all('h6')[movie].a['href']#是否上映if soup.find_all('h6')[movie].find_all('span')[1].text=='(未上映)':baby_movies_dict['coming_soon']='Y'else:baby_movies_dict['coming_soon']='N'tbl_baby_movies = tbl_baby_movies.append(baby_movies_dict,ignore_index=True)

之后我们就得到了一个这样的表

(2)再获取一些比较细节的节目内容

拿到这些link之后,我们要挨个进去看看它们是什么类型的节目,这样有助于帮我们选择出电视剧和电影。

这些从细节页面里都有体现。除此之外,我们还可以拿一拿其他的电影信息。

#把已经上架的选出来
onboard_general_links = tbl_baby_movies[tbl_baby_movies['coming_soon']=='N']['movie_link'].tolist()
#获取页面
general_links = pd.DataFrame()
for link in tqdm(onboard_general_links):general = {}response = requests.get(link, headers=headers)soup = BeautifulSoup(response.text, "html.parser")#左边的节目详细信息general['name'] = soup.find('span',{'property':'v:itemreviewed'}).texttry:general['link'] = link#影片类型general['type1'] = soup.find_all('span',{'property':'v:genre'})[0].textgeneral['type2'] = soup.find_all('span',{'property':'v:genre'})[1].textgeneral['type3'] = soup.find_all('span',{'property':'v:genre'})[2].textexcept:pass#影片市场try:general['program_length'] = int(soup.find_all('span',{'property':'v:runtime'})[0].text.replace('分钟',''))except:pass #右边的豆瓣评分板块#每个星评分的百分比try:general['overall_star']= float(soup.find_all('strong',{'class':'ll rating_num'})[0].text)for star in range(5):general['overall_star_'+str(star+1)]= float(soup.find_all('span',{'class':'rating_per'})[star].text.replace('%',''))      except:pass    #好于百分之几的什么片try:good_than=soup.find_all('div',{'class':'rating_betterthan'})[0].find_all('a')general['good_than_1'] = good_than[0].textgeneral['good_than_2'] = good_than[1].textexcept:pass  general_links = general_links.append(general,ignore_index=True)
general_links[[col for col in general_links.columns.tolist() if 'overall_star' in col]] = general_links[[col for col in
#评分补空值
general_links.columns.tolist() if 'overall_star' in col]].fillna(0)
#保存表
general_links.to_csv('angelababy_programs.csv',index= None,encoding ='utf-8-sig')

做出来之后就是这样的一个索引:

顺便看一下杨颖参演的总体评分

general_links.loc[general_links['overall_star']!=-1,'overall_star'].mean()
#5.6551724137931005

5.7,一个不高也不低的数字。

我们再把歌舞晚会真人秀这样的节目从表里去掉,然后再拿到每个节目的的ID,一会要用这些得到的ID去搜索它们的短评。

tbl_baby_movie_links = general_links[(general_links['type1']!='真人秀')\& (general_links['type1']!='脱口秀') \& (general_links['type1']!='歌舞')\& (general_links['type1']!='音乐')\]
tbl_baby_movie_links['link_id'] = tbl_baby_movie_links['link'].str.replace('https://movie.douban.com/subject/','').str.replace('/','')

拿到的ID就像是这样

再看看总体评分的变化

貌似有一点下降。。。。。。(别着急)

(3)用筛选出来的电影/电视剧ID抓取短评

用这些ID我们做一个循环抓取

data= pd.DataFrame()
for baby_item in tqdm(tbl_baby_movie_links['link_id'].tolist()):extract_page = 10ID = baby_itemstatus='P'#or F:想看 P: 看过SORT = 'new_score'#or time:按最新排序 new_score: 按热门排序for page in tqdm(range(extract_page)):url = f'https://movie.douban.com/subject/{baby_item}/comments?start={page*20}&limit=20&sort={SORT}&status={status}'headers = {'User-Agent':ua.random}try:#尝试着对我们合成的页面进行获取response = requests.get(url, headers=headers)soup = BeautifulSoup(response.text, "html.parser")#拿到一些电影统一的信息movie_name = soup.find_all('div',{'id':'content'})[0].select('h1')[0].text.replace(' 短评','')movie_staff = soup.find_all('span',{'class':'attrs'})[0].find_all('a')actor = ' '.join([name.text for name in movie_staff[1:-1]])movie_type = soup.find_all('span',{'class':'attrs'})[0].find_all('p')[2].text.replace(' ','').replace('\n','').replace('类型:','')movie_region = soup.find_all('span',{'class':'attrs'})[0].find_all('p')[3].text.replace(' ','').replace('\n','').replace('地区:','')movie_time = soup.find_all('span',{'class':'attrs'})[0].find_all('p')[4].text.replace(' ','').replace('\n','').replace('片长:','').replace('分钟','')move_onboard_time = soup.find_all('span',{'class':'attrs'})[0].find_all('p')[-1].text.replace(' ','').replace('\n','').replace('上映:','')comments = soup.find_all('div',{'class':'comment'})for comment in range(len(comments)):temp_comment_info={}#影片固定信息temp_comment_info['movie'] = movie_nametemp_comment_info['director'] = movie_staff[0].texttemp_comment_info['actor'] = actor#评论信息temp_comment_info['user'] = comments[comment].find_all('a',{'class':''})[0].texttemp_comment_info['user_url'] = comments[comment].find_all('a',{'class':''})[0]['href']temp_comment_info['useful'] = int(comments[comment].find('span',{'class':'votes'}).text)temp_comment_info['date'] = comments[comment].find('span',{'class':'comment-time'}).text.replace('\n','').strip(' ')temp_comment_info['text'] = comments[comment].find('span',{'class':'short'}).textif status == 'P':temp_comment_info['status'] = 'P'try:temp_comment_info['rating'] = int(comments[comment].find('span',{'class':'comment-info'}).find_all('span')[1]['class'][0].replace('allstar',''))except:print(f'no rating in page {page}, comment {comment+1}')                else:temp_comment_info['status'] = 'F'data = data.append(temp_comment_info,ignore_index=True)except:#如果没有的话就说明评论太少导致页面不足,进入下一个电影/电视剧print(f'no page {page+1} for id {baby_item}')break
data.to_csv('baby_comment.csv',index= None,encoding ='utf-8-sig')

做出来之后就像这样:

(4)拿到了这些短评之后,做一些数据分析

(a)从评分看

先改一下日期格式

data_1 = data.copy()
#更改日期格式
data_1['year_mth'] = data_1['date'].str[:7].str.replace('-','').astype(str)
data_1['date'] = pd.to_datetime(data_1['date']).dt.strftime('%Y/%m/%d')#选出有评分的
data_2 = data_1[data_1['rating'].notnull()]

康康我们群众的眼睛,再次看看短评对杨颖参演电视剧/电影的总体评分


WOOOOOOO…这跟影评里写的差池很大啊,别着急。之前的豆瓣电影的评分就是基于用户打分:把豆瓣用户的打分(一到五星换算为零到十分)加起来,再除以用户数。所以民众评分换算过来就是4.8分。

看看平均评分最高的和最低的

import plotly.express as px
fig = px.bar(data_2.groupby('movie')['rating'].mean().sort_values(ascending=False).reset_index(), x='movie', y='rating',color='rating')
fig.show()


何以笙箫默?那没事了…

看看有没有冲分的(我们选的是精华帖,也就意味着代表民意;评分是总体的加权)。

#我们连接上最开始的总体评分
data_2 = data_2.merge(tbl_baby_movie_links,how='left',left_on='movie',right_on='name')
#标准化一下评分
data_2['rating']=data_2['rating']/10
data_2['overall_star']=data_2['overall_star']/2
#制作表格
pingfen_compare = data_2.groupby('movie')[['rating','overall_star']].mean().sort_values(by='rating',ascending=False).reset_index()
#只选有影评分的(有两个没有)
pingfen_compare = pingfen_compare[pingfen_compare['overall_star']!=-0.5]import plotly.graph_objects as gofig = go.Figure(data=[go.Bar(name='热评评分', x=pingfen_compare['movie'], y=pingfen_compare['rating'],marker_color='lightgreen'),go.Bar(name='豆瓣影评分', x=pingfen_compare['movie'], y=pingfen_compare['overall_star'],marker_color='lightsalmon')
])
# Change the bar mode
fig.update_layout(barmode='group')
fig.show()


要是这个不明显的话,看看两者之差

pingfen_compare['diff'] = pingfen_compare['rating']-pingfen_compare['overall_star']fig = go.Figure(data=[go.Bar(x=pingfen_compare.sort_values('diff')['movie'], y=pingfen_compare.sort_values('diff')['diff'])])
# Customize aspect
fig.update_traces(marker_color='rgb(158,202,225)', marker_line_color='rgb(8,48,107)',marker_line_width=1, opacity=0.7)
fig.update_layout(title_text='热评与总评分之差(越大越没有嫌疑)')
fig.show()


咳咳,又是《何以笙箫默》

再看看热门评分分数的占比吧

colors = ['gold', 'mediumturquoise', 'darkorange', 'lightgreen']fig = go.Figure(data=[go.Pie(labels=data_2['rating'].value_counts().reset_index()['index'],values=data_2['rating'].value_counts().reset_index()['rating'], hole=.5)])
fig.update_traces(hoverinfo='label+percent', textinfo='label+percent', textfont_size=20,marker=dict(colors=colors, line=dict(color='#000000', width=2)))
fig.show()


秒懂,1分之王

最后让我们按照时间看看我们大baby的火爆时间

rating_by_ymh = pd.DataFrame(data_2.groupby(['year_mth','movie'])['rating'].mean()).reset_index(drop=False)
fig = px.bar(rating_by_ymh, x="year_mth", y="rating",color='movie',height=400)
fig.show()


能看出来,2017年是她的最忙的时候,各种电影应接不暇。

(b)从评论看

我们先做个词云玩玩,看看评论最多的到底是啥。

我们用清华大学做的NLP库来分词(因为准确率要比其他的库高)

import thulac
thulac_model = thulac.thulac()test_text = data_2['text']#找出所有的评分有效评论
select_word=[]
for roll_text in trange(data_2.shape[0]):wordseg = thulac_model.cut(test_text[roll_text])    #拿到除标点符号、副词、量词、助词、代词和方位词的词for word in wordseg:if word[1]!='w' and word[1]!='d' and word[1]!='q' and word[1]!='u' and word[1]!='r' and word[1]!='f':select_word.append(word[0])#去掉单字
fnl_words = [word for word in select_word if len(word)>1]#检查一下, 再去掉一些没分化出来的词
word_freq_chk = pd.DataFrame({'word':list(cnt_list.keys()),'cnt':list(cnt_list.values())}).sort_values(by='cnt', ascending=False)
word_freq_chk[:30]
fnl_words_1 = fnl_words
fnl_words_1 = [ele for ele in fnl_words_1 if ele not in ['一个','觉得','感觉']]import wordcloud
wc = wordcloud.WordCloud(width=1920*2, font_path='simfang.ttf',height=1080*2)#设定词云画的大小字体,一定要设定字体,否则中文显示不出来
wc.generate(' '.join(fnl_words_1))from matplotlib import pyplot as plt
plt.imshow(wc)

这还不够!因为这些电影有些杨颖只是刷了个脸,我们要挑选出来她是主演的电影

#分化一下演员(演员列表是按照顺序记录的)
tbl_actor_list = data_2["actor"].str.split(" ", n = 30, expand = True)
tbl_actor_list.columns = ['actor_'+str(i+1) for i in range(31)]
#join回去
data_2 = pd.concat([data_2, tbl_actor_list], axis=1, sort=False)


把她是主演的电影选出来(演员排名前五),再按照同样的方式做一遍

baby_test_text = data_2.loc[(data_2['actor_1']=='杨颖') | (data_2['actor_2']=='杨颖') | (data_2['actor_3']=='杨颖') |(data_2['actor_4']=='杨颖') |(data_2['actor_5']=='杨颖') , 'text'].reset_index(drop = True)#找出所有的评分有效评论
select_word_2=[]
for roll_text in tqdm(baby_test_text):wordseg = thulac_model.cut(roll_text)    #拿到除标点符号、副词、量词、助词、代词和方位词的词for word in wordseg:if word[1]!='w' and word[1]!='d' and word[1]!='q' and word[1]!='u' and word[1]!='r' and word[1]!='f':select_word_2.append(word[0])
fnl_words_2 = [word for word in select_word_2 if len(word)>1]
fnl_words_3 = fnl_words_2
fnl_words_3 = [ele for ele in fnl_words_2 if ele not in ['一个','觉得','感觉','第一','看到']]
wc = wordcloud.WordCloud(width=1920*2, font_path='simfang.ttf',height=1080*2)#设定词云画的大小字体,一定要设定字体,否则中文显示不出来
wc.generate(' '.join(fnl_words_3))
plt.imshow(wc)


哦哦哦,有演技!!!我们再带回去确认一下!

for comment in data_2[data_2['text'].str.contains('演技', regex=False)]['text'].sample(frac=0.5).reset_index(drop=True)[:10]:print(comment)print('---------------------------------------------------------------------')

…咳咳,这不重要

(c)从演职人员来看

先做以下处理

actor_list = list(set(' '.join(data_2.drop_duplicates(subset= 'movie')['actor'].tolist()).split(' ')))[1:]
for actor in tqdm(actor_list):data_2['actor_include_'+actor] = data_2['actor'].str.contains(actor, regex=False).astype(int)

看看哪位演员参与了低分(3分一下)演出的评论最多

bad_actor = data_2.loc[data_2['rating']<=3,[col for col in data_2.columns if 'actor_include_' in col]].sum().reset_index().sort_values(by=0,ascending=False)[1:20].reset_index(drop=True)
bad_actor.columns=['actor_include','comment_count']
bad_actor['actor_include']=bad_actor['actor_include'].str.replace('actor_include_','')#画图
colors = ['lightslategray',] * 19
colors[0] = 'crimson'fig = go.Figure(data=[go.Bar(x=bad_actor['actor_include'],y=bad_actor['comment_count'],marker_color=colors
)])
fig.update_layout(title_text='哪位演员跟随差评最多')
fig.show()

看看哪位导演也受了危害

bad_dir = data_2.loc[data_2['rating']<=3,'director'].value_counts().sort_values(ascending=False).reset_index(drop=False)[:10]
bad_dir.columns =['director_include','comment_count']colors = ['lightgray',] * 10
colors[0] = 'lightgreen'fig = go.Figure(data=[go.Bar(x=bad_dir['director_include'],y=bad_dir['comment_count'],marker_color=colors
)])
fig.update_layout(title_text='哪位导演跟随差评最多')
fig.show()

总结

以上就是部分杨颖的爬虫数据分析了。

不难看出我们的大BABY虽然非常热门,但是参演的大多数电影/电视剧风评都不太好,且这些差评作品也都是同期偶像演员凑成的班底,显然是以量取胜。

细心的同志会发现,我并没有完全开发完这个数据,只是对豆瓣网上的数据现状进行了剖析。后续我会用这个数据建模来分析怎样使你的评论更让大家觉得有用。

做完之后我会把链接加进这个博客。如果你有什更好的想法或者搞怪的主意,务必留言给我,让我们一起探寻!!

豆瓣爬虫实战——Angelababy到底是什么风评相关推荐

  1. xhr get获取文件流下载文件_python爬虫实战——豆瓣电影get初体验

    影评许可证 公众号[2019]第22期 本栏目由"数据皮皮侠"独家呈献 专场 python爬虫实战--豆瓣电影get初体验 2019.10.28 / 早上7点场 / 免费 本期&q ...

  2. Python3 爬虫实战 — 豆瓣电影TOP250【requests、Xpath、正则表达式、CSV、二进制数据储存】

    爬取时间:2019-09-27 爬取难度:★★☆☆☆☆ 请求链接:https://movie.douban.com/top250 以及每部电影详情页 爬取目标:爬取榜单上每一部电影详情页的数据,保存为 ...

  3. Python 爬虫实战:分析豆瓣中最新电影的影评

    Python 爬虫实战:分析豆瓣中最新电影的影评 接触python时间不久,做些小项目来练练手.前几天看了<战狼2>,发现它在最新上映的电影里面是排行第一的,如下图所示.准备把豆瓣上对它的 ...

  4. 爬虫实战2(上):爬取豆瓣影评

       这次我们将主要尝试利用python+requsets模拟登录豆瓣爬取复仇者联盟4影评,首先让我们了解一些模拟登录相关知识补充.本文结构如下: request模块介绍与安装 get与post方式介 ...

  5. 爬虫实战2(下):爬取豆瓣影评

       上篇笔记我详细讲诉了如何模拟登陆豆瓣,这次我们将记录模拟登陆+爬取影评(复仇者联盟4)实战.本文行文结构如下: 模拟登陆豆瓣展示 分析网址和源码爬取数据 进行面对对象重构 总结   一.模拟登陆 ...

  6. 爬取豆瓣读书-豆瓣成员常用的标签(Python爬虫实战)

    前两篇博客,我们介绍了如何对豆瓣读书历史记录进行抓取,这一篇博客是一个收尾工作. 传送门: 爬取豆瓣读书-用户信息页链接(Python爬虫实战) 爬取豆瓣读书-用户所有阅读书籍名称.日期和书籍链接(P ...

  7. 爬虫实战——豆瓣电影Top250

    爬虫实战--豆瓣电影Top250 准备阶段 网页分析 在目标网页直接ctrl+u查看网页源代码(或者F12审查),豆瓣的网页源代码就出现了(非常友好): <!DOCTYPE html> & ...

  8. Python爬虫实战(1) | 爬取豆瓣网排名前250的电影(下)

    在Python爬虫实战(1) | 爬取豆瓣网排名前250的电影(上)中,我们最后爬出来的结果不是很完美,这对于"精益求精.追求完美的"程序猿来说怎么能够甘心 所以,今天,用pyth ...

  9. python实例豆瓣音乐代码_Python爬虫实战(3)-爬取豆瓣音乐Top250数据(超详细

    前言 首先我们先来回忆一下上两篇爬虫实战文章: 第一篇:讲到了requests和bs4和一些网页基本操作. 第二篇:用到了正则表达式-re模块 今天我们用lxml库和xpath语法来爬虫实战. 1.安 ...

最新文章

  1. python课程怎么样-python课程体系是怎么样的?
  2. TensorFlow莫烦 placehoder (三)
  3. AAAI2019 | 腾讯AI Lab详解自然语言处理领域三大研究方向及入选论文
  4. 一招明白URL和URI的区别
  5. 35岁成MIT终身教授!北大数学“黄金一代”再获大奖
  6. GitHub 创建项目
  7. SpringBoot (14)---日志配置(logback)
  8. [过年菜谱之]清蒸鲍鱼
  9. (二)可变分区存储管理方案中的内存分配
  10. 排名前50的开源Web爬虫用于数据挖掘
  11. python PDF文件拆分与合并
  12. 语文网站第十九周推荐博客
  13. R语言字符串相关操作
  14. JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK17特性讲解】
  15. VS2010在加载项目时,提示无法打开项目文件, 此安装不支持该项目类型的解决方法
  16. 炒白菜怎么做(保姆级教程 爸妈吃了都说好)
  17. 2022群发邮件软件有哪些?哪个好用呢?解读如何大量群发邮件及单显功能
  18. nginx配置tcp转发
  19. 摄影基础1 : 135相机
  20. 光遇安卓服务器维护哪天,光遇安卓版什么时候上线 光遇全平台公测具体开服时间...

热门文章

  1. STM32G071RB-NUCLEO和X-NUCLEO-GFX01M1进行GUI开发(一)
  2. nii文件中的方向理解
  3. js运动小球碰壁反弹
  4. 平面几何----用梅涅劳斯定解20年一道高三数学模拟题
  5. 请给我一本防爆仓秘籍@中本葱
  6. A Persona-Based Neural Conversation Model论文
  7. [转载]ExtJs4 笔记(11) Ext.ListView、Ext.view.View 数据视图
  8. 微信公众号网页H5跳转微信小程序
  9. 神经网络入门经典书籍,神经网络基础书籍
  10. 数字化采购管理系统开发:精细化采购业务流程管理,赋能企业实现“阳光采购”