当使用 'rvest' 在 R 中进行 Web 抓取时,基于特定行信息将其他变量合并到数据的最佳做法是什么?
What would be the best practice to merge additional variables to data based on specific row information when web scraping in R using 'rvest'?
我目前正在抓取 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)
我将有带有标题和 links 的电影 DT 作为列。
现在,我想使用 links
提取每部电影的附加数据
我继续以第一行为例
#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 table
我想为每部 link 电影提取数据并将其合并到 DT 中以得到一个包含 6 列的最终 DT; 'title', 'link' + 四个预算变量。我试图创建一个函数,其中包含使用每一行的 link 作为参数并使用 'lapply' 获取预算数据的代码,我认为这不是正确的方法。
我想看看您是否有有效的解决方案。
非常感谢您的帮助。
我认为这可以解决您的问题:
# 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
不需要 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
.
我目前正在抓取 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)
我将有带有标题和 links 的电影 DT 作为列。
现在,我想使用 links
提取每部电影的附加数据我继续以第一行为例
#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 table
我想为每部 link 电影提取数据并将其合并到 DT 中以得到一个包含 6 列的最终 DT; 'title', 'link' + 四个预算变量。我试图创建一个函数,其中包含使用每一行的 link 作为参数并使用 'lapply' 获取预算数据的代码,我认为这不是正确的方法。
我想看看您是否有有效的解决方案。
非常感谢您的帮助。
我认为这可以解决您的问题:
# 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
不需要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
.