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.统计上榜电影的类型占比

浙公网安备 33010602011771号