Python爬取豆瓣电影信息并分析

一、摘要

      该数据来自豆瓣,本选题应用Python网络爬虫方法。

二、选题背景:

  为一些片荒的影迷快速找出高分优质电影,省去寻找电影或观看劣质爆米花电影的时间

三、过程及代码:

1.爬取豆瓣高分电影

 1 import re
 2 import requests
 3 from bs4 import BeautifulSoup
 4 import pandas as pd
 5 def get_movies(link):
 6     headers = {  # 这是请求头
 7         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
 8                       'Chrome/83.0.4103.116 Safari/537.36 '
 9 
10     }
11     movie_names=[]
12     movie_types=[]
13     movie_dis=[]
14     movie_grade=[]
15     movie_addr=[]
16     movie_actor=[]
17     movie_director=[]
18     movie_year=[]
19     r=requests.get(link,headers=headers,timeout=10)
20     soup=BeautifulSoup(r.text,"lxml")
21     
22     for each in soup.find_all('div',class_='abstract'):
23         a=each.text
24         #.匹配任意字符,除了换行符
25         tp = re.search(r'类型: (.*)',a)
26         if tp==None:
27             movie_types.append(" ")
28         else:
29             movie_types.append(tp.group(1))
30         actor = re.search(r'主演: (.*)',a)
31         if actor==None:
32             movie_actor.append(" ")
33         else:
34             movie_actor.append(actor.group(1))
35         director = re.search(r'导演: (.*)',a)
36         if director==None:
37             movie_director.append(" ")
38         else:
39             movie_director.append(director.group(1))
40         addr = re.search(r'制片国家/地区: (.*)',a)
41         if addr==None:
42             movie_addr.append(" ")
43         else:
44             movie_addr.append(addr.group(1))
45         year=re.search(r'年份: (.*)',a)
46         if year==None:
47             movie_year.append(" ")
48         else:
49             year_str=year.group(1)
50             sj=int(year_str[:2])+1
51             nd=year_str[2]+'0'
52             movie_year.append(str(sj)+'世纪'+nd+'年代')
53     #查询所有class=title的div
54     div_list=soup.find_all('div',class_='title')
55     for each in div_list:
56         movie_name=each.a.text.strip() # 在div中,a标签的text的内容就是中文电影名称
57         movie_names.append(movie_name)
58     for each in soup.find_all('div',class_='rating'):
59         a=each.text.split('\n') #在div中,第三个span的text的内容就是评价人数
60         #获取字符串中的数字
61         x=re.sub("\D","",a[3])
62         movie_dis.append(int(x))
63         movie_grade.append(float(a[2]))
64     return movie_names,movie_types,movie_dis,movie_grade,movie_addr,movie_actor,movie_director,movie_year

用for 循环读取每页的数据并写入dataframe

1 movies=get_movies("https://www.douban.com/doulist/240962/")
2 movies_1=pd.DataFrame({'电影名称':movies[0],'电影类型':movies[1],'导演':movies[6],'主演':movies[5],'评价人数':movies[2],'评分':movies[3],'国家/地区':movies[4],'年代':movies[7]})
3 for i in range(1,18):
4     #总共18页,一页25个
5     link="https://www.douban.com/doulist/240962/?start="+str(i*25)
6     movies=get_movies(link)
7     movies_1=movies_1.append(pd.DataFrame({'电影名称':movies[0],'电影类型':movies[1],'导演':movies[6],'主演':movies[5],'评价人数':movies[2],'评分':movies[3],'国家/地区':movies[4],'年代':movies[7]}),ignore_index=True)
8 all_movies=movies_1

总共读取三个网页的电影信息,操作类似
整合所有数据后的到

 

 

 

 

 

 2.数据分析

    首先把年份的列名改成year

data.rename(columns={'年代':'year'},inplace=True)

    统计每个年代上榜影片数量,并用plotly绘制柱状图

    首先要导入相关库

1 import plotly.express as px
2 import plotly.graph_objects as go
1 n=data.groupby('year').count()
2 x=list(n.index)
3 y=list(n['评分'])
4 fig = go.Figure()
5 fig.add_trace(go.Bar(
6     x=x,
7     y=y,
8 ))

plotly可以用以下方法下载图片

import plotly.io as pio
pio.write_image(fig, '1.png')

 

 

 

 

 

 3.评分和评价人数

这里需要标准化数据,使他们落在一个区间

1 x=data.groupby('year')['评价人数','评分'].mean()
2 s=(x-x.mean())/x.std()
3 fig = px.line(s)
4 fig.show()

 

 

 20世纪早期的电影观看人数较少,但评分普遍较高,了20世纪中期之后的电影观看人数开始增加,但评分却略显平庸,到了本世纪,评分才有了上涨的趋势。

4.统计所有上榜电影

首先将电影类型按照 ‘/’ 分割,并去空格,转化成list 的目的是使用collections.Counter
先导入

 1 from collections import Counter
 2 types=data['电影类型'].str.split('/')
 3 l=[]
 4 tl=[]
 5 for i in range(783):
 6     l.extend(types[i])
 7 for i in l:
 8     tl.append(i.strip())
 9 c = Counter(tl)
10 k=list(c.keys())
11 v=list(c.values())
12 count=pd.DataFrame({'type':k,'c':v})
13 count.sort_values(by='c')
14 total=count

绘制饼图

fig = px.pie(total, values='c', names='type')
fig.show()

 

 

 5.每个年代电影类型占比的统计

 

 

 再按照之前的方法进行统计
并计算出每个年代各个类型出现的概率,画出柱状图
其中x是所有电影类型的列表
y是该年代各个电影类型的占比

 1 import plotly.graph_objects as go
 2 
 3 fig = go.Figure()
 4 fig.add_trace(go.Bar(
 5     x=k,
 6     y=get_ep(l20_20,k),
 7     name='20世纪20年代',
 8 ))
 9 fig.add_trace(go.Bar(
10     x=k,
11     y=get_ep(l20_30,k),
12     name='20世纪30年代',
13 ))
14 fig.add_trace(go.Bar(
15     x=k,
16     y=get_ep(l20_40,k),
17     name='20世纪40年代',
18 ))
19 fig.add_trace(go.Bar(
20     x=k,
21     y=get_ep(l20_50,k),
22     name='20世纪50年代',
23 ))
24 fig.add_trace(go.Bar(
25     x=k,
26     y=get_ep(l20_60,k),
27     name='20世纪60年代',
28 ))
29 fig.add_trace(go.Bar(
30     x=k,
31     y=get_ep(l20_70,k),
32     name='20世纪70年代',
33 ))
34 fig.add_trace(go.Bar(
35     x=k,
36     y=get_ep(l20_80,k),
37     name='20世纪80年代',
38 ))
39 fig.add_trace(go.Bar(
40     x=k,
41     y=get_ep(l20_90,k),
42     name='20世纪90年代',
43 ))
44 fig.add_trace(go.Bar(
45     x=k,
46     y=get_ep(l21_00,k),
47     name='21世纪00年代',
48 ))
49 fig.add_trace(go.Bar(
50     x=k,
51     y=get_ep(l21_10,k),
52     name='21世纪10年代',
53 ))
54 fig.show()

 

 

 你可以详细查看其中的类

 

 

 

四、完整代码:

  1 import re
  2 import requests
  3 from bs4 import BeautifulSoup
  4 import pandas as pd
  5 def get_movies(link):
  6     headers = {  # 这是请求头
  7         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
  8                       'Chrome/83.0.4103.116 Safari/537.36 '
  9 
 10     }
 11     movie_names=[]
 12 
 13     movie_types=[]
 14 
 15     movie_dis=[]
 16 
 17     movie_grade=[]
 18 
 19     movie_addr=[]
 20 
 21     movie_actor=[]
 22 
 23     movie_director=[]
 24 
 25     movie_year=[]
 26 
 27     r=requests.get(link,headers=headers,timeout=10)
 28 
 29     soup=BeautifulSoup(r.text,"lxml")
 30     
 31     for each in soup.find_all('div',class_='abstract'):
 32         a=each.text
 33         #.匹配任意字符,除了换行符
 34 
 35         tp = re.search(r'类型: (.*)',a)
 36         if tp==None:
 37             movie_types.append(" ")
 38 
 39         else:
 40             movie_types.append(tp.group(1))
 41         actor = re.search(r'主演: (.*)',a)
 42 
 43         if actor==None:
 44             movie_actor.append(" ")
 45 
 46         else:
 47             movie_actor.append(actor.group(1))
 48         director = re.search(r'导演: (.*)',a)
 49 
 50         if director==None:
 51             movie_director.append(" ")
 52 
 53         else:
 54             movie_director.append(director.group(1))
 55         addr = re.search(r'制片国家/地区: (.*)',a)
 56 
 57         if addr==None:
 58             movie_addr.append(" ")
 59 
 60         else:
 61             movie_addr.append(addr.group(1))
 62         year=re.search(r'年份: (.*)',a)
 63 
 64         if year==None:
 65             movie_year.append(" ")
 66 
 67         else:
 68             year_str=year.group(1)
 69             sj=int(year_str[:2])+1
 70             nd=year_str[2]+'0'
 71             movie_year.append(str(sj)+'世纪'+nd+'年代')
 72     #查询所有class=title的div
 73 
 74     div_list=soup.find_all('div',class_='title')
 75     for each in div_list:
 76         movie_name=each.a.text.strip() # 在div中,a标签的text的内容就是中文电影名称
 77 
 78         movie_names.append(movie_name)
 79     for each in soup.find_all('div',class_='rating'):
 80         a=each.text.split('\n') #在div中,第三个span的text的内容就是评价人数
 81 
 82         #获取字符串中的数字
 83         x=re.sub("\D","",a[3])
 84 
 85         movie_dis.append(int(x))
 86 
 87         movie_grade.append(float(a[2]))
 88 
 89     return movie_names,movie_types,movie_dis,movie_grade,movie_addr,movie_actor,movie_director,movie_year
 90 
 91 movies=get_movies("https://www.douban.com/doulist/240962/")
 92 movies_1=pd.DataFrame({'电影名称':movies[0],'电影类型':movies[1],'导演':movies[6],'主演':movies[5],'评价人数':movies[2],'评分':movies[3],'国家/地区':movies[4],'年代':movies[7]})
 93 
 94 for i in range(1,18):
 95     #总共18页,一页25个
 96 
 97     link="https://www.douban.com/doulist/240962/?start="+str(i*25)
 98 
 99     movies=get_movies(link)
100 
101     movies_1=movies_1.append(pd.DataFrame({'电影名称':movies[0],'电影类型':movies[1],'导演':movies[6],'主演':movies[5],'评价人数':movies[2],'评分':movies[3],'国家/地区':movies[4],'年代':movies[7]}),ignore_index=True)
102 all_movies=movies_1
103 
104 data.rename(columns={'年代':'year'},inplace=True)
105 
106 import plotly.express as px
107 import plotly.graph_objects as go
108 
109 
110 n=data.groupby('year').count()
111 x=list(n.index)
112 y=list(n['评分'])
113 fig = go.Figure()
114 fig.add_trace(go.Bar(
115     x=x,
116     y=y,
117 ))
118 
119 import plotly.io as pio
120 pio.write_image(fig, '1.png')
121 
122 
123 x=data.groupby('year')['评价人数','评分'].mean()
124 s=(x-x.mean())/x.std()
125 fig = px.line(s)
126 fig.show()
127 
128 from collections import Counter
129 
130 types=data['电影类型'].str.split('/')
131 
132 l=[]
133 
134 tl=[]
135 
136 for i in range(783):
137     l.extend(types[i])
138 
139 for i in l:
140     tl.append(i.strip())
141 
142 c = Counter(tl)
143 k=list(c.keys())
144 v=list(c.values())
145 
146 count=pd.DataFrame({'type':k,'c':v})
147 count.sort_values(by='c')
148 total=count
149 
150 fig = px.pie(total, values='c', names='type')
151 fig.show()
152 
153 data_y=data[data.year==year]
154 
155 import plotly.graph_objects as go
156 
157 fig = go.Figure()
158 fig.add_trace(go.Bar(
159     x=k,
160     y=get_ep(l20_20,k),
161     name='20世纪20年代',
162 ))
163 
164 fig.add_trace(go.Bar(
165     x=k,
166     y=get_ep(l20_30,k),
167     name='20世纪30年代',
168 ))
169 
170 fig.add_trace(go.Bar(
171     x=k,
172     y=get_ep(l20_40,k),
173     name='20世纪40年代',
174 ))
175 
176 fig.add_trace(go.Bar(
177     x=k,
178     y=get_ep(l20_50,k),
179     name='20世纪50年代',
180 ))
181 
182 fig.add_trace(go.Bar(
183     x=k,
184     y=get_ep(l20_60,k),
185     name='20世纪60年代',
186 ))
187 
188 fig.add_trace(go.Bar(
189     x=k,
190     y=get_ep(l20_70,k),
191     name='20世纪70年代',
192 ))
193 
194 fig.add_trace(go.Bar(
195     x=k,
196     y=get_ep(l20_80,k),
197     name='20世纪80年代',
198 ))
199 
200 fig.add_trace(go.Bar(
201     x=k,
202     y=get_ep(l20_90,k),
203     name='20世纪90年代',
204 ))
205 
206 fig.add_trace(go.Bar(
207     x=k,
208     y=get_ep(l21_00,k),
209     name='21世纪00年代',
210 ))
211 
212 fig.add_trace(go.Bar(
213     x=k,
214     y=get_ep(l21_10,k),
215     name='21世纪10年代',
216 ))
217 fig.show()

五、总结:

1.以评分高优先的方式爬取电影数据

2.分析高分电影的年代分布情况

3.爬取各个年代电影的评分和评价人数

4.统计上榜电影的类型占比

 

posted @ 2021-06-22 19:51  陈长浩  阅读(1087)  评论(0)    收藏  举报