一.選題的背景
豆瓣電影網對世界知名電影都進行了排行,主要是根據觀眾們對這部電影的評價的高低來對電影進行等級排序,而我想觀測電影的評價分數和評價人數兩者那個對電影的等級影響更大。
二、主題式網絡爬蟲設計方案
1.主題式網絡爬蟲名稱
《Python爬蟲對豆瓣Top250電影網的數據爬取以及分析》
2.主題式網絡爬蟲爬取的內容與數據特征分析
爬取內容:豆瓣Top250
3.主題是網絡爬蟲設計方案概述
實現思路:在瀏覽器 中通過F12訪問網頁源代碼,,分析網站源代碼,找到自己所需要的數據所在的位置,提取數據,對數據進行保存到相同路徑csv文件中,讀取改文件,進行數據清洗,數據模型分析,數據可視化處理,繪制分布圖,直方圖,散點圖。
技術難點:對庫使用和庫中函數的運用,爬取的內容的機構分析處理做數據分析,即求回歸系數。由於不明原因,輸出結果經常會顯示超出列表范圍。
三、主題頁面的結構特種分析
1.對豆瓣網頁面進行結構與特征分析:先找到豆瓣Top250的網址,然后找出電影的評級,圖片。電影名,電影簡介,電影人員介紹,等信息的標簽,並對其進行准確的提取。
2.頁面分析。
抓取自己所需要的標簽,
1 from bs4 import BeautifulSoup #網頁解析獲取數據 2 import urllib.request #制定url。獲取網頁數據 3 import urllib.error 4 import re #正側表達式un,進行文字匹配 5 import xlwt #進行excel操作 6 import sqlite3 #進行sqlit數據庫操作 7 import pandas as np 8 qw=[] #定義空的表,用於存放數據。 9 we=[] 10 er=[] 11 rt=[] 12 ty=[] 13 yu=[] 14 15 def askURL(url): 16 #頭 17 cookie = 'll="118204"; bid=G42QcJoRaWE; _vwo_uuid_v2=D97D607CF35477ACD7007818FB3693D61|29f3ddbf9989fb63a5ddb2567bbbc83a; __gads=ID=f5bf17d7797239d3-227aa9128ecf00d2:T=1640588801:RT=1640588801:S=ALNI_MYBWT9GYs91XjGmv6vlZ7qGL3ht_Q; __yadk_uid=wX9wcwzazXO3XN9AFd60eUUl7x7b9bjo; __utmz=30149280.1640614862.5.5.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __utmz=223695111.1640614862.4.4.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1640667200%2C%22https%3A%2F%2Fcn.bing.com%2F%22%5D; _pk_ses.100001.4cf6=*; __utma=30149280.1607185886.1640317225.1640665257.1640667200.7; __utma=223695111.1200427924.1640531148.1640665257.1640667200.6; __utmb=223695111.0.10.1640667200; Hm_lvt_16a14f3002af32bf3a75dfe352478639=1640610451,1640668363; __utmc=30149280; __utmc=223695111; ap_v=0,6.0; __utmt=1; __utmb=30149280.4.10.1640667200; _pk_id.100001.4cf6=af16e508012adde8.1640531148.6.1640673421.1640665257.' 18 head={ 19 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62", 20 "Cookie": cookie.encode("utf-8").decode("latin1")} 21 22 request=urllib.request.Request(url,headers=head) 23 try: 24 response=urllib.request.urlopen(request) 25 html = response.read().decode("utf-8") 26 return html 27 except urllib.error.URLError as e: 28 if hasattr(e,"code"): 29 print(e.code) 30 elif hasattr(e,"reason"):
31 print(e.reason) 32 #2.解析數據 33 o = 1 34 for i in range(0,10): #調用獲取頁面信息的函數 35 url=f"https://movie.douban.com/top250?start={i*25}&filter="#對10頁網頁進行依次爬取 36 html=askURL(url) 37 soup=BeautifulSoup(html,'html.parser') 38 39 # 影片評價人數 40 findJudge=soup.find_all('div',{'class':'star'}) 41 for i in findJudge: 42 people=i.string 43 # < span > 2512760人評價 < / span > 44 k=re.findall(r'(\d*?)人評價',str(i))[0] 45 qw.append(k) 46 print(k) 47 # 影片評分 48 findRating=soup.find_all('span',{'class':'rating_num'}) 49 for i in findRating: 50 z=i.string 51 we.append(z) 52 print(z) 53 54 # 影片標題 55 findTitle =soup.find_all('span',{'class':'title'}) 56 for i in findTitle : 57 if " / " in str(i): #只爬取電影的中文名稱 58 continue 59 d=i.string 60 er.append(d) 61 print(d) 62 # 影片詳情鏈接 63 findLink =soup.find_all('div',{'class':'hd'}) 64 for i in findLink : 65 b=i.select('a')[0].get('href') 66 rt.append(b) 67 print(b) 68 69 # 影片相關內容 70 findInq=soup.find_all('div',{'class':'bd'})[1:] 71 for i in findInq: 72 y=i.select('p')[0].get_text() 73 ty.append(y) 74 print(y) 75 # 影片圖片 76 findImgSrc=soup.find_all('div',{'class':'pic'}) 77 for i in findImgSrc: 78 q=i.select('img')[0].get('src') 79 request = urllib.request.Request(q) 80 response = urllib.request.urlopen(request) 81 html = response.read() 82 with open(f'.//img/{o}.jpq', "wb") as f: 83 # 寫文件用bytes而不是str,所以要轉碼 84 f.write(html) 85 o += 1 86 #實o每次加以以達到換頁的效果 87 88 # print(len(qw)) 89 # print(len(we)) 90 # print(len(er)) 91 # print(len(rt)) 92 # print(len(ty)) 93 #測試文本數量是否一致
2.保存數據
1 u=[]#建立一個空的列表用於存放數據 2 df = np.DataFrame(data=[qw,we,er,rt,ty],index=['評論人數','評分','電影名','超鏈接','電影人員介紹'])#將數據保存到列表中 3 df2=np.DataFrame(df.values.T,columns=df.index)#對文本進行,行換列,列換行 4 df2.to_excel('qq.xlsx')#保存數據到xlsx文件中
3.數據可視化
1 import pandas as pd 2 from pyecharts.charts import Bar 3 from pyecharts.faker import Faker 4 from pyecharts.globals import ThemeType 5 from pyecharts.charts import Bar 6 from pyecharts.options import global_options as opts 7 #導入所需的庫 8 df=pd.read_excel('qq.xlsx')#導入數據 9 a=df['評分'].values.tolist()[:250] 10 b=df['電影名'].values.tolist()[:250] 11 s=df['評論人數'].values.tolist()[:250]
1 #——————————————————————————————————————評價等級可視化———————————————————————————————————————————————————————————— 2 c = ( 3 Bar({"theme": ThemeType.MACARONS}) 4 .add_xaxis(b) 5 .add_yaxis("評分",a) 6 # .add_yaxis("評論人數",s) 7 .set_global_opts( 8 title_opts={"text": "Bar-通過 dict 進行配置", "subtext": "我也是通過 dict 進行配置的"} 9 10 ) 11 .set_global_opts(title_opts=opts.TitleOpts(), 12 datazoom_opts=opts.DataZoomOpts(),#分段 13 xaxis_opts=opts.AxisOpts(name_rotate=60, name="電影名", axislabel_opts={"rotate": 35})#字體傾斜角度 14 ) 15 16 .render("評級.html") 17 )

1 #————————————————————————————————————評價人數可視化—————————————————————————————————————————————————————————————— 2 3 c = ( 4 Bar({"theme": ThemeType.MACARONS}) 5 .add_xaxis(b) 6 # .add_yaxis("評分",a) 7 .add_yaxis("評論人數",s) 8 .set_global_opts( 9 title_opts={"text": "Bar-通過 dict 進行配置", "subtext": "我也是通過 dict 進行配置的"} 10 11 ) 12 .set_global_opts(title_opts=opts.TitleOpts(), 13 datazoom_opts=opts.DataZoomOpts(),#分段 14 xaxis_opts=opts.AxisOpts(name_rotate=60, name="電影名", axislabel_opts={"rotate": 35})#字體傾斜角度 15 ) 16 17 .render("評價人數.html") 18 )
1 from pyecharts import options as opts 2 from pyecharts.charts import Bar, Grid, Line 3 import pandas as pd 4 from matplotlib import pyplot as plt 5 import numpy as np 6 7 df=pd.read_excel('qq.xlsx')#導入數據 8 b=df['電影名'].values.tolist()[:250] 9 a=df['評分'].values.tolist()[:250] 10 s=df['評論人數'].values.tolist()[:250] 11 12 bar = ( 13 Bar() 14 .add_xaxis(b) 15 .add_yaxis( 16 "評分", 17 a, 18 yaxis_index=0, 19 color="#d14a61", 20 ) 21 .add_yaxis( 22 "評價人數", 23 s, 24 yaxis_index=1, 25 color="#5793f3", 26 ) 27 .extend_axis( 28 yaxis=opts.AxisOpts( 29 name="評價人數", 30 type_="value", 31 min_=0, 32 max_=3000000, 33 position="right", 34 axisline_opts=opts.AxisLineOpts( 35 linestyle_opts=opts.LineStyleOpts(color="#d14a61") 36 ), 37 axislabel_opts=opts.LabelOpts(formatter="{value} ml"), 38 ) 39 ) 40 .extend_axis( 41 yaxis=opts.AxisOpts( 42 type_="value", 43 name="評分", 44 min_=0, 45 max_=2000000, 46 position="left", 47 axisline_opts=opts.AxisLineOpts( 48 linestyle_opts=opts.LineStyleOpts(color="#675bba") 49 ), 50 axislabel_opts=opts.LabelOpts(formatter="{value} "), 51 splitline_opts=opts.SplitLineOpts( 52 is_show=True, linestyle_opts=opts.LineStyleOpts(opacity=1) 53 ), 54 ) 55 ) 56 .set_global_opts( 57 yaxis_opts=opts.AxisOpts( 58 name="評分", 59 min_=0, 60 max_=10, 61 position="right", 62 offset=80, 63 axisline_opts=opts.AxisLineOpts( 64 linestyle_opts=opts.LineStyleOpts(color="#5793f3") 65 ), 66 axislabel_opts=opts.LabelOpts(formatter="{value} ml"), 67 ), 68 title_opts=opts.TitleOpts(title="豆瓣Top250多Y軸數據分析"), 69 tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross"), 70 datazoom_opts=opts.DataZoomOpts(), # 分段 71 xaxis_opts=opts.AxisOpts(name_rotate=60, name="電影名", axislabel_opts={"rotate": 35}) # 字體傾斜角度 72 ) 73 ) 74 75 line = ( 76 Line() 77 .add_xaxis(b) 78 .add_yaxis( 79 "平均評分", 80 s, 81 yaxis_index=2, 82 color="#675bba", 83 label_opts=opts.LabelOpts(is_show=False), 84 ) 85 )
1 import random 2 import pandas as pd 3 from pyecharts import options as opts 4 from pyecharts.charts import Bar3D 5 from pyecharts.faker import Faker 6 7 #導入所需的庫 8 df=pd.read_excel('qq.xlsx')#導入數據 9 a=df['評分'].values.tolist()[:10] 10 b=df['電影名'].values.tolist()[:10] 11 s=df['評論人數'].values.tolist()[:10] 12 data = [(i, j, random.randint(0, 10)) for i in range(10) for j in range(10)] 13 c = ( 14 Bar3D() 15 .add( 16 "", 17 [[d[1], d[0], d[2]] for d in data], 18 xaxis3d_opts=opts.Axis3DOpts(a), 19 yaxis3d_opts=opts.Axis3DOpts(b), 20 zaxis3d_opts=opts.Axis3DOpts(s), 21 ) 22 .set_global_opts( 23 visualmap_opts=opts.VisualMapOpts(max_=20), 24 title_opts=opts.TitleOpts(title="豆瓣Top250電影可視化分析圖"), 25 ) 26 .render("bar3d_base.html") 27 )
四 、完整代碼
1 from bs4 import BeautifulSoup #網頁解析獲取數據 2 import urllib.request #制定url。獲取網頁數據 3 import urllib.error 4 import re #正側表達式un,進行文字匹配 5 from pyecharts.charts import Bar, Grid, Line 6 import pandas as pd 7 from pyecharts import options as opts 8 from pyecharts.charts import Bar3D 9 from pyecharts.globals import ThemeType 10 from pyecharts.charts import Bar 11 import random 12 import xlwt #進行excel操作 13 import sqlite3 #進行sqlit數據庫操作 14 import pandas as np 15 qw=[] #定義空的表,用於存放數據。 16 we=[] 17 er=[] 18 rt=[] 19 ty=[] 20 yu=[] 21 22 def askURL(url): 23 #頭 24 cookie = 'll="118204"; bid=G42QcJoRaWE; _vwo_uuid_v2=D97D607CF35477ACD7007818FB3693D61|29f3ddbf9989fb63a5ddb2567bbbc83a; __gads=ID=f5bf17d7797239d3-227aa9128ecf00d2:T=1640588801:RT=1640588801:S=ALNI_MYBWT9GYs91XjGmv6vlZ7qGL3ht_Q; __yadk_uid=wX9wcwzazXO3XN9AFd60eUUl7x7b9bjo; __utmz=30149280.1640614862.5.5.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __utmz=223695111.1640614862.4.4.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1640667200%2C%22https%3A%2F%2Fcn.bing.com%2F%22%5D; _pk_ses.100001.4cf6=*; __utma=30149280.1607185886.1640317225.1640665257.1640667200.7; __utma=223695111.1200427924.1640531148.1640665257.1640667200.6; __utmb=223695111.0.10.1640667200; Hm_lvt_16a14f3002af32bf3a75dfe352478639=1640610451,1640668363; __utmc=30149280; __utmc=223695111; ap_v=0,6.0; __utmt=1; __utmb=30149280.4.10.1640667200; _pk_id.100001.4cf6=af16e508012adde8.1640531148.6.1640673421.1640665257.' 25 head={ 26 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62", 27 "Cookie": cookie.encode("utf-8").decode("latin1")} 28 #模仿瀏覽器頭部 29 request=urllib.request.Request(url,headers=head) 30 try: 31 response=urllib.request.urlopen(request) 32 html = response.read().decode("utf-8") 33 return html 34 except urllib.error.URLError as e: 35 if hasattr(e,"code"): 36 print(e.code) 37 elif hasattr(e,"reason"): 38 print(e.reason) 39 #2.解析數據 40 o = 1 41 for i in range(0,10): #調用獲取頁面信息的函數 42 url=f"https://movie.douban.com/top250?start={i*25}&filter="#對10頁網頁進行依次爬取 43 html=askURL(url) 44 soup=BeautifulSoup(html,'html.parser') 45 46 # 影片評價人數 47 findJudge=soup.find_all('div',{'class':'star'}) 48 for i in findJudge: 49 people=i.string 50 # < span > 2512760人評價 < / span > 51 k=re.findall(r'(\d*?)人評價',str(i))[0] 52 qw.append(k) 53 print(k) 54 # 影片評分 55 findRating=soup.find_all('span',{'class':'rating_num'}) 56 for i in findRating: 57 z=i.string 58 we.append(z) 59 print(z) 60 61 # 影片標題 62 findTitle =soup.find_all('span',{'class':'title'}) 63 for i in findTitle : 64 if " / " in str(i): #只爬取電影的中文名稱 65 continue 66 d=i.string 67 er.append(d) 68 print(d) 69 # 影片詳情鏈接 70 findLink =soup.find_all('div',{'class':'hd'}) 71 for i in findLink : 72 b=i.select('a')[0].get('href') 73 rt.append(b) 74 print(b) 75 76 # 影片相關內容 77 findInq=soup.find_all('div',{'class':'bd'})[1:] 78 for i in findInq: 79 y=i.select('p')[0].get_text() 80 ty.append(y) 81 print(y) 82 # 影片圖片 83 findImgSrc=soup.find_all('div',{'class':'pic'}) 84 for i in findImgSrc: 85 q=i.select('img')[0].get('src') 86 request = urllib.request.Request(q) 87 response = urllib.request.urlopen(request) 88 html = response.read() 89 with open(f'.//img/{o}.jpq', "wb") as f: 90 # 寫文件用bytes而不是str,所以要轉碼 91 f.write(html) 92 o += 1 93 #實o每次加以以達到換頁的效果 94 # print(len(qw)) 95 # print(len(we)) 96 # print(len(er)) 97 # print(len(rt)) 98 # print(len(ty)) 99 #測試文本數量是否一致 100 u=[]#建立一個空的列表用於存放數據 101 df = np.DataFrame(data=[qw,we,er,rt,ty],index=['評論人數','評分','電影名','超鏈接','電影人員介紹'])#將數據保存到列表中 102 df2=np.DataFrame(df.values.T,columns=df.index)#對文本進行,行換列,列換行 103 df2.to_excel('qq.xlsx')#保存數據到xlsx文件中 104 df=pd.read_excel('qq.xlsx')#導入數據 105 b=df['電影名'].values.tolist()[:250] 106 a=df['評分'].values.tolist()[:250] 107 s=df['評論人數'].values.tolist()[:250] 108 109 110 111 #——————————————————————————————————————評價等級可視化———————————————————————————————————————————————————————————— 112 c = ( 113 Bar({"theme": ThemeType.MACARONS}) 114 .add_xaxis(b) 115 .add_yaxis("評分",a) 116 # .add_yaxis("評論人數",s) 117 .set_global_opts( 118 title_opts={"text": "Bar-通過 dict 進行配置", "subtext": "我也是通過 dict 進行配置的"} 119 120 ) 121 .set_global_opts(title_opts=opts.TitleOpts(), 122 datazoom_opts=opts.DataZoomOpts(),#分段 123 xaxis_opts=opts.AxisOpts(name_rotate=60, name="電影名", axislabel_opts={"rotate": 35})#字體傾斜角度 124 ) 125 126 .render("評級.html") 127 ) 128 129 130 #————————————————————————————————————評價人數可視化—————————————————————————————————————————————————————————————— 131 132 c = ( 133 Bar({"theme": ThemeType.MACARONS}) 134 .add_xaxis(b) 135 # .add_yaxis("評分",a) 136 .add_yaxis("評論人數",s) 137 .set_global_opts( 138 title_opts={"text": "Bar-通過 dict 進行配置", "subtext": "我也是通過 dict 進行配置的"} 139 140 ) 141 .set_global_opts(title_opts=opts.TitleOpts(), 142 datazoom_opts=opts.DataZoomOpts(),#分段 143 xaxis_opts=opts.AxisOpts(name_rotate=60, name="電影名", axislabel_opts={"rotate": 35})#字體傾斜角度 144 ) 145 146 .render("評價人數.html") 147 ) 148 149 150 151 #——————————————————————————————————————————————豆瓣Top250多Y軸數據分析———————————————————————————————————————————————— 152 bar = ( 153 Bar() 154 .add_xaxis(b) 155 .add_yaxis( 156 "評分", 157 a, 158 yaxis_index=0, 159 color="#d14a61", 160 ) 161 .add_yaxis( 162 "評價人數", 163 s, 164 yaxis_index=1, 165 color="#5793f3", 166 ) 167 .extend_axis( 168 yaxis=opts.AxisOpts( 169 name="評價人數", 170 type_="value", 171 min_=0, 172 max_=3000000, 173 position="right", 174 axisline_opts=opts.AxisLineOpts( 175 linestyle_opts=opts.LineStyleOpts(color="#d14a61") 176 ), 177 axislabel_opts=opts.LabelOpts(formatter="{value} ml"), 178 ) 179 ) 180 .extend_axis( 181 yaxis=opts.AxisOpts( 182 type_="value", 183 name="評分", 184 min_=0, 185 max_=2000000, 186 position="left", 187 axisline_opts=opts.AxisLineOpts( 188 linestyle_opts=opts.LineStyleOpts(color="#675bba") 189 ), 190 axislabel_opts=opts.LabelOpts(formatter="{value} "), 191 splitline_opts=opts.SplitLineOpts( 192 is_show=True, linestyle_opts=opts.LineStyleOpts(opacity=1) 193 ), 194 ) 195 ) 196 .set_global_opts( 197 yaxis_opts=opts.AxisOpts( 198 name="評分", 199 min_=0, 200 max_=10, 201 position="right", 202 offset=80, 203 axisline_opts=opts.AxisLineOpts( 204 linestyle_opts=opts.LineStyleOpts(color="#5793f3") 205 ), 206 axislabel_opts=opts.LabelOpts(formatter="{value} ml"), 207 ), 208 title_opts=opts.TitleOpts(title="豆瓣Top250多Y軸數據分析"), 209 tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross"), 210 datazoom_opts=opts.DataZoomOpts(), # 分段 211 xaxis_opts=opts.AxisOpts(name_rotate=60, name="電影名", axislabel_opts={"rotate": 35}) # 字體傾斜角度 212 ) 213 ) 214 215 line = ( 216 Line() 217 .add_xaxis(b) 218 .add_yaxis( 219 "平均評分", 220 s, 221 yaxis_index=2, 222 color="#675bba", 223 label_opts=opts.LabelOpts(is_show=False), 224 ) 225 ) 226 227 228 229 #——————————————————————————————————————————————豆瓣Top250電影3D可視化分析圖———————————————————————————————— 230 data = [(i, j, random.randint(0, 10)) for i in range(10) for j in range(10)] 231 c = ( 232 Bar3D() 233 .add( 234 "", 235 [[d[1], d[0], d[2]] for d in data], 236 xaxis3d_opts=opts.Axis3DOpts(a), 237 yaxis3d_opts=opts.Axis3DOpts(b), 238 zaxis3d_opts=opts.Axis3DOpts(s), 239 ) 240 .set_global_opts( 241 visualmap_opts=opts.VisualMapOpts(max_=20), 242 title_opts=opts.TitleOpts(title="豆瓣Top250電影可視化分析圖"), 243 ) 244 .render("bar3d_base.html") 245 )
五、總結
1.經過對爬取的豆瓣電影數據分析,電影的評分和評價人數沒有直接的關系,但是又間接的關系。
大多數口碑比較好的電影評價的人數就很多。所以,看電影的時候可以先看一下評分,再看一下評價人數的多少,來判斷電影的好壞。
2.寫完這個之后才發現,在即在爬蟲上的不足,對於網頁標簽的摘取,和最后數據的處理都有一定的不足,每次遇到不會的還要去網上翻閱資料。有時候程序出現錯誤,自己知道錯誤在哪,但不知道如何更改以達到自己想要的目的。
這次爬蟲花費了很大的時間和經歷,是我覺得自學習剛接觸編程語言以來做過最令我高興的事情。