首页 > 解决方案 > 使用“rvest”在 R 中进行网络抓取时,将其他变量合并到基于特定行信息的数据的最佳实践是什么?

问题描述

我目前正在网上抓取 IMDB 网站以提取电影数据。

我想知道你将如何解决这个问题。

library(tidyverse)
library(data.table)
library(rvest)
library(janitor)

#top rated movies website 
url <- 'https://www.imdb.com/chart/top/?ref_=nv_mv_250'

# extract the title of the movies using rvest

titles <- url %>%
  read_html() %>%
  html_nodes(' .titleColumn a') %>%
  html_text() %>%
  as.data.table() %>%
  setnames(. ,old = colnames(.), new='title') 

# extract links to each of the titles, this will be the reference 

links <- url %>%
  read_html() %>%
  html_nodes('.titleColumn a') %>%
  html_attr('href') %>%
  as.data.table() %>%
  setnames(. ,old = colnames(.), new='links') 

# creating a DT with the data

movies <- cbind(titles,links)

我将有带有标题和链接的电影 DT 作为列。

现在,我想使用链接提取每部电影的附加数据

我将继续以第一行为例。


#the first link in movies  

link <- 'https://www.imdb.com/title/tt0111161/?pf_rd_m=A2FGELUUNOQJNL&pf_rd_p=e31d89dd-322d-4646-8962-327b42fe94b1&pf_rd_r=NJ52X0MM1V9FKSPBT46G&pf_rd_s=center-1&pf_rd_t=15506&pf_rd_i=top&ref_=chttp_tt_1'

# selector for budget data (this will not change)

select <- '.txt-block:nth-child(15) , .txt-block:nth-child(14) , #titleDetails .txt-block:nth-child(13) , #titleDetails .txt-block:nth-child(12)'


# get budget data

budget <- link %>%
  read_html() %>%
  html_nodes(select) %>%
  html_text() %>%
  gsub('\\n','',.) %>%
  str_split(.,'\\:')%>%
  as.data.table() %>%
  janitor::row_to_names(row_number = 1) %>%
  setnames(.,old=colnames(.),new= tolower(gsub(' ','_' , str_trim(colnames(.)))))

budget[,(colnames(budget))] <- lapply(budget,function(x) str_extract_all(x, "(\\$) *([0-9,]+)"))

现在我有一个包含预算信息的 1x4 表

我想为电影的每个链接提取数据并将其合并到 DT 中,以获得具有 6 列的最终 DT;'title', 'link' + 四个预算变量。我试图创建一个函数,其中包含使用每一行的链接作为参数并使用“lapply”获取预算数据的代码,我认为这不是正确的方法。

我想看看您是否有有效的解决方案。

非常感谢你的帮助。

标签: rweb-scrapingdata.tableapplyrvest

解决方案


我认为这可以解决您的问题:

# selector for budget data (this will not change)
select <- '.txt-block:nth-child(15) , .txt-block:nth-child(14) , #titleDetails .txt-block:nth-child(13) , #titleDetails .txt-block:nth-child(12)'

# get budget data
## As function
get_budget = function(link,select){
budget <- link %>%
  read_html() %>%
  html_nodes(select) %>%
  html_text() %>%
  gsub('\\n','',.) %>%
  str_split(.,'\\:')%>%
  as.data.table() %>%
  janitor::row_to_names(row_number = 1) %>%
  setnames(.,old=colnames(.),new= tolower(gsub(' ','_' , str_trim(colnames(.)))))

budget[,(colnames(budget))] <- lapply(budget,function(x) str_extract_all(x, "(\\$) *([0-9,]+)"))
return(budget)
}

#As your code is slow I'll subset movies to have 10 rows:
movies = movies[1:10,]
tmp = 
lapply(movies[, links], function(x) 
  get_budget(link = paste0("https://www.imdb.com/",x),select=select )) %>% 
  rbindlist(., fill = T)

movies = cbind(movies, tmp)

你的结果看起来像这样:movies_result

最后,我认为这个小建议会让你的代码看起来更酷:

  • setnames不需要.from magrittr; 它会自动理解您的代码类型。
  • 尽可能避免使用setnames(. ,old = colnames(.), new='links'). 在您的情况下是必要的setnames('links'),因为您正在重命名所有变量。
  • setnames(dt,old = oldnames, new=newnames)仅当 oldnames 不等于 names(dt) 时才需要。
  • 由于DT是另一个R流行的库,与data.table我认为将 data.table 称为什么是data.table.

推荐阅读