1. 程式人生 > >R網頁抓取資料

R網頁抓取資料


R網頁抓取資料

web上有大量可用的資料。其中一些是以格式化的、可下載的data-sets的形式,易於訪問。但大多數線上資料都是作為網路內容存在的,如部落格、新聞故事和烹飪菜譜。使用格式化的檔案,訪問資料相當簡單;只需下載檔案,必要時解壓縮,然後匯入到r
然而,對於“wild”資料,將資料轉換成可分析的格式更困難。訪問此類的線上資料有時稱為“web抓取。您將需要從網際網路下載目標頁面並提取您需要的資訊。兩個r工具,從基本包中的readline ( )rcurl包中的geturl ()使此任務成為可能。

Readlines

對於基本的web抓取任務,readline ()函式通常就足夠了。readline ()
允許對非安全伺服器上的網頁源資料進行簡單訪問。在最簡單的形式中,readline ( )接受一個引數要讀取的web頁面的URL :
web_page <- readLines("http://www.interestingwebsite.com")

作為一個(有點)實際使用web抓取的例子,設想一個場景,我們想知道20091月的r -help伺服器上的10個最常見的海報。因為伺服器是在一個安全的站點上(例如,它有https : / /而不是http : / /URL),我們不能輕鬆地使用readline ()訪問live版本。因此,對於此示例,我已在此站點上釋出了列表歸檔的本地副本。
readline ()其本身只能獲取資料。您將需要使用

grep ( )gsub ()或等價物來解析資料並保留您所需要的內容。web抓取中的一個關鍵挑戰是找到一種方法,從包含其他元素的網頁中開啟所需的資料。

web_page <- read.csv("http://www.programmingr.com/jan09rlist.html")
author_lines <- web_page[grep("<I>", web_page)]
authors <- gsub("<I>", "", author_lines, fixed = TRUE)
author_counts <- sort(table(authors), decreasing = TRUE)
author_counts[1:10]

為了理解為什麼這個示例如此簡單,下面是對底層html的更深入的瞭解:

老實說,這是關於使用者友好,因為您可以得到的html資料格式的在野外。我們感興趣的資料元素(海報名稱)是它自己行的主要元素。我們可以使用grep ()快速輕鬆地獲取這些行。一旦我們有了我們感興趣的行,我們可以通過使用gsub ()來替換不需要的html程式碼。
順便說一句,對於那些也是web開發人員的人來說,這可能是重複任務的一個巨大的節省時間。如果您沒有處理任何高度敏感的問題,請向您的站點新增一些簡單的資料轉儲頁面,並使用readline ()在您需要的時候撤回資料。這對於進度報告和狀態更新非常重要。確保頁面設計簡單——基本的、格式良好的html和最小的絨毛。
在找一個測試專案嗎?檢視我們的網頁抓取專案的想法!

rcurl包

為了獲得更高階的http功能(post功能和https訪問),您需要使用rcurl包。要使用rcurl包執行web抓取任務,請使用geturl ()函式。在通過geturl ()獲取資料之後,需要對它進行重組和解析。XML包中的htmltreeparse ()函式是專門為這個任務定製的。使用geturl ()我們可以訪問一個安全的站點,因此我們可以使用實時站點作為示例。
# Install the RCurl package if necessary
install.packages("RCurl", dependencies = TRUE)
library("RCurl")

# Install the XML package if necessary
install.packages("XML", dependencies = TRUE)
library("XML")

# Get first quarter archives
jan09 <- getURL("https://stat.ethz.ch/pipermail/r-help/2009-January/date.html", ssl.verifypeer = FALSE)

jan09_parsed <- htmlTreeParse(jan09)

對於基本的web抓取任務readline ()將足夠並避免使任務複雜化。對於更困難的程式或需要其他http功能geturl ()rcurl包中的其他功能的任務,可能需要。這是我們在網上抓取的系列中的第一個。請檢視後面的一篇文章,瞭解有關抓取的更多資訊:

1.json

json已經成為在web上共享資料的通用標準之一,特別是可能被前端JavaScript應用程式使用的資料。json ( JavaScriptobject符號)是一個關鍵的:值格式,它為讀者提供了一個關於價值的含義的高度的上下文。鍵-值結構可以巢狀,允許如下資料分組:

{‘book’:”Midsummer Nights Dream”,
‘author’: “William Shakespeare”,
‘price’:5.99,
‘inventory’:12}

對於已經出現了幾個用於r使用者的庫,使您能夠輕鬆地處理和消化json資料。我們將從其中一個庫jsonlite提供一個示例,它是另一個領先庫rjsonio的分叉。我們選擇了這個圖書館,由於它的相對易用性。我們從預賽開始,因為jsonlite不作為r標準庫的一部分:

json_file <- "https://jsonplaceholder.typicode.com/posts"

data <- fromJSON(json_file)

我們將使用一個用於JSON資料的佔位符生成器:https : / / www . jsonplaceholder.typicode.com . org/帖子.這個服務列出了一個錯誤的JSON資料列表,據稱是一個部落格文章或新聞文章的列表。將這些資訊移動到r資料幀相當簡單它為我們提供了一個具有要求的欄位的可愛的資料幀。對於喜歡在文字編輯器或excel中瀏覽資料的人,您可以輕鬆地將檔案轉儲到CSV檔案,並使用以下一個線性檔案:該包可以支援更高階的資料檢索,包括:

訪問需要金鑰的API提取並連線到單個數據幀中的多頁劃痕使用複雜的標頭和資料元素的post請求操作這裡詳細介紹了一組示例(由包作者提供)

本節列出了以JSON格式釋出資料的公共httpAPI的一些示例。這些是很好的,以瞭解在真實的世界JSON資料中遇到的複雜結構。所有服務都是免費的,但有些服務需要註冊/身份驗證。每個示例返回大量資料,因此不是所有輸出都在本文件中列印。

library(jsonlite)

github

github是一個線上程式碼儲存庫,並具有幾乎所有活動的APIs來獲取實時資料。下面是一個著名的r包和作者的一些例子:

hadley_orgs <- fromJSON("https://api.github.com/users/hadley/orgs")

hadley_repos <- fromJSON("https://api.github.com/users/hadley/repos")

gg_commits <- fromJSON("https://api.github.com/repos/hadley/ggplot2/commits")

gg_issues <- fromJSON("https://api.github.com/repos/hadley/ggplot2/issues")

#latest issues

paste(format(gg_issues$user$login), ":", gg_issues$title)

[1] "jsta            : fix broken stowers link"                                         

[2] "krlmlr          : Log transform on geom_bar() silently omits layer"                  

[3] "yutannihilation : Fix a broken link in README"                                   

[4] "raubreywhite    : Fix theme_gray's legend/panels for large base_size"               

[5] "batuff          : Add minor ticks to axes"                                        

[6] "mcol            : overlapping boxes with geom_boxplot(varwidth=TRUE)"            

[7] "karawoo         : Fix density calculations for groups with one or two elements"        [8] "Thieffen        : fix typo"                                 

[9] "Thieffen        : fix typo"                                                     

[10] "thjwong         : `axis.line` works, but not `axis.line.x` and `axis.line.y`"            

[11] "schloerke       : scale_discrete not listening to 'breaks' arg"                         

[12] "hadley          : Consider use of vwline"                                         

[13] "JTapper         : geom_polygon accessing data$y"                                  

[14] "Ax3man          : Added linejoin parameter to geom_segment."                      

[15] "LSanselme       : geom_density with groups of 1 or 2 elements"                     

[16] "philstraforelli : (feature request) Changing facet_wrap strip colour based on variable in data frame"    

[17] "eliocamp        : geom_tile() + coord_map() is extremely slow."                     

[18] "eliocamp        : facet_wrap() doesn't play well with expressions in facets. "        

[19] "dantonnoriega   : Request: Quick visual example for each geom at http://ggplot2.tidyverse.org/reference/"

[20] "randomgambit    : it would be nice to have date_breaks('0.2 sec')"                    

[21] "adrfantini      : Labels can overlap in coord_sf()"                                   

[22] "adrfantini      : borders() is incompatible with coord_sf() with projected coordinates"    

[23] "adrfantini      : coord_proj() is superior to coord_map() and could be included in the default ggplot"   

[24] "adrfantini      : Coordinates labels and gridlines are wrong in coord_map()"           

[25] "jonocarroll     : Minor typo: monotonous -> monotonic"                            

[26] "FabianRoger     : label.size in geom_label is ignored when printing to pdf"             

[27] "andrewdolman    : Add note recommending annotate"                              

[28] "Henrik-P        : scale_identity doesn't play well with guide = \"legend\""           

[29] "cpsievert       : stat_sf(geom = \"text\")"                                        

[30] "hadley          : Automatically fill in x for univariate boxplot"     

一個單一的公共API,顯示了紐約市自行車共享模擬的所有站點的位置、狀態和當前可用性。

citibike <- fromJSON("http://citibikenyc.com/stations/json")stations <- citibike$stationBeanListcolnames(stations)

 [1] "id"                    "stationName"          

 [3] "availableDocks"        "totalDocks"           

 [5] "latitude"              "longitude"            

 [7] "statusValue"           "statusKey"            

 [9] "availableBikes"        "stAddress1"           

[11] "stAddress2"            "city"                 

[13] "postalCode"            "location"             

[15] "altitude"              "testStation"          

[17] "lastCommunicationTime" "landMark"             

nrow(stations)

[1] 666

ergast

ergast開發人員API是一種實驗性的web服務,它為非商業目的提供了關於賽車資料的歷史記錄。
res <- fromJSON('http://ergast.com/api/f1/2004/1/results.json')drivers <- res$MRData$RaceTable$Races$Results[[1]]$Drivercolnames(drivers)

[1] "driverId"        "code"            "url"             "givenName"      

[5] "familyName"      "dateOfBirth"     "nationality"     "permanentNumber"

drivers[1:10, c("givenName", "familyName", "code", "nationality")]

   givenName    familyName code nationality

1    Michael    Schumacher  MSC      German

2     Rubens   Barrichello  BAR   Brazilian

3   Fernando        Alonso  ALO     Spanish

4       Ralf    Schumacher  SCH      German

5       Juan Pablo Montoya  MON   Colombian

6     Jenson        Button  BUT     British

7      Jarno        Trulli  TRU     Italian

8      David     Coulthard  COU     British

9     Takuma          Sato  SAT    Japanese

10 Giancarlo    Fisichella  FIS     Italian

propublica

下面是propublica非營利的探索者API的一個例子,我們在那裡檢索了美國的第一個10頁的免稅組織,由收入訂購。rbind _pages函式用於將頁面組合成單個數據幀。
#store all pages in a list firs

tbaseurl <- "https://projects.propublica.org/nonprofits/api/v1/search.json?order=revenue&sort_order=desc"

pages <- list()for(i in 0:10){

mydata <- fromJSON(paste0(baseurl, "&page=", i), flatten=TRUE)

message("Retrieving page ", i)

pages[[i+1]] <- mydata$filings}

#combine all into one

filings <- rbind_pages(pages)

#check outputnrow(filings)

[1] 275

filings[1:10, c("organization.sub_name", "organization.city", "totrevenue")]

               organization.sub_name organization.city  totrevenue

1  KAISER FOUNDATION HEALTH PLAN INC           OAKLAND 40148558254

2  KAISER FOUNDATION HEALTH PLAN INC           OAKLAND 37786011714

3        KAISER FOUNDATION HOSPITALS           OAKLAND 20796549014

4        KAISER FOUNDATION HOSPITALS           OAKLAND 17980030355

5    PARTNERS HEALTHCARE SYSTEM INC         SOMERVILLE 10619215354

6                              UPMC         PITTSBURGH 10098163008

7    UAW RETIREE MEDICAL BENEFITS TR           DETROIT  9890722789

8   THRIVENT FINANCIAL FOR LUTHERANS       MINNEAPOLIS  9475129863

9   THRIVENT FINANCIAL FOR LUTHERANS       MINNEAPOLIS  9021585970

10                    DIGNITY HEALTH     SAN FRANCISCO  8718896265

紐約時報

《紐約時報》作為紐約時報開發者網路的一部分,有幾個API。這些介面與來自不同部門的資料,如新聞文章、書評、房地產等。需要註冊(但免費),在這裡可以獲得一個金鑰。下面的程式碼包括一些用於說明目的的示例鍵。
search for articles

article_key <- "&api-key=b75da00e12d54774a2d362adddcc9bef"

url <- "http://api.nytimes.com/svc/search/v2/articlesearch.json?q=obamacare+socialism"

req <- fromJSON(paste0(url, article_key))

articles <- req$response$docscolnames(articles)

 [1] "web_url"           "snippet"           "lead_paragraph"   

 [4] "abstract"          "print_page"        "blog"             

 [7] "source"            "multimedia"        "headline"         

[10] "keywords"          "pub_date"          "document_type"    

[13] "news_desk"         "section_name"      "subsection_name"  

[16] "byline"            "type_of_material"  "_id"              

[19] "word_count"        "slideshow_credits"

#search for best sellers

books_key <- "&api-key=76363c9e70bc401bac1e6ad88b13bd1d"

url <- "http://api.nytimes.com/svc/books/v2/lists/overview.json?published_date=2013-01-01"

req <- fromJSON(paste0(url, books_key))

bestsellers <- req$results$list

category1 <- bestsellers[[1, "books"]]

subset(category1, select = c("author", "title", "publisher"))

           author                title                  publisher

1   Gillian Flynn            GONE GIRL           Crown Publishing

2    John Grisham        THE RACKETEER Knopf Doubleday Publishing

3       E L James FIFTY SHADES OF GREY Knopf Doubleday Publishing

4 Nicholas Sparks           SAFE HAVEN   Grand Central Publishing

5  David Baldacci        THE FORGOTTEN   Grand Central Publishing

#movie reviews

movie_key <- "&api-key=b75da00e12d54774a2d362adddcc9bef"

url <- "http://api.nytimes.com/svc/movies/v2/reviews/dvd-picks.json?order=by-date"

req <- fromJSON(paste0(url, movie_key))

reviews <- req$resultscolnames(reviews)

 [1] "display_title"    "mpaa_rating"      "critics_pick"    

 [4] "byline"           "headline"         "summary_short"   

 [7] "publication_date" "opening_date"     "date_updated"    

[10] "link"             "multimedia"      

reviews[1:5, c("display_title", "byline", "mpaa_rating")]

                    display_title            byline mpaa_rating

1                 Hermia & Helena       GLENN KENNY            

2             The Women's Balcony NICOLE HERRINGTON            

3               Long Strange Trip    DANIEL M. GOLD           R

4 Joshua: Teenager vs. Superpower    KEN JAWOROWSKI            

5                 Berlin Syndrome       GLENN KENNY           R

陽光基金會

陽光基金會是一個非營利組織,有助於通過資料、工具、政策和新聞工作使政府透明和負責。在這裡註冊一個免費鑰匙。提供了一個示例金鑰。

key <- "&apikey=39c83d5a4acc42be993ee637e2e4ba3d"

key <- "&apikey=39c83d5a4acc42be993ee637e2e4ba3d"
#Find bills about drones

Twitter

TwitterAPI需要oauth2身份驗證。一些示例程式碼:

#Create your own appication key at https://dev.twitter.com/apps

consumer_key = "EZRy5JzOH2QQmVAe9B4j2w";

consumer_secret = "OIDC4MdfZJ82nbwpZfoUO4WOLTYjoRhpHRAWj6JMec";

#Use basic auth

secret <- jsonlite::base64_enc(paste(consumer_key, consumer_secret, sep = ":"))

req <- httr::POST("https://api.twitter.com/oauth2/token",httr::add_headers(

    "Authorization" = paste("Basic", gsub("\n", "", secret)),

    "Content-Type" = "application/x-www-form-urlencoded;charset=UTF-8"),

body = "grant_type=client_credentials");

#Extract the access token

httr::stop_for_status(req, "authenticate with twitter")

token <- paste("Bearer", httr::content(req)$access_token)

#Actual API call

url <- "https://api.twitter.com/1.1/statuses/user_timeline.json?count=10&screen_name=Rbloggers"

req <- httr::GET(url, httr::add_headers(Authorization = token))

json <- httr::content(req, as = "text")

tweets <- fromJSON(json)substring(tweets$text, 1, 100)

[1] "simmer 3.6.2 https://t.co/rRxgY2Ypfa #rstats #DataScience"                            [2] "Getting data for every Census tract in the US with purrr and tidycensus https://t.co/B3NYJS8sLO #rst"

[3] "Gender Roles with Text Mining and N-grams https://t.co/Rwj0IaTiAR #rstats #DataScience" [4] "Data Science Podcasts https://t.co/SaAuO82a7M #rstats #DataScience"                    [5] "Reflections on ROpenSci Unconference 2017 https://t.co/87kMldvrsd #rstats #DataScience"   [6] "Summarizing big data in R https://t.co/GMaZZ9sWiL #rstats #DataScience"               [7] "Mining CRAN DESCRIPTION Files https://t.co/gWEIAYaBZF #rstats #DataScience"       [8] "New package polypoly (helper functions for orthogonal polynomials) https://t.co/MzzzcIySym #rstats #"

 [9] "Hospital Infection Scores – R Shiny App https://t.co/Rf8wKNBPU6 #rstats #DataScience"  [10] "New R job: Software Engineer in Test for RStudio https://t.co/X1bWkKlzYv #rstats #DataScience #jobs"