作者:风雨无组所有成员 (^▽^)

来自南京审计大学

前言:

本文全程记录“数据采集技术”这门课的一份小组作业的实现过程,包括选题,数据爬取与数据分析,这是所有“风雨无组”小组成员的努力成果(*^▽^*)

一.选题背景及意义

  • 1.1背景:

            随着经济和科技的日益发展,给人们的物质生活带来了极大的变化的同时也使人们对精神方面的消费需求愈发提高。电影产业作为文化产业的核心组成部分,已成为人们生活中不可或缺的一种娱乐方式,不仅仅是对文化领域有着重要的影响,更成为促进经济发展的强大动力。在计算机网络覆盖全球的今天,文化与经济两大主体早就脱离了互不干涉、没有交集的情况,而文化产业也正在逐渐发展成为影响世界经济发展的重要部分。在短短一百多年的时间里,电影产业不断地发展壮大,现在它早就凭借着其特殊的魅力和巨大的吸引力成为推动国民经济迅速增长的产业之一。中国自从改革开放以来一直始终坚持与世界接轨,紧跟世界发展潮流,在改革中打破原有的经济体制并成功研究出符合中国的特殊国情的社会主义市场经济体制,这也是我国的电影产业随之开始向市场化转变最重要的政治基础。我国影视行业发展迅速,成为全球第二大电影市场,同时也是增长最快的市场之一。据中国新闻出版广电总局调查显示,2017年全国电影总票房已经超过550亿,这说明中国电影产业有着良好的发展前景。

  • 1.2前言:

            研究中国电影的现状和存在的问题,有利于分析出我国电影产业发展的优势与劣势,找出其他国家电影发展有利方法加以借鉴从而推动电影产业的快速发展,最为重要的是有利于抵御外来电影大片的带来的文化和经济冲击,有利于中华传统文化的传承与延续和社会经济的发展。而票房反映了一部电影的商业效益,对后续电影拍摄计划和方向有着重大影响,也是衡量一部电影是否盈利与是否成功的重要指标。然而,国产电影只有极少数是盈利的,70%的国产电影都面临亏损,高投入低票房低收益的电影案例也屡见不鲜,如2016年上映的《封神传奇》斥资5亿,却只收获2.84亿的票房。因此,对电影票房的有效分析将有利于降低电影投资市场的风险,对电影投资、制作及营销各个阶段都有着重要的指导性意义。而目前国内电影票房的研究还处在经验分析阶段,依赖于专家判断,缺乏数据技术支撑。为引导电影产业的理性决策,对电影票房的数据分析显得尤为必要。

# 二.获取目标数据 ## 2.1:目标网站分析 ### 2.1.1:获取来源

        小组将主要从猫眼电影(https://www.maoyan.com)获取数据。猫眼电影是美团旗下的一家集媒体内容、在线购票、用户互动社交、电影衍生品销售等服务的一站式电影互联网平台。2015年6月,猫眼电影覆盖影院超过4000家,这些影院的票房贡献占比超过90%。猫眼占网络购票70%的市场份额,每三张电影票就有一张出自猫眼电影,是影迷下载量较多、使用率较高的电影应用软件。同时,猫眼电影为合作影院和电影制片发行方提供覆盖海量电影消费者的精准营销方案,助力影片票房。2015年上半年,猫眼电影交易额达60亿,超过2014年全年。

### 2.1.2:目标数据

小组将爬取豆瓣近五年来每年评分排名前90的电影,并爬取这些电影的名字、类型、评论等相关数据。

  • 时间跨度:

            小组爬取豆瓣近五年来的数据,充分考虑到了时代变化的因素,可以跳脱出获取数据时的静态局限,进一步反映出观众对电影的偏好的动态变化,从而可以帮助预测未来电影行业的趋势、发展。

  • 评分:

            电影的评分往往与电影的质量、观众的喜爱程度有着密不可分的正相关的关系,对电影评分排名的爬取可以从宏观上帮助小组初步筛选出更符合观众观影偏好的高质量电影。

  • 类型:

            电影的受喜爱程度是否和它所属类型有关?观众喜爱的电影类型是否正在发生变化?对哪种的投资拍摄更容易吸引到更多观众?对电影类型的爬取可以帮助小组探索这个问题的答案。

  • 评论:

            电影的评论可以直观、详细、真实地反映观众对于电影的评价。这些评论中往往会反复出现一些关于这些电影的关键词,精准地找出这些关键词可以帮助小组进一步细化、筛选出电影中影响观众喜爱程度的因素。

### 2.1.3:网页源码分析

        我们首先进入猫眼官网,根据我们的数据获取要求,我们进入如下界面:

        这时,我们右击检查,开始定位我们需要的数据类型,我们发现在一级页面中,网页源码中只包含了电影名称、评分,他们的位置路径如下图:

        紧接着,我们发现我们剩下的数据,例如:类型、评论等,在二级页面,我们仔细观察后,在如下位置发现了可以用于拼接二级页面的规则编号,位置如下:

        到此为止,我们已经完成了对网页源码的分析,接下来,就要进入代码实现阶段啦(*^▽^*)

## 2.2:Python爬虫代码实现 ### 2.2.1:Python库准备

        在本次实现中,我们用到了如下几个库:

  • urllib:

            它是 Python 内置的 HTTP 请求库,也就是说我们不需要额外安装即可使用,它包含四个模块:

    • 第一个模块 request,它是最基本的 HTTP 请求模块,我们可以用它来模拟发送一请求,就像在浏览器里输入网址然后敲击回车一样,只需要给库方法传入 URL 还有额外的参数,就可以模拟实现这个过程了。
    • 第二个 error 模块即异常处理模块,如果出现请求错误,我们可以捕获这些异常,然后进行重试或其他操作保证程序不会意外终止。
    • 第三个 parse 模块是一个工具模块,提供了许多 URL 处理方法,比如拆分、解析、合并等等的方法。
    • 第四个模块是 robotparser,主要是用来识别网站的 robots.txt 文件,然后判断哪些网站可以爬,哪些网站不可以爬的,其实用的比较少。。
  • lxml:

            lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高。

  • xlwt:

            可以实现对excle的读写

### 2.2.2:Python代码实现

注释中包含了url规律分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#2022
#https://www.maoyan.com/films?yearId=17&showType=3&sortId=3
#https://www.maoyan.com/films?yearId=17&showType=3&sortId=3&offset=30
#https://www.maoyan.com/films?yearId=17&showType=3&sortId=3&offset=60
#https://www.maoyan.com/films?yearId=17&showType=3&sortId=3&offset=90
#2021
#https://www.maoyan.com/films?yearId=16&showType=3&sortId=3
#https://www.maoyan.com/films?yearId=16&showType=3&sortId=3&offset=30
#https://www.maoyan.com/films?yearId=16&showType=3&sortId=3&offset=60
#https://www.maoyan.com/films?yearId=16&showType=3&sortId=3&offset=90

#url规律为:
#基础url=https://www.maoyan.com/films? 加上yearID=年份-2005 加上showType=3&sortId=3&offset=(页码-1)*30

#//*[@id="app"]/div/div[2]/div[2]/dl//dd//div[1]/a/@href 二级页面的url


from lxml import etree
import urllib.parse
import urllib.request
import xlwt


def creat_request(page,year):
#定制url,方便循环
if page == 1:
url = 'https://www.maoyan.com/films?yearId='+str(year-2005)+'&showType=3&sortId=3'
else:
url = 'https://www.maoyan.com/films?yearId='+str(year-2005)+'&showType=3&sortId=3'+'&offset='+str((page-1)*30)

headers = {
'Cookie': 'uuid_n_v=v1; uuid=9A24E0F0631311EDBF6151208720BA007113D57EEFF04C3CA640F73319AF072A; _csrf=4d7ff24790b2c392970278265e244e3534b30e30b8da2dfd29d8c4a819f05503; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1668317137; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; _lxsdk_cuid=1846f734a21c8-01b03943f3297b-26021f51-190140-1846f734a21c8; _lxsdk=9A24E0F0631311EDBF6151208720BA007113D57EEFF04C3CA640F73319AF072A; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1668321628; __mta=148124936.1668317137787.1668321468086.1668321627622.19; _lxsdk_s=1846fb47f87-f6f-621-be8%7C%7C5',

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
}

request = urllib.request.Request(url=url,headers=headers)

return request


def get_content(request):
response = urllib.request.urlopen(request)
#用于检查报错
a = response.getcode() #返回状态码 200则逻辑无误

content = response.read().decode('utf-8')

return content



def name_list(content):

tree = etree.HTML(content)
#Xpath解析源码
jieguo1 = tree.xpath('//*[@id="app"]/div/div[2]/div[2]/dl//dd/div[2]/@title')

return jieguo1

def score_list(content):

tree = etree.HTML(content)

score = tree.xpath('//*[@id="app"]/div/div[2]/div[2]/dl//dd/div[3]//i/text()')

score_1 = score[::2]

score_2 = score[1::2]

jieguo2 = [p + q for p,q in zip(score_1,score_2) ]

return jieguo2

def url2_list(content1):

tree = etree.HTML(content1)

url_list = tree.xpath('//*[@id="app"]/div/div[2]/div[2]/dl//dd//div[1]/a/@href')
#拼接二级页面的url,为访问二级页面做准备
url3 = ['https://www.maoyan.com'+ str(url2) for url2 in url_list]


return url3

def save_outcome(name,score,url3,year,page):

f = xlwt.Workbook('encoding = utf-8') #设置工作簿编码

sheet1 = f.add_sheet('1') #创建sheet工作表

for i in range(30):

sheet1.write(i,0,name[i]) #写入数据参数对应 行, 列, 值

sheet1.write(i,1,score[i])

sheet1.write(i,2,url3[i])

f.save(str(year)+'-'+str(page)+'.xls')#保存.xls到当前工作目录



#程序的入口
if __name__ == '__main__':
start_page = int(input('请输入起始的页码'))
end_page = int(input('请输入结束的页码'))
year = int(input('请输入你要爬取的年份'))

for page in range(start_page,end_page+1):#range函数左闭右开
# 每一页都有自己的请求对象的定制
request = creat_request(page,year)

# 获取响应数据
content1 = get_content(request)

name = name_list(content1)

score = score_list(content1)

url3 = url2_list(content1)

#下载,写入excle
save_outcome(name,score,url3,year,page)

#用于检查程序是否运行正常,若打印[],这说明ip被暂时封禁,无法获取源码
print(name)
print(score)
print(url3)


        结果实现如下,仅展示一张表格

2.2.2.1:Python代码实现出现的问题

        在上面的代码结果中,可以看到,我们已经批量获取了2022年评分最高的前30部电影的名字、评分及详细情况的二级页面url。我们想要的评论、类型等数据都存储在二级页面之中,就像这样:

        本来我的想法已经形成了,既然我们已经获取了二级页面的url,我们可以再写一个函数,用来遍历每一个url,提取信息。想法很简单,但是由于猫眼反爬十分严格,问题频出,包括但不限于:

  • 如此频繁的访问页面会导致网站识别,被反爬,表现的具体形式即为:返回[]
  • 二级页面的数据不在页面源码中,为异步加载,我们在审查是可以定位到,但是获取源码会发现不在源码中,而在审查-网络中可以发现这个文件,如下:

    该页面的url不具有规律,我们无法进行批量访问

  • 了解到这个问题后,我更换了selenium库进行自动化操作,但是猫眼反爬比较严格,当识别到请求者为selenium后,会拒绝访问
  • 利用selenium_Phantomjs进行页面截图,也被识别如下:

  • 我尝试了undetected-chromedriver等新的驱动,目前还未成功,所以目前的方案是手动打开批量获取的二级页面进行信息获取。

注:在日后的学习过程中会继续研究这个问题,比如利用猫眼移动端的url进行爬取,如若可以成功,将会更新在这里。

# 三.数据分析

我们通过爬虫程序搜集了近五年豆瓣电影top90榜的相关资料,如电影名称、上映地区及时间、票房与评分等,并应用数据分析工具制作了以下相关图表。

1.评分

上表是我们对搜集得来的450条评分数据进行分析所得。由表可知,评分的平均值在8.851,是一个较高的数值,且评分的方差仅有0.187——数据的波动性小,说明近五年豆瓣top前90的电影得到了大多数观众的一致好评。

除此以外,我们还做了有关评分的散点图与箱型图:

散点图与箱型图更直观地反映了观众们评分分数的集中区间,由两图可见,观众们的评分分数集中在8.5到9.5之间,少数处于7到8.5之间,也再次说明大多数观众对近五年豆瓣top前90的电影给出了一致好评。

2.指标相关性

上表是我们针对已搜集的有关“评分数”、“票房”、“评分”、“时长”这四大指标的数据进行相关性分析所得。由表可知,“评分数”与“票房”这两个指标的相关系数高达0.951,说明两者的相关性极强,即通常票房高的电影,评分数也多,反之亦然。另外,表中各指标的相关系数不存在负值,说明各指标间不存在一方制约另一方的情况。

3.地区票房统计

上图是我们对各地区票房数据进行分析所得。由此饼状图可见,在中国香港上映的电影的票房量最多,近乎占据所有票房量的一半,其次是在中国大陆上映的电影,其票房量也占总体的一大部分。但在中国香港、中国大陆、日本、美国以外的地区上映的电影的票房量很少,仅占总体的极小部分,可能因为这些地区的人口较少,或是人们的偏好所致。

下图以不同的色彩展示了在世界各区域内上映的电影的票房量的差异:

4.电影放映的月份差异

我们对各月份影院电影的放映数进行了数据分析,得到了以上折线图。有图可见,在每年的十二月份,电影的放映数达到峰值,可能与圣诞等一系列节日有关。在三到六月份,电影的放映数整体偏少,可能因为这是各年龄学生们上学的时期。七到九月份的电影放映数整体偏多,可能因为这是各年龄学生们放暑假的时期,在此时期学生们有时间观影。影院可根据此状况,增加在七到九月份上映的电影数量。

另外还有各月份票房数的饼状图:

可见十月份的电影票房量占整体比重最大,甚至超过整体的半数,究其原因,可能与国庆等节日有关。九月份的电影票房量占比也较多,其余各月份的票房量占比均较小。所以推荐影院在十月或九月多上映电影。

各类型电影票房差异

上图是我们对各类型电影的票房量进行数据分析所得。由此饼状图可见,悬疑/动作/犯罪类型的电影最受观众们欢迎,其票房量近乎占总体的一半,其次是剧情/爱情类型的电影。其余各类型的电影的票房占比均较小。所以推荐影院多上映悬疑/动作/犯罪与剧情/爱情类型的电影。