2019-11-08豆瓣网电影区信息爬取与数据分析

**

爬取豆瓣电影信息,分析近年电影行业的发展情况

**

好奇心爆棚的电影爱好者

平常的休闲娱乐中,肯定少不了看电影,每次想找找电影看的时候,都会到各大电影评分网站去搜高分、好评、热门的电影,防止自己踩坑,浪费时间、精力去熬一部烂片。电影评分较权威的豆瓣网是我日常求助的地方,出于对电影的热爱和对电影行业的发展状况和趋势,今天就尝试着通过爬虫爬取豆瓣网的电影数据,来分析一下不同的发展趋势。

爬虫区

1import requests 2from lxml import etree 3import pandas as pd 4import numpy as np 5from selenium import webdriver 6from selenium.webdriver.common.by import By 7from selenium.webdriver.support import expected_conditions as EC 8from selenium.webdriver.support.wait import WebDriverWait 9import time 10import random 11import re 12 13

由于豆瓣的电影区采用了Ajax技术来渲染页面信息,为方便爬取页面的电影信息,采用了selenium方法来模拟浏览器访问页面并对Ajax渲染操作,不断获取更新的电影信息。
另外还需requests、xpath、re、pandas、numpy处理爬取信息,再使用time、random作为辅助处理方法。

1with open('user_agents.txt', 'r') as f: 2 U=[] 3 for line in f: 4 U.append(f.readline()) 5 6

user_agent.txt收集了大量不同的user-agent数据,用来编辑访问请求的请求头信息,模仿后期的浏览器浏览

1url='https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0' 2#豆瓣电影区,根据热门标签选电影的url 3broser=webdriver.Chrome() 4broser.get(url) 5n=14 #每一次Ajax渲染出来20部电影信息,n是20次Ajax渲染,爬取电影数量为20*n 6for i in range(n): 7 wait=WebDriverWait(broser,20) 8 button=wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'more'))) 9 button.click() 10 time.sleep(1) 11movie_photo=[item.get_attribute('src') for item in broser.find_elements_by_xpath('//div[@class="cover-wp"]/img')] 12movie_url=[item.get_attribute('href') for item in broser.find_elements_by_class_name('item')] 13broser.close() 14 15

通过selenium作n次Ajax渲染后,爬取页面源代码中电影的图片、url,并关闭浏览器,后续再对爬取到的信息过滤采集。

1'''存储爬取电影图片可选''' 2# for i in range(len(movie_photo)): 3# open('MoviePhoto\\'+str(i)+'.jpg','wb').write( requests.get(movie_photo[i],headers=headers).content ) 4output=[] #用以整合所有类别的数据的列表 5for i in range(len(movie_url)): 6 useragent = U[random.randint(0, len(U)-1)].strip() 7 #调用所有存储的user-agent头信息,加强每次访问电影地址时候的爬虫生命力 8 headers = { # 设置请求头,如需建造更严谨、更安全的爬虫,可以设置多个User-Agent信息以便循环调用。 9 'User-Agent': useragent 10 } 11 response=requests.get(movie_url[i],headers=headers) 12 html=etree.HTML(response.text) #将网页返回信息存储成html格式,允许xpath方法分析 13 name=html.xpath('//span[@property="v:itemreviewed"]/text()')#电影名 14 director=html.xpath('//a[@rel="v:directedBy"]/text()')#导演 15 #playwright=html.xpath('//span[@class="pl",contains(text(),"编剧")]//text()') 16 actor=html.xpath('//span[@class="actor"]/span[@class="attrs"]//text()')#演员 17 movie_class=html.xpath('//span[@property="v:genre"]//text()')#电影分类 18 contry=re.compile('<span class="pl">制片国家/地区:</span>(.*?)<br/>').findall(response.text)#制片国家\地区 19 releasedate=html.xpath('//span[@property="v:initialReleaseDate"]/@content')#上映日期 20 runtime=html.xpath('//span[@property="v:runtime"]/@content')#片长 21 grade=html.xpath('//strong[@class="ll rating_num"]/text()')#电影评分 22 try: #整合一部电影的所有信息 23 data=name+grade+[movie_class[0]]+[director[0]]+[actor[0]]+contry+[releasedate[0]]+runtime 24 print(data) #便于运行程序时观察爬取的信息,便于后期修改 25 output.append(data) #整合入最终的输出列表 26 except: 27 continue 28movie_data=pd.DataFrame(output,columns=['电影名','豆瓣分数','类别','导演','演员','制片国家/地区','上映日期','片长']) 29movie_data.to_csv('Douban_Movie.csv') 30#导出至目录下的Douban_Movie.csv文件 31 32

数据分析区

1import pandas as pd 2import numpy as np 3import datetime 4from matplotlib import pyplot as plt 5 6movie=pd.read_csv('Douban_Movie.csv') 7del movie['Unnamed: 0'] #删除第一列无意义列,是导出csv时的索引列 8movie['片长']=movie['片长'].dropna() #小部分电影唔片长信息 9 10'''绘制电影片长分布图''' 11plt.hist(movie['片长'],bins=np.arange(60,190,10)) 12plt.title('Histogram : The length of films') 13plt.tight_layout() 14plt.xlabel('The length of a film') 15plt.ylabel('Numbers of films') 16plt.show() 17 18

在这里插入图片描述

1'''对数据集的 “上映日期” 列进行数据清洗,除去上映地点信息''' 2def rebuild(x): 3 x=x[:10] 4 if '(' in x: 5 start=x.index('(') 6 x=x[:start] 7 return x 8movie['上映日期']=movie['上映日期'].apply(rebuild) 9movie['上映日期']=pd.to_datetime(movie['上映日期']) #修改类型datetime64[ns] 10movie=movie.set_index('上映日期') #将上映日期设置为索引 11movie=movie.sort_index(ascending=False) 12'''绘制不同制片国家\地区电影的平均分数''' 13fig3=movie[['制片国家/地区','豆瓣分数']].groupby(by=movie['制片国家/地区']).mean() 14#print(fig3) 15# plt.hist(fig3.index) #需要画出直方图,需要修正中文字体显示 16# plt.xlabel('moviemaking country/district') 17# plt.ylabel('Mean grade') 18# plt.title('Histogram : films mean grade in different moviemaking country/district') 19# plt.show() 20 21

此处尚未解决中文作图的报错,所以暂时缺图

1print(fig3.describe()) 2 3

count 58.000000
mean 6.740270
std 0.938747
min 3.600000
25% 6.300000
50% 6.687500
75% 7.375000
max 9.100000

1'''绘制近年不同月份下上映电影的平均分''' 2# mean_grade_month=movie.resample('MS').mean() # 绘制近年不同月份上映电影的平均分数 3# plt.plot(mean_grade_month['豆瓣分数']) 4# plt.xlabel('Year-Month') 5# plt.ylabel('Mean Grade') 6# plt.title('The mean grade of films in recent years') 7# plt.show() 8 9

在这里插入图片描述

1print(movie[movie['豆瓣分数']>8].count()) 2 3

豆瓣分数大于8分的电影数为22部,热门标签下爬取的电影总数为254部,占比8.67%。

数据分析

作为数据分析初学者,我会尽我所能尝试分析,【此篇文章的所有分析观点都仅代表文章原创者的现时观点,如有观点不同,欢迎评论,我也很愿意接受不同角度的分析观点。】
1、相比于以前电影片长集中在100分钟内,如今电影的发行,片长都集中在100分钟至200分钟区段,叙事时间的延长利于讲好、讲深每个故事,更加能够满足观影者对电影全景的展示的需求,也更能让故事的观点升华到更高的深度,触动观影者。
2、根据获取的不同制片国家\地区的电影平均分,发现电影工业发展也同样趋于全球化,多方合作制作电影是未来的大趋势,将各方的优势集中融合,能提升电影的视觉效果和叙事能力。各制片国家\地区的电影平均分在6.740270,分数集中在6.30~7.38区间,热门标签采集的电影数据下,最大评分9.1。高分电影还是占少数,只有8.67%。
3、根据热门标签下爬取的电影信息,发现电影平均分高的上映日期集中在年末年初。
【由于采集样本的数量还是很少,本文章分析的观点仍是很片面的,不是成熟的、专业的数据分析】
因为该文章只是初试数据分析,也是初始检验这个小项目成果的试验品,后期会重新整理修改爬取电影的数目,再从更多方面、角度来分析电影工业的发展状况。

代码交流 2021