本文主要是爬取猫眼电影TOP100的电影数据,并且进行了跨页爬虫,获取的字段:电影名,主演,上映时间,评分,电影类型和时长。最后保存在csv文件中。然后对爬取的数据进行可视化和数据分析。
如果有什么不足之处,欢迎大家进行评论,我也会进行改正!
获取想要的数据是我们进行数据分析的第一步,也是最重要的一步。爬取数据主要分为分析网页、获取数据网页信息、数据存储等几步。
下面博主将会对猫眼电影TOP100的电影数据进行分析爬取。
在定义爬虫程序的时候,因为有些网页会有反爬虫的设置,所以在爬虫程序运行过程中会出现问题,因此在爬虫程序中需要添加一个头部 headers 信息,模拟成浏览器访问网页的形式,headers 头部信息中包含 User-Agent 以及 Cookies 等信息。
User-Agent 可以用来判断是否是浏览器发起的 Request,是一个特殊的字符串头,可以识别客户使用的操作系统及浏览器版本等信息。对于 User-Agent 的设置方法有两种,一是自定义 User-Agent 的数组,然后使用 random 的方式随机调用 User-Agent 数组;二是使用 Python 的第三方类库 fake-useragent,它里面提供了很多的 User-Agent,使用时只需要只需要导入第三方库,然后通过 UserAgent().random 获取即可,不用担心重复的问题。使用 fake_useragent 类库首先需要在命令行通过 pip 提前安装该类库然后进行使用。Cookies 是某些网站为了进行 session 跟踪、辨别用户身份而储存在用户本地终端上的数据,通过使用 requests.session()得到 Cookies 信息。
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
res = requests.get(url,headers=headers)
html = etree.HTML(res.text)
爬取网页的URL为:https://maoyan.com/board/4?
首先要在浏览器中打开网页,并且观察网页信息:
大家可以看到,在该排行榜中,每页显示十个电影的数据信息,100个电影分为十页进行显示,要爬取TOP100排行榜上的全部电影信息,需要10个网址链接,分别为:
https://maoyan.com/board/4?offset=0
https://maoyan.com/board/4?offset=10
https://maoyan.com/board/4?offset=20
https://maoyan.com/board/4?offset=30
https://maoyan.com/board/4?offset=40
https://maoyan.com/board/4?offset=50
https://maoyan.com/board/4?offset=6
https://maoyan.com/board/4?offset=70
https://maoyan.com/board/4?offset=80
https://maoyan.com/board/4?offset=90
由这十个网页大家可以发现每页网址的前面部分都是一样的,只有offset=的数字不一样,但是其实是有规律的,即每页网址最后的数字是递增的(前一个数据+10就是后一个数字),每次请求中都有10条数据。
想要访问多条网址链接,就需将URL中的offset=?进行变化,对网页网址链接进行获取跳转的代码如下所示:
urls = ['http://maoyan.com/board/4?offset={}'.format(str(i)) for i in range(0, 100, 10)]
for url in urls:
get_url(url)
在当前网页中,我们需要获取的数据信息是电影名,主演,上映时间,评分。
获取网页中的数据信息,我们就要分析网页的源代码,在浏览器中把要访问的网页打开,然后按下键盘上的F12,就可以查看网页的源代码;也可以单击鼠标右键,然后点击审查元素查看网页源代码。
该网页的源代码如下图所示:
由这两张图片我们可以看到,猫眼电影TOP100中的电影数据信息在网页源代码中的标签是相同的,故在爬取时使用一个for循环即可对全部电影的数据信息进行爬取。
博主在爬取数据时,采用的是xpath方法获取电影数据数据信息,代码如下所示:
def get_url(url):
res = requests.get(url,headers=headers)
html = etree.HTML(res.text)
infos = html.xpath('//dl[@class="board-wrapper"]/dd')
for info in infos:
name = info.xpath('div/div/div[1]/p[1]/a/text()')[0]
info_url = 'http://maoyan.com' + info.xpath('div/div/div[1]/p[1]/a/@href')[0]
star = info.xpath('div/div/div[1]/p[2]/text()')[0].strip()
release_time = info.xpath('div/div/div[1]/p[3]/text()')[0].strip()
score_1 = info.xpath('div/div/div[2]/p/i[1]/text()')[0]
score_2 = info.xpath('div/div/div[2]/p/i[2]/text()')[0]
score = score_1 + score_2
get_info(info_url,name,star,release_time,score)
在二级网页中,我们需要获取的数据信息是电影类型和时长。
首先,我们先看网页源代码,如下所示:
由这两张图片我们可以看到,猫眼电影TOP100二级信息中的电影数据信息在网页源代码中的标签也是相同的,故在爬取时同样使用一个for循环对全部电影的二级数据信息进行爬取。
博主在爬取二级数据时,同样采用的是xpath方法获取电影数据数据信息,上代码:
def get_info(url,name,star,time,score):
res = requests.get(url, headers=headers)
html = etree.HTML(res.text)
style = html.xpath('/html/body/div[3]/div/div[2]/div[1]/ul/li[1]/text()')[0]
long_time = html.xpath('/html/body/div[3]/div/div[2]/div[1]/ul/li[2]/text()')[0].split('/')[1].strip()
print(name,star,time,score,style,long_time)
writer.writerow([name,star,time,score,style,long_time])
注意:在获取二级信息之后,需要将一级信息同二级信息一起写入CSV文件中。
本文将数据信息存储到了CSV文件中。
将信息存储到CSV文件的代码如下所示(CSV文件中存储的是解析网页代码得到的数据信息):
def write_dictionary_to_csv(dict,filename):
file_name='{}.csv'.format(filename)
with open(file_name, 'a',encoding='utf-8') as f:
file_exists = os.path.isfile(filename)
w =csv.DictWriter(f, dict.keys(),delimiter=',', quotechar='"', lineterminator='\n',quoting=csv.QUOTE_ALL, skipinitialspace=True)
if not file_exists :
w.writeheader()
w.writerow(dict)
print('当前行写入csv成功!')
本文中,博主并未使用该方式进行存储信息,博主的方法如下:
fp = open('maoyan_2.csv','w',encoding='utf-8',newline='')
writer = csv.writer(fp)
writer.writerow(['name','star','time','score','style','long_time'])
import requests
from lxml import etree
import csv
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
def get_url(url):
res = requests.get(url,headers=headers)
html = etree.HTML(res.text)
infos = html.xpath('//dl[@class="board-wrapper"]/dd')
for info in infos:
name = info.xpath('div/div/div[1]/p[1]/a/text()')[0]
info_url = 'http://maoyan.com' + info.xpath('div/div/div[1]/p[1]/a/@href')[0]
star = info.xpath('div/div/div[1]/p[2]/text()')[0].strip()
release_time = info.xpath('div/div/div[1]/p[3]/text()')[0].strip()
score_1 = info.xpath('div/div/div[2]/p/i[1]/text()')[0]
score_2 = info.xpath('div/div/div[2]/p/i[2]/text()')[0]
score = score_1 + score_2
# print(name,star,release_time,score,info_url)
get_info(info_url,name,star,release_time,score)
def get_info(url,name,star,time,score):
res = requests.get(url, headers=headers)
html = etree.HTML(res.text)
style = html.xpath('/html/body/div[3]/div/div[2]/div[1]/ul/li[1]/text()')[0]
long_time = html.xpath('/html/body/div[3]/div/div[2]/div[1]/ul/li[2]/text()')[0].split('/')[1].strip()
print(name,star,time,score,style,long_time)
writer.writerow([name,star,time,score,style,long_time])
if __name__ == '__main__':
fp = open('maoyan_2.csv','w',encoding='utf-8',newline='')
writer = csv.writer(fp)
writer.writerow(['name','star','time','score','style','long_time'])
urls = ['http://maoyan.com/board/4?offset={}'.format(str(i)) for i in range(0, 100, 10)]
for url in urls:
get_url(url)
CSV截图:
因为要进行数据分析,所以博主将CSV文件进行了一些修改,修改后的CSV文件如下:
本文使用jupyter进行数据分析。
首先,我们来看看采用jupyter读取的CSV文件中的数据:
import pandas as pd
import random
data=pd.read_csv(r'C:\Users\ASUS\Desktop\Python实训\maoyan_2.csv')
data
import pandas as pd
import numpy as np
data=pd.read_csv(r'C:\Users\ASUS\Desktop\Python实训\maoyan_2.csv')
data.info()
由此可见,本次分析的CSV文件中有8列,100行数据信息,并且没有空值。
查看CSV文件中的数据信息是否有重复的值:
data.duplicated().value_counts()
CSV文件里存储的演员和简介主要是电影的主演演员和电影的简介,这两列对本文的数据可视化分析是无意义的,故我们可以把这两列删除,然后对其他存储信息进行数据分析。
本文使用drop()方法对数据进行删除,删除之后剩下电影名,上映时间,评分,电影类型和时长这五列数据信息,删除代码如下:
data=data.drop(columns=["演员","简介"])
data
1、
data.plot.scatter(x='year',y='rate')
观察该散点图可知,在猫眼TOP100排行榜中的100部电影中,1990-2020年期间的电影发布数量较多,但评分比较散乱;1940-1980年其间在猫眼TOP100排行榜上的有5部电影,其中3部评分在9分以上,2部在9分以下。总的来看,大部分电影还是在9分左右。
2、
下面这两个图是评分和上映年份的趋势图:
import matplotlib.pylab as plt
data['评分'].plot()
plt.xlabel('count')
plt.ylabel('score')
import matplotlib.pylab as plt
data['上映年份'].plot()
plt.xlabel('count')
plt.ylabel('year')
3、
(1)统计所有电影出现的评分的情况,并且统计这些情况出现的次数。
data1=data.drop_duplicates(subset=['评分'])
d=pd.DataFrame(data1['评分'],columns=['评分'])
d['count']=[len(data[data['评分']==8]),len(data[data['评分']==8.1]),
len(data[data['评分']==8.2]),len(data[data['评分']==8.3]),
len(data[data['评分']==8.4]),len(data[data['评分']==8.5]),
len(data[data['评分']==8.6]),len(data[data['评分']==8.7]),
len(data[data['评分']==8.8]),len(data[data['评分']==8.9]),
len(data[data['评分']==9]),len(data[data['评分']==9.1]),
len(data[data['评分']==9.2]),len(data[data['评分']==9.3]),
len(data[data['评分']==9.4]),len(data[data['评分']==9.5]),
len(data[data['评分']==9.6]),len(data[data['评分']==9.7])]
d
plt.figure(figsize=(6,6))
label=d['评分'].values.tolist()
explode=[0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01]
plt.pie(x=d['count'].values.tolist(),explode=explode,labels=label,autopct='%1.1f%%')
plt.title('Score')
plt.show()
plt.rcParams['figure.figsize']=[13,8]#这是这个表的大小
lable=d['评分'].values.tolist()#刻度标签
plt.bar(range(18),d['count'].values.tolist(),width=0.5)#18根柱子,对应值,宽度
#下面两个是x轴,y轴的表是的是啥
plt.ylabel('count',fontsize=15)
plt.xlabel("score",fontsize=15)
#每一个柱子代表的城市
plt.xticks(range(18),lable)
plt.title('100 movie Score')
plt.show()
由饼状图和柱状图可知,电影评分为9.2的电影居多,而评分为9.1、9.8、8.5的电影数量占有百分之三十,而其他评分的电影就比较少了。
4、
(1)统计所有电影出现的上映年份的情况,并且统计这些情况出现的次数。
df=data.drop_duplicates(subset=['上映年份'])
d1=pd.DataFrame(df['上映年份'],columns=['上映年份'])
d1['count']=[len(data[data['上映年份']==1939]),len(data[data['上映年份']==1953]),
len(data[data['上映年份']==1957]),len(data[data['上映年份']==1975]),
len(data[data['上映年份']==1987]),len(data[data['上映年份']==1988]),
len(data[data['上映年份']==1989]),len(data[data['上映年份']==1990]),
len(data[data['上映年份']==1992]),len(data[data['上映年份']==1993]),
len(data[data['上映年份']==1994]),len(data[data['上映年份']==1995]),
len(data[data['上映年份']==1997]),len(data[data['上映年份']==1998]),
len(data[data['上映年份']==1999]),len(data[data['上映年份']==2000]),
len(data[data['上映年份']==2001]),len(data[data['上映年份']==2003]),
len(data[data['上映年份']==2004]),len(data[data['上映年份']==2005]),
len(data[data['上映年份']==2006]),len(data[data['上映年份']==2008]),
len(data[data['上映年份']==2009]),len(data[data['上映年份']==2010]),
len(data[data['上映年份']==2011]),len(data[data['上映年份']==2012]),
len(data[data['上映年份']==2013]),len(data[data['上映年份']==2014]),
len(data[data['上映年份']==2015]),len(data[data['上映年份']==2016]),
len(data[data['上映年份']==2017]),len(data[data['上映年份']==2018]),
len(data[data['上映年份']==2019]),len(data[data['上映年份']==2020])]
d1
y=data['上映年份'].value_counts()
y.columns=['year','count']
plt.figure(figsize=(15,6.5))
y.sort_index().plot(kind='bar')
同一部电影的类型也可能会有多个类型,下面博主将本次CSV中的电影类型进行查看和总和。
all_type = df['类型'].str.split('、').apply(pd.Series)
all_type.head(67)
从这个图中我们可以看到:有些电影有一种类型,而有些电影有2-4种类型。该图片中有很多空值,我们可以将这些空值用“0”进行替换,然后再将这些类型进行计数和总和。
下面就是将空值替换,然后汇总的代码和数据显示:
all_type = df['类型'].str.split('、').apply(pd.Series)
all_type = all_type.apply(pd.value_counts).fillna('0')
all_type.columns = ['tpye1','type2','type3','type4']
all_type['tpye1'] = all_type['tpye1'].astype(int)
all_type['type2'] = all_type['type2'].astype(int)
all_type['type3'] = all_type['type3'].astype(int)
all_type['type4'] = all_type['type4'].astype(int)
all_type.head(67)
all_type['all_counts'] = all_type['tpye1']+all_type['type2']+all_type['type3']+all_type['type4']
all_type = all_type.sort_values(['all_counts'],ascending=False)
all_type.head(67)
type_rank = pd.DataFrame({
'counts':all_type['all_counts']})
type_rank
type_rank.sort_values(by='counts',ascending=False).plot(kind='bar',figsize=(14,6))
由此图可见,猫眼TOP100排行榜中的,几乎8百分之八十的电影都包含剧情这一种类型;其次大家比较爱看的是冒险、喜剧、爱情、动作这些类型的电影;而西部、灾难、古装、歌舞这些类型电影在排行榜上就比较少,几乎没有。
同一部电影的可能由多个国家联合制作,下面博主将本次CSV中的电影制作国家进行查看和总和。
all_country = df['国家'].str.split('、').apply(pd.Series)
all_country.head(67)
从这个图中我们可以看到:有些电影有一个国家制作,而有些电影有2-4个国家制作。并且该图片中有很多空值,我们可以将这些空值用“0”进行替换,然后再将这些类型进行计数和总和。
下面就是将空值替换,然后汇总的代码和数据显示:
all_country = df['国家'].str.split('、').apply(pd.Series)
all_country = all_country.apply(pd.value_counts).fillna('0')
all_country.columns = ['area1','area2','area3','area4']
all_country['area1'] = all_country['area1'].astype(int)
all_country['area2'] = all_country['area2'].astype(int)
all_country['area3'] = all_country['area3'].astype(int)
all_country['area4'] = all_country['area4'].astype(int)
all_country['all_counts'] = all_country['area1']+all_country['area2']+all_country['area3']+all_country['area4']
all_country.sort_values(['all_counts'],ascending=False)
all_country
我们将这些制作国家情况生成一个柱状图来观察一下:
由此图可见,猫眼TOP100排行榜中的,几乎8百分之八十的电影都由美国制作,可见美国在电影制作方面还是很厉害的啊;其次是英国、中国、意大利、德国、法国这些国家;而西班牙、黎巴嫩、阿根廷、比利时这些国家制作电影在排行榜上就比较少,几乎没有。
以上就是博主本次的总结。由于数据量太小,所以做的分析并不是很全面。如果有什么不足之处,欢迎大家进行评论,我也会进行改正!
欢迎大家一起探讨啊!如果有喜欢的,希望能给我点个赞,谢谢大家了!