**
**
平常的休闲娱乐中,肯定少不了看电影,每次想找找电影看的时候,都会到各大电影评分网站去搜高分、好评、热门的电影,防止自己踩坑,浪费时间、精力去熬一部烂片。电影评分较权威的豆瓣网是我日常求助的地方,出于对电影的热爱和对电影行业的发展状况和趋势,今天就尝试着通过爬虫爬取豆瓣网的电影数据,来分析一下不同的发展趋势。
import requests
from lxml import etree
import pandas as pd
import numpy as np
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
import random
import re
由于豆瓣的电影区采用了Ajax技术来渲染页面信息,为方便爬取页面的电影信息,采用了selenium方法来模拟浏览器访问页面并对Ajax渲染操作,不断获取更新的电影信息。
另外还需requests、xpath、re、pandas、numpy处理爬取信息,再使用time、random作为辅助处理方法。
with open('user_agents.txt', 'r') as f:
U=[]
for line in f:
U.append(f.readline())
user_agent.txt收集了大量不同的user-agent数据,用来编辑访问请求的请求头信息,模仿后期的浏览器浏览
url='https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0'
#豆瓣电影区,根据热门标签选电影的url
broser=webdriver.Chrome()
broser.get(url)
n=14 #每一次Ajax渲染出来20部电影信息,n是20次Ajax渲染,爬取电影数量为20*n
for i in range(n):
wait=WebDriverWait(broser,20)
button=wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'more')))
button.click()
time.sleep(1)
movie_photo=[item.get_attribute('src') for item in broser.find_elements_by_xpath('//div[@class="cover-wp"]/img')]
movie_url=[item.get_attribute('href') for item in broser.find_elements_by_class_name('item')]
broser.close()
通过selenium作n次Ajax渲染后,爬取页面源代码中电影的图片、url,并关闭浏览器,后续再对爬取到的信息过滤采集。
'''存储爬取电影图片可选'''
# for i in range(len(movie_photo)):
# open('MoviePhoto\\'+str(i)+'.jpg','wb').write( requests.get(movie_photo[i],headers=headers).content )
output=[] #用以整合所有类别的数据的列表
for i in range(len(movie_url)):
useragent = U[random.randint(0, len(U)-1)].strip()
#调用所有存储的user-agent头信息,加强每次访问电影地址时候的爬虫生命力
headers = {
# 设置请求头,如需建造更严谨、更安全的爬虫,可以设置多个User-Agent信息以便循环调用。
'User-Agent': useragent
}
response=requests.get(movie_url[i],headers=headers)
html=etree.HTML(response.text) #将网页返回信息存储成html格式,允许xpath方法分析
name=html.xpath('//span[@property="v:itemreviewed"]/text()')#电影名
director=html.xpath('//a[@rel="v:directedBy"]/text()')#导演
#playwright=html.xpath('//span[@class="pl",contains(text(),"编剧")]//text()')
actor=html.xpath('//span[@class="actor"]/span[@class="attrs"]//text()')#演员
movie_class=html.xpath('//span[@property="v:genre"]//text()')#电影分类
contry=re.compile('制片国家/地区:(.*?)
').findall(response.text)#制片国家\地区
releasedate=html.xpath('//span[@property="v:initialReleaseDate"]/@content')#上映日期
runtime=html.xpath('//span[@property="v:runtime"]/@content')#片长
grade=html.xpath('//strong[@class="ll rating_num"]/text()')#电影评分
try: #整合一部电影的所有信息
data=name+grade+[movie_class[0]]+[director[0]]+[actor[0]]+contry+[releasedate[0]]+runtime
print(data) #便于运行程序时观察爬取的信息,便于后期修改
output.append(data) #整合入最终的输出列表
except:
continue
movie_data=pd.DataFrame(output,columns=['电影名','豆瓣分数','类别','导演','演员','制片国家/地区','上映日期','片长'])
movie_data.to_csv('Douban_Movie.csv')
#导出至目录下的Douban_Movie.csv文件
import pandas as pd
import numpy as np
import datetime
from matplotlib import pyplot as plt
movie=pd.read_csv('Douban_Movie.csv')
del movie['Unnamed: 0'] #删除第一列无意义列,是导出csv时的索引列
movie['片长']=movie['片长'].dropna() #小部分电影唔片长信息
'''绘制电影片长分布图'''
plt.hist(movie['片长'],bins=np.arange(60,190,10))
plt.title('Histogram : The length of films')
plt.tight_layout()
plt.xlabel('The length of a film')
plt.ylabel('Numbers of films')
plt.show()
'''对数据集的 “上映日期” 列进行数据清洗,除去上映地点信息'''
def rebuild(x):
x=x[:10]
if '(' in x:
start=x.index('(')
x=x[:start]
return x
movie['上映日期']=movie['上映日期'].apply(rebuild)
movie['上映日期']=pd.to_datetime(movie['上映日期']) #修改类型datetime64[ns]
movie=movie.set_index('上映日期') #将上映日期设置为索引
movie=movie.sort_index(ascending=False)
'''绘制不同制片国家\地区电影的平均分数'''
fig3=movie[['制片国家/地区','豆瓣分数']].groupby(by=movie['制片国家/地区']).mean()
#print(fig3)
# plt.hist(fig3.index) #需要画出直方图,需要修正中文字体显示
# plt.xlabel('moviemaking country/district')
# plt.ylabel('Mean grade')
# plt.title('Histogram : films mean grade in different moviemaking country/district')
# plt.show()
此处尚未解决中文作图的报错,所以暂时缺图
print(fig3.describe())
count 58.000000
mean 6.740270
std 0.938747
min 3.600000
25% 6.300000
50% 6.687500
75% 7.375000
max 9.100000
'''绘制近年不同月份下上映电影的平均分'''
# mean_grade_month=movie.resample('MS').mean() # 绘制近年不同月份上映电影的平均分数
# plt.plot(mean_grade_month['豆瓣分数'])
# plt.xlabel('Year-Month')
# plt.ylabel('Mean Grade')
# plt.title('The mean grade of films in recent years')
# plt.show()
print(movie[movie['豆瓣分数']>8].count())
豆瓣分数大于8分的电影数为22部,热门标签下爬取的电影总数为254部,占比8.67%。
作为数据分析初学者,我会尽我所能尝试分析,【此篇文章的所有分析观点都仅代表文章原创者的现时观点,如有观点不同,欢迎评论,我也很愿意接受不同角度的分析观点。】
1、相比于以前电影片长集中在100分钟内,如今电影的发行,片长都集中在100分钟至200分钟区段,叙事时间的延长利于讲好、讲深每个故事,更加能够满足观影者对电影全景的展示的需求,也更能让故事的观点升华到更高的深度,触动观影者。
2、根据获取的不同制片国家\地区的电影平均分,发现电影工业发展也同样趋于全球化,多方合作制作电影是未来的大趋势,将各方的优势集中融合,能提升电影的视觉效果和叙事能力。各制片国家\地区的电影平均分在6.740270,分数集中在6.30~7.38区间,热门标签采集的电影数据下,最大评分9.1。高分电影还是占少数,只有8.67%。
3、根据热门标签下爬取的电影信息,发现电影平均分高的上映日期集中在年末年初。
【由于采集样本的数量还是很少,本文章分析的观点仍是很片面的,不是成熟的、专业的数据分析】
因为该文章只是初试数据分析,也是初始检验这个小项目成果的试验品,后期会重新整理修改爬取电影的数目,再从更多方面、角度来分析电影工业的发展状况。