閱讀228 返回首頁    go 技術社區[雲棲]


手把手 | 教你爬下100部電影數據:R語言網頁爬取入門指南


0?wx_fmt=jpeg


前言

網頁上的數據和信息正在呈指數級增長。如今我們都使用穀歌作為知識的首要來源——無論是尋找對某地的評論還是了解新的術語。所有這些信息都已經可以從網上輕而易舉地獲得。

網絡中可用數據的增多為數據科學家開辟了可能性的新天地。我非常相信網頁爬取是任何一個數據科學家的必備技能。在如今的世界裏,我們所需的數據都在互聯網上,使用它們唯一受限的是我們對數據的獲取能力。有了本文的幫助,您定會克服這個困難。

網上大多數的可用數據並不容易獲取。它們以非結構化的形式(HTML格式)表示,並且不能下載。因此,這便需要知識和專業技能來使用它們。

我在本文中準備帶您走一遍用R來實現網頁爬取的過程。讓您學會如何使用互聯網上任何類型的可用數據。


先決條件

用R來進行網頁爬取的先決條件分為兩個

要進行網頁爬取,您必須具備R語言的操作知識。如果您正處於初識階段或者想刷新基礎知識,我強烈建議您按這個學習路徑(https://www.analyticsvidhya.com/learning-paths-data-science-business-analytics-business-intelligence-big-data/learning-path-r-data-science/)學習R語言。在本文中,我們將使用R語言中由Hadley Wickham撰寫的“rvest”包。您可以從下麵的鏈接(https://cran.r-project.org/web/packages/rvest/rvest.pdf)獲得rvest包的文檔。請確保您安裝了這個包。如果您現在還沒有這個包,請按下麵的代碼來安裝。

install.packages('rvest')

此外,如果有關於HTML和CSS的知識就更好了。我能找到的關於學習HTML和CSS的最好資源在這裏(https://flukeout.github.io)。根據觀察而言大多數數據科學家對於HTML和CSS不是那麼精通。因此,我們會利用一個名為“Selector Gadget”的開源軟件,對所有人來講,用它來執行網頁爬取是足夠的。您可以從這裏(https://selectorgadget.com)訪問和下載Selector Gadge的擴展程序。請確保跟隨該網站上的指示來安裝這個擴展程序。我已經完成了這一步,現在正在使用穀歌chrome,並且可以通過chrome右上角的擴展欄上的這個圖標使用它。

0?wx_fmt=jpeg

有了它,隻需要輕輕的點擊,您便可以選擇網站的任何部分並獲得相關標簽。請注意:這是一個實際學習HTML和CSS並手動操作的方法。但是,要掌握網頁爬取,我強烈建議您學習HTML和CSS以更好地理解和體味在搜索引擎背後發生的故事。


使用R語言實現網頁爬取

現在,讓我們開始爬取IMDb網站中2016年上映的100部最受歡迎的電影。您可以點擊這裏https://www.imdb.com/search/title?count=100&release;_date=2016,2016&title;_type=feature訪問網站。

#加載rvest包

library('rvest')

#定義需要爬取網站的url

url <- 'https://www.imdb.com/search/title?count=100&release;_date=2016,2016&title;_type=feature'

#從網站中讀取HTML代碼

webpage <- read_html(url)

現在,我們將從這個網站上爬取以下數據。

Rank:電影排名(1-100),包括2016年上映的100個最受歡迎的電影。

Title:電影標題。

Description:電影描述。

Runtime:電影時長。

Genre:電影類型。

Rating:電影的IMDb評分(用戶打分)。

Metascore:電影在IMDb網站上的metascore評分(評論家打分)。

Votes:電影讚成票數。

Gross_Earning_in_Mil:電影總收入,以百萬為單位。

Director:電影的主要導演。注意,如果有多個導演,我隻選取第一個。

Actor:電影的主要演員。注意,如果有多個演員,我隻選取第一個。

這是一個包含如何排列所有這些字段的截圖。

0?wx_fmt=png

步驟1:現在,我們先來爬取Rank字段。為此,我們將使用Selector Gadget來獲取包含排名的特定CSS選擇器。您可以在瀏覽器中點擊這個擴展程序,並用光標選擇排名字段。

0?wx_fmt=jpeg

請確保所有的排名都被選中。您可以選擇更多的排名部分,以防您無法獲取所有這些排名,也可以通過單擊所選部分以取消選擇,用以確保隻突出了您想要爬取的內容。

步驟2:當您確定已正確選擇後,您需要複製相應的CSS選擇器,這可以在底部中心查看。

0?wx_fmt=jpeg

步驟3:當您知道CSS選擇器已包含了排名順序之後,您可以使用這個簡單的R語言代碼來獲取所有的排名:

#使用CSS選擇器來爬取排名部分

rank_data_html <- html_nodes(webpage,'.text-primary')

#將排名數據轉化為文本

rank_data <- html_text(rank_data_html)

#讓我們來看看排名

head(rank_data)

[1] "1." "2." "3." "4." "5." "6."


步驟4:當您有了數據後,請確保它看起來是您所需的格式。我在對數據進行預處理,將其轉換為數字格式。

#數據預處理:將排名轉換為數字格式

rank_data<-as.numeric(rank_data)

#我們再來看看排名

head(rank_data)

[1] 1 2 3 4 5 6


步驟5現在您可以清除選擇器部分並選擇所有標題。您可以直觀地檢查所有標題是否被選中。使用您的光標進行任何所需的添加和刪除。我在這裏做了同樣的事情。

0?wx_fmt=png

步驟6:再一次,我有了相應標題的CSS選擇器-- .lister-item-essay-header a。我將使用該選擇器和以下代碼爬取所有標題。

#使用CSS選擇器來爬取標題部分

title_data_html <- html_nodes(webpage,'.lister-item-essay-header a')

#將標題數據轉化為文本

title_data <- html_text(title_data_html)

#讓我們來看看標題

head(title_data)

[1] "Sing"          "Moana"         "Moonlight"     "Hacksaw Ridge"

[5] "Passengers"    "Trolls"


步驟7:在下麵的代碼中,我對Description、Runtime、Genre、Rating、Metascore、Votes、Gross_Earning_in_Mil、Director和Actor數據做了同樣的操作。

#使用CSS選擇器來爬取描述部分

description_data_html <- html_nodes(webpage,'.ratings-bar+ .text-muted')

#將描述數據轉化為文本

description_data <- html_text(description_data_html)

#讓我們來看看描述數據

head(description_data)

[1] "\nIn a city of humanoid animals, a hustling theater impresario's attempt to save his theater with a singing competition becomes grander than he anticipates even as its finalists' find that their lives will never be the same."

[2] "\nIn Ancient Polynesia, when a terrible curse incurred by the Demigod Maui reaches an impetuous Chieftain's daughter's island, she answers the Ocean's call to seek out the Demigod to set things right."

[3] "\nA chronicle of the childhood, adolescence and burgeoning adulthood of a young, African-American, gay man growing up in a rough neighborhood of Miami."

[4] "\nWWII American Army Medic Desmond T. Doss, who served during the Battle of Okinawa, refuses to kill people, and becomes the first man in American history to receive the Medal of Honor without firing a shot."

[5] "\nA spacecraft traveling to a distant colony planet and transporting thousands of people has a malfunction in its sleep chambers. As a result, two passengers are awakened 90 years early."

[6] "\nAfter the Bergens invade Troll Village, Poppy, the happiest Troll ever born, and the curmudgeonly Branch set off on a journey to rescue her friends.

#Data-Preprocessing: removing '\n'

#數據預處理:去掉'\n'

description_data<-gsub("\n","",description_data)

#Let's have another look at the description data

#我們再來看看描述數據

head(description_data)

[1] "In a city of humanoid animals, a hustling theater impresario's attempt to save his theater with a singing competition becomes grander than he anticipates even as its finalists' find that their lives will never be the same."

[2] "In Ancient Polynesia, when a terrible curse incurred by the Demigod Maui reaches an impetuous Chieftain's daughter's island, she answers the Ocean's call to seek out the Demigod to set things right."

[3] "A chronicle of the childhood, adolescence and burgeoning adulthood of a young, African-American, gay man growing up in a rough neighborhood of Miami."

[4] "WWII American Army Medic Desmond T. Doss, who served during the Battle of Okinawa, refuses to kill people, and becomes the first man in American history to receive the Medal of Honor without firing a shot."

[5] "A spacecraft traveling to a distant colony planet and transporting thousands of people has a malfunction in its sleep chambers. As a result, two passengers are awakened 90 years early."

[6] "After the Bergens invade Troll Village, Poppy, the happiest Troll ever born, and the curmudgeonly Branch set off on a journey to rescue her friends."

#使用CSS選擇器來爬取電影時長部分

runtime_data_html <- html_nodes(webpage,'.text-muted .runtime')

#將時長數據轉化為文本

runtime_data <- html_text(runtime_data_html)

#讓我們來看看時長

head(runtime_data)

[1] "108 min" "107 min" "111 min" "139 min" "116 min" "92 min"

#數據預處理:去掉'mins',並轉換為數字格式

runtime_data<-gsub(" min","",runtime_data)

runtime_data<-as.numeric(runtime_data)

#我們再來看看時長數據

head(rank_data)

[1] 1 2 3 4 5 6

#使用CSS選擇器來爬取電影類型部分

genre_data_html <- html_nodes(webpage,'.genre')

#將類型數據轉化為文本

genre_data <- html_text(genre_data_html)

#讓我們來看看類型

head(genre_data)

[1] "\nAnimation, Comedy, Family "

[2] "\nAnimation, Adventure, Comedy "

[3] "\nDrama "

[4] "\nBiography, Drama, History "

[5] "\nAdventure, Drama, Romance "

[6] "\nAnimation, Adventure, Comedy "

#數據預處理:去掉'\n'

genre_data<-gsub("\n","",genre_data)

#數據預處理:去掉多餘的空格

genre_data<-gsub(" ","",genre_data)

#隻選取每一部電影的第一種類型

genre_data<-gsub(",.*","",genre_data)

#將每種類型從文本轉換為因子

genre_data<-as.factor(genre_data)

#我們再來看看類型數據

head(genre_data)

[1] Animation Animation Drama     Biography Adventure Animation

10 Levels: Action Adventure Animation Biography Comedy Crime Drama ... Thriller

#使用CSS選擇器來爬取IMDB評分部分

rating_data_html <- html_nodes(webpage,'.ratings-imdb-rating strong')

#將評分數據轉化為文本

rating_data <- html_text(rating_data_html)

#讓我們來看看評分

head(rating_data)

[1] "7.2" "7.7" "7.6" "8.2" "7.0" "6.5"

#數據預處理:將評分轉換為數字格式

rating_data<-as.numeric(rating_data)

#我們再來看看評分數據

head(rating_data)

[1] 7.2 7.7 7.6 8.2 7.0 6.5

#使用CSS選擇器來爬取讚成票部分

votes_data_html <- html_nodes(webpage,'.sort-num_votes-visible span:nth-child(2)')

#將讚成票數據轉化為文本

votes_data <- html_text(votes_data_html)

#讓我們來看看讚成票數據

head(votes_data)

[1] "40,603"  "91,333"  "112,609" "177,229" "148,467" "32,497"

#數據預處理:去掉逗號

votes_data<-gsub(",","",votes_data)

#數據預處理:將讚成票數據轉換為數字格式

votes_data<-as.numeric(votes_data)

#我們再來看看讚成票數據

head(votes_data)

[1]  40603  91333 112609 177229 148467  32497

#使用CSS選擇器來爬取導演部分

directors_data_html <- html_nodes(webpage,'.text-muted+ p a:nth-child(1)')

#將導演數據轉化為文本

directors_data <- html_text(directors_data_html)

#讓我們來看看導演數據

head(directors_data)

[1] "Christophe Lourdelet" "Ron Clements"         "Barry Jenkins"

[4] "Mel Gibson"           "Morten Tyldum"        "Walt Dohrn"

#數據預處理:將導演數據轉換為因子

directors_data<-as.factor(directors_data)

#使用CSS選擇器來爬取演員部分

actors_data_html <- html_nodes(webpage,'.lister-item-content .ghost+ a')

#將演員數據轉化為文本

actors_data <- html_text(actors_data_html)

#讓我們來看看演員數據

head(actors_data)

[1] "Matthew McConaughey" "Auli'i Cravalho"     "Mahershala Ali"

[4] "Andrew Garfield"     "Jennifer Lawrence"   "Anna Kendrick"

#數據預處理:將演員數據轉換為因子

actors_data<-as.factor(actors_data)

但是,我想讓您緊跟我看看當我對Metascore評分數據做同樣的事情時會發生什麼。

#使用CSS選擇器來爬取metascore評分部分

metascore_data_html <- html_nodes(webpage,'.metascore')

#將metascore數據轉化為文本

metascore_data <- html_text(metascore_data_html)

#讓我們來看看metascore

data head(metascore_data)

[1] "59        " "81        " "99        " "71        " "41        "

[6] "56        "

#數據預處理:去掉metascore中多餘的空格

metascore_data<-gsub(" ","",metascore_data)

#讓我們檢查一下metascore數據的長度

length(metascore_data)

[1] 96

步驟8:我們正在爬取100部電影的數據,而metascore評分數據的長度是96。原因是因為有4部電影沒有相應的Metascore字段。

0?wx_fmt=jpeg

步驟9:它是在爬取任何網站時都會發生的實際情況。不幸的是,如果我們簡單地添加NA到最後4個條目,它將Metascrore數據中的NA映射到第96到100個電影,而實際上,數據丟失的是其他的一些電影。經過直觀地檢查,我發現缺失的是電影39、73、80和89的Metascore數據。我寫了以下函數來解決這個問題。

for (i in c(39,73,80,89)){

a<-metascore_data[1:(i-1)]

b<-metascore_data[i:length(metascore_data)]

metascore_data<-append(a,list("NA"))

metascore_data<-append(metascore_data,b)

}

#數據預處理:將metascore轉換為數字格式

metascore_data<-as.numeric(metascore_data)

#Let's have another look at length of the metascore data

#我們再來看看metascore數據長度

length(metascore_data)

[1] 100

#讓我們來看看summary statistics

summary(metascore_data)

Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's

23.00   47.00   60.00   60.22   74.00   99.00       4


步驟10:同樣的事情發生在Gross變量,這個數字代表這部電影的總收入。我使用相同的解決方案來解決這個問題:

#使用CSS選擇器來爬取總收入部分

gross_data_html <- html_nodes(webpage,'.ghost~ .text-muted+ span')

#將總收入數據轉化為文本

gross_data <- html_text(gross_data_html)

#讓我們來看看總收入

head(gross_data)

[1] "$269.36M" "$248.04M" "$27.50M"  "$67.12M"  "$99.47M"  "$153.67M"

#數據預處理:去掉符號'$'和'M'

gross_data<-gsub("M","",gross_data)

gross_data<-substring(gross_data,2,6)

#我們再來看看總收入數據長度

length(gross_data)

[1] 86

 #用NA填補缺失條目

for (i in c(17,39,49,52,57,64,66,73,76,77,80,87,88,89)){

a<-gross_data[1:(i-1)]

b<-gross_data[i:length(gross_data)]

gross_data<-append(a,list("NA"))

gross_data<-append(gross_data,b)

}

#數據預處理:將總收入轉換為數字格式

gross_data<-as.numeric(gross_data) 

#我們再來看看總收入數據長度

length(gross_data)

[1] 100

summary(gross_data)

Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's

0.08   15.52   54.69   96.91  119.50  530.70      14


步驟11:現在我們已經成功地爬取了2016年上映的100部最受歡迎的電影的所有11個特征。讓我們合並它們到一個數據框並檢查它的結構。

#合並所有列表構造一個數據框

movies_df<-data.frame(Rank = rank_data, Title = title_data,

Description = description_data, Runtime = runtime_data,

Genre = genre_data, Rating = rating_data,

Metascore = metascore_data, Votes = votes_data,                                                             Gross_Earning_in_Mil = gross_data,

Director = directors_data, Actor = actors_data)

#數據框的結構

str(movies_df)

'data.frame':            100 obs. of  11 variables:

$ Rank                : num  1 2 3 4 5 6 7 8 9 10 ...

$ Title               : Factor w/ 99 levels "10 Cloverfield Lane",..: 66 53 54 32 58 93 8 43 97 7 ...

$ Description         : Factor w/ 100 levels "19-year-old Billy Lynn is brought home for a victory tour after a harrowing Iraq battle. Through flashbacks the film shows what"| __truncated__,..: 57 59 3 100 21 33 90 14 13 97 ...

$ Runtime             : num  108 107 111 139 116 92 115 128 111 116 ...

$ Genre               : Factor w/ 10 levels "Action","Adventure",..: 3 3 7 4 2 3 1 5 5 7 ...

$ Rating              : num  7.2 7.7 7.6 8.2 7 6.5 6.1 8.4 6.3 8 ...

$ Metascore           : num  59 81 99 71 41 56 36 93 39 81 ...

$ Votes               : num  40603 91333 112609 177229 148467 ...

$ Gross_Earning_in_Mil: num  269.3 248 27.5 67.1 99.5 ...

$ Director            : Factor w/ 98 levels "Andrew Stanton",..: 17 80 9 64 67 95 56 19 49 28 ...

$ Actor               : Factor w/ 86 levels "Aaron Eckhart",..: 59 7 56 5 42 6 64 71 86 3 ...

您現在已經成功地在IMDb網站上爬取了2016年上映的最受歡迎的100部電影數據。 


分析從網頁上爬取到的數據

一旦您有了數據,就可以進行不少操作,如分析數據、從數據中進行推算、在獲得的數據上訓練機器學習模型等等。我已經利用我們剛爬取到的數據做了一些有趣的數據可視化。跟著這些數據可視化並回答下麵的問題。請在評論區留下您的答案,謝謝。

0?wx_fmt=jpeg 

問1:基於上麵的數據,哪種類型的電影時長最長? 

0?wx_fmt=png 

問2:基於上麵的數據,時長在130到160分鍾的電影中,哪種類型的電影最受青睞? 

0?wx_fmt=png

問3:基於上麵的數據,所有時長在100到120分鍾的電影中,哪種類型的電影收入最高? 


結語:

我相信本文將幫助您理解如何利用R語言進行網頁爬取。現在,你也許對遇到的問題和解決方案有了一些主意。由於大多數網頁上的數據是以非結構化的形式表示的,對任何一個數據科學家來說,網頁爬取都是一個極其方便帶勁的技能。

原文發布時間為:2014-04-25

本文來自雲棲社區合作夥伴“大數據文摘”,了解相關信息可以關注“BigDataDigest”微信公眾號

最後更新:2017-05-17 11:04:37

  上一篇:go  如何用Python和Google“自動化”我的婚禮?
  下一篇:go  ECMAScript對象基礎