前言
- 蛋肥是python小白,自學(xué)python兩周多曹洽,純屬愛(ài)好,代碼或思路比較稚嫩辽剧,文章主要用來(lái)記錄和總結(jié),還請(qǐng)代碼大神一笑而過(guò)多多指教税产。
- 豆瓣電影提供了api(現(xiàn)在似乎不能用了)怕轿,總之盡量將爬取的數(shù)據(jù)先保存起來(lái),避免過(guò)多請(qǐng)求辟拷,浪費(fèi)服務(wù)器資源(反正也會(huì)被403)撞羽。
準(zhǔn)備
爬取時(shí)間:2020/11/25
系統(tǒng)環(huán)境:Windows 10
所用工具:Jupyter Notebook\Python 3.0
涉及的庫(kù):requests\lxml\pandas\matplotlib\numpy
獲取基礎(chǔ)數(shù)據(jù)
蛋肥想法:先將電影名稱、原名衫冻、評(píng)分诀紊、評(píng)價(jià)人數(shù)、分類信息從網(wǎng)站上爬取下來(lái)隅俘。
豆瓣電影TOP250網(wǎng)址
https://movie.douban.com/top250?start=0
參考資料
xPath用法總結(jié)整理
時(shí)下流行的瀏覽器User-Agent大全
常見(jiàn)的HTTP狀態(tài)碼(HTTP Status Code)
Chrome瀏覽器F12開(kāi)發(fā)者工具簡(jiǎn)單使用
import requests
from lxml import etree
#寫(xiě)一個(gè)函數(shù)去爬取豆瓣TOP250的數(shù)據(jù)
def getinfo(list,xpath):
list=[]
#偽造請(qǐng)求頭
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"}
#循環(huán)解決翻頁(yè)問(wèn)題
for i in range(0,10):
link="https://movie.douban.com/top250?start="+str(i*25)
r=requests.get(link,headers=headers,timeout=10)
print(str(i+1),r.status_code)
#爬取對(duì)應(yīng)xpath下的數(shù)據(jù)并存入列表
html=etree.HTML(r.text)
list_transit=html.xpath(xpath+'/text()')
list.extend(list_transit)
return(list)
#通過(guò)函數(shù)爬取數(shù)據(jù)放入列表邻奠,依次為電影名稱、原名为居、評(píng)分碌宴、評(píng)價(jià)人數(shù)、分類信息
film_title=getinfo(list,'//div[@class="hd"]/a/span[1]')
film_origin=getinfo(list,'//div[@class="hd"]/a/span[2]')
film_rate=getinfo(list,'//div[@class="star"]/span[2]')
film_num=getinfo(list,'//div[@class="star"]/span[4]')
film_sort=getinfo(list,'//div[@class="bd"]/p')
數(shù)據(jù)預(yù)處理
蛋肥想法:print數(shù)據(jù)列表后發(fā)現(xiàn)電影原名蒙畴、分類信息等存在不需要的字符贰镣,需預(yù)先處理;同時(shí)因?yàn)楹罄m(xù)想做一個(gè)豆瓣電影TOP250的維度分布圖膳凝,而同一電影存在多個(gè)發(fā)行國(guó)家碑隆、類型(如“法國(guó) 美國(guó) / 劇情 動(dòng)作 犯罪”),為了簡(jiǎn)(偷)便(懶)蹬音,這里均取第一個(gè)作為記入的數(shù)據(jù)上煤;最后將數(shù)據(jù)保存為xlsx。
#新建列表分別保存原始數(shù)據(jù)祟绊,避免與豆瓣403后無(wú)法獲取數(shù)據(jù)楼入,也避免原始數(shù)據(jù)受到誤操作的影響
film_title_save=film_title.copy()
film_origin_save=film_origin.copy()
film_rate_save=film_rate.copy()
film_num_save=film_num.copy()
film_sort_save=film_sort.copy()
#去除電影原名中不需要的字符
for i in range(len(film_origin_save)):
film_origin_save[i]=film_origin_save[i].replace("\xa0","").replace("/","",1).replace(" ","")
#去除電影分類中不需要的字符哥捕、去除頭尾空格、按"/"將字符串劃分
for i in range(len(film_sort_save)):
film_sort_save[i]=film_sort_save[i].replace("\xa0","").replace("\n","").strip().split("/",2)
#經(jīng)觀察嘉熊,列表中['']的出現(xiàn)并無(wú)規(guī)律遥赚,所以先去掉['']后再切片
while [''] in film_sort_save:
film_sort_save.remove([''])
film_sort_save=film_sort_save[1::2]
#取發(fā)行國(guó)家、電影類型的第一個(gè)
for i in range(len(film_sort_save)):
film_sort_save[i][1]=film_sort_save[i][1].split(" ")[0]
film_sort_save[i][2]=film_sort_save[i][2].split(" ")[0]
#['1961(中國(guó)大陸) ', '', '']阐肤, ['1983(中國(guó)大陸)', '中國(guó)大陸', '動(dòng)畫(huà)']這兩條數(shù)據(jù)存在異常凫佛,再次處理
for i in range(len(film_sort_save)):
if(film_sort_save[i][0]=="1983(中國(guó)大陸)"):
film_sort_save[i][0]="1983"
elif(film_sort_save[i][0]=="1961(中國(guó)大陸) "):
film_sort_save[i][0]="1961"
film_sort_save[i][1]="中國(guó)大陸"
film_sort_save[i][2]="動(dòng)畫(huà)"
#現(xiàn)在將所有數(shù)據(jù)存入表中保存,先對(duì)分類信息做拆分
film_sort_save_time=[x[0] for x in film_sort_save]
film_sort_save_country=[x[1] for x in film_sort_save]
film_sort_save_type=[x[2] for x in film_sort_save]
#保存并導(dǎo)出數(shù)據(jù)為xlsx
import pandas as pd
df=pd.DataFrame([film_title_save,film_origin_save,film_rate_save,film_num_save,film_sort_save_time,film_sort_save_country,film_sort_save_type],
index=["電影名稱","電影原名","評(píng)分","評(píng)價(jià)人數(shù)","發(fā)行時(shí)間","發(fā)行國(guó)家","電影類型"])
df.T.to_excel(r"C:\Users\Archer\Desktop\爬取數(shù)據(jù).xlsx",index=False)
數(shù)據(jù)可視化
蛋肥想法:蛋肥想知道在豆瓣電影TOP250中年份孕惜、國(guó)家愧薛、類型的維度數(shù)據(jù),為了練手衫画,使用剛才保存成xlsx的數(shù)據(jù)毫炉,并分別畫(huà)成雷達(dá)圖、柱形圖削罩、扇形圖瞄勾。
#導(dǎo)入excel數(shù)據(jù)
import pandas as pd
df=pd.read_excel(r"C:\Users\Archer\Desktop\爬取數(shù)據(jù).xlsx")
#發(fā)行國(guó)家,分類弥激、計(jì)數(shù)进陡、排序后取前10
country=df.groupby("發(fā)行國(guó)家").count().sort_values(by=["電影名稱"],ascending=False)[:10]
#發(fā)行時(shí)間,轉(zhuǎn)化int微服、按區(qū)間計(jì)數(shù)
df["發(fā)行時(shí)間"]=df["發(fā)行時(shí)間"].astype(int)
time_slice=["1930-1940","1940-1950","1950-1960","1960-1970","1970-1980","1980-1990","1990-2000","2000-2010","2010-2020"]
data_time=[]
for i in range(0,9):
data=df[(df["發(fā)行時(shí)間"]>(1940+(i-1)*10))&(df["發(fā)行時(shí)間"]<=(1940+i*10))]["電影名稱"].count()
data_time.append(data)
#電影類型趾疚,分類、計(jì)數(shù)以蕴、排序
form=df.groupby("電影類型").count().sort_values(by=["電影名稱"],ascending=False)
#直接用index做label畫(huà)扇形圖有重疊糙麦,稍微處理下
pie_label=list(form.index)
pie_label[-4:]=["","","",""]
import matplotlib.pyplot as plt
import numpy as np
#畫(huà)圖四件套:顯示、矢量舒裤、中文喳资、負(fù)號(hào)
%matplotlib inline
%config InlineBackend.figure_format="svg"
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#繪制畫(huà)布尺寸
plt.figure(figsize=(12,5))
#設(shè)置發(fā)行國(guó)家子畫(huà)布(n行,n列,該畫(huà)布位置)
plt.subplot(1,1,1)
#設(shè)置標(biāo)題
plt.title("發(fā)行國(guó)家前10 柱形圖")
#設(shè)置橫縱坐標(biāo)軸標(biāo)簽
plt.xlabel("發(fā)行國(guó)家")
plt.ylabel("電影數(shù)量")
#設(shè)置數(shù)據(jù)
x=list(range(0,10))
y=country["電影名稱"]
plt.xticks(x,country.index)
#繪制柱形圖
plt.bar(x,y)
#添加數(shù)據(jù)標(biāo)簽 plt.text(橫坐標(biāo),縱坐標(biāo),值,水平對(duì)齊方式,垂直對(duì)齊方式,字號(hào))
for a,b in zip(x,y):
plt.text(a,b,b,ha="center",va="bottom",fontsize=10)
#導(dǎo)出圖表
plt.savefig(r"C:\Users\Archer\Desktop\my_fig_1.png")
#繪制畫(huà)布尺寸
plt.figure(figsize=(12,5))
#設(shè)置發(fā)行時(shí)間子畫(huà)布(n行,n列,該畫(huà)布位置,是否為極坐標(biāo)系)
polar=plt.subplot(1,2,1,polar="true")
#設(shè)置標(biāo)題
plt.title("發(fā)行時(shí)間 雷達(dá)圖",va="bottom")
#在指定的間隔內(nèi)返回均勻的角度
angles=np.linspace(0,2*np.pi,9,endpoint=False)
#完成數(shù)據(jù)拼接,實(shí)現(xiàn)閉環(huán)
angles=np.concatenate((angles,[angles[0]]))
data_time=np.concatenate((data_time,[data_time[0]]))
#設(shè)置橫坐標(biāo)軸
plt.xticks(angles,time_slice)
#設(shè)置y軸范圍
plt.ylim(0,100)
#繪制雷達(dá)圖
plt.polar(angles,data_time,marker="o",markersize=4,markerfacecolor='white')
#設(shè)置0°的位置及極坐標(biāo)旋轉(zhuǎn)方向
polar.set_theta_zero_location("N")
polar.set_theta_direction("clockwise")
#填充顏色
plt.fill(angles,data_time,color="#7bbfea")
#設(shè)置電影類型子畫(huà)布(n行,n列,該畫(huà)布位置,是否為極坐標(biāo)系)
polar=plt.subplot(1,2,2)
#設(shè)置標(biāo)題
plt.title("電影類型 扇形圖")
#繪制扇形圖
plt.pie(form["電影名稱"],labels=pie_label)
#添加注釋去解釋設(shè)為空的label腾供,annotate(注釋文本,起點(diǎn)位置,文本位置,箭頭設(shè)置)
plt.annotate("傳記",xy=(0.9,-0.11),xytext=(1.5,-0.2),arrowprops=dict(arrowstyle="-"))
plt.annotate("冒險(xiǎn)",xy=(0.9,-0.07),xytext=(1.5,-0.1),arrowprops=dict(arrowstyle="-"))
plt.annotate("兒童",xy=(0.9,-0.035),xytext=(1.5,-0.005),arrowprops=dict(arrowstyle="-"))
plt.annotate("愛(ài)情",xy=(0.9,-0.01),xytext=(1.5,0.1),arrowprops=dict(arrowstyle="-"))
#導(dǎo)出圖表
plt.savefig(r"C:\Users\Archer\Desktop\my_fig_2.png")
數(shù)據(jù)分析
- 發(fā)行國(guó)家上仆邓,美國(guó)電影的數(shù)量一騎絕塵,可以綜合其評(píng)分伴鳖、排名數(shù)據(jù)深入研究榜上美國(guó)電影的質(zhì)量分布情況节值,同時(shí),從柱形圖上可以看出日韓位列前10榜聂,從蛋肥的觀影經(jīng)驗(yàn)上看搞疗,日韓電影自成一派,有著強(qiáng)烈的地域風(fēng)格须肆,但高評(píng)分的電影往往集中于這些風(fēng)格中匿乃,很少有跳脫出來(lái)的桩皿,這點(diǎn)可以通過(guò)對(duì)數(shù)據(jù)的進(jìn)一步分析去進(jìn)行考證。
- 發(fā)行時(shí)間上幢炸,1990-2020年間的電影幾乎占據(jù)了榜單泄隔,不知道是否是因?yàn)?990年前(尤其是1980年前)的電影已經(jīng)很難接觸到了,蛋肥個(gè)人感覺(jué)還是有不少經(jīng)典的影片沒(méi)有上榜宛徊,比如《卡薩布蘭卡》(1942年)佛嬉,同時(shí),可以進(jìn)一步探討為什么從1990年起高質(zhì)量的電影的數(shù)量陡增闸天,結(jié)合電影產(chǎn)業(yè)暖呕、大眾審美等的發(fā)展歷程,應(yīng)該是個(gè)有意思的論題苞氮。
- 電影類型上湾揽,不得不說(shuō),一個(gè)高質(zhì)量的電影往往有一個(gè)好的故事笼吟,蛋肥最近總覺(jué)得國(guó)內(nèi)外的電影钝腺,特效越來(lái)越花哨、場(chǎng)景越來(lái)越精美赞厕,卻很少有能認(rèn)真地講好一個(gè)故事的,不知道是否前人成就太高導(dǎo)致后人有點(diǎn)無(wú)從下手了定硝。
- 其他皿桑,蛋肥覺(jué)得可以從一個(gè)更長(zhǎng)的時(shí)間區(qū)間上去研究豆瓣電影TOP250榜單,看是否能反映出大眾電影審美的變化趨勢(shì)蔬啡;或是是否存在因?yàn)槟巢侩娪霸u(píng)分高诲侮,后續(xù)觀看的人受到評(píng)分影響,導(dǎo)致該電影評(píng)分持續(xù)漲高箱蟆,是否有指標(biāo)可以來(lái)衡量其相關(guān)性沟绪;或是是否存在一個(gè)口碑的延后,某部電影在某一時(shí)刻評(píng)分一般空猜,但在之后某一時(shí)刻開(kāi)始卻持續(xù)走高绽慈,導(dǎo)致變化的原因是什么等。
總結(jié)
- 不會(huì)就百度辈毯,實(shí)在不行就構(gòu)造一個(gè)小的代碼段坝疼,不斷嘗試,總能找到答案的谆沃。
- python只是工具钝凶,分析問(wèn)題的思路和方法才是最重要的,蛋肥還需多多補(bǔ)充相關(guān)知識(shí)唁影。