【问题标题】:Creating a new column in RVest based on a cascading variable基于级联变量在 RVest 中创建新列
【发布时间】:2021-02-25 20:22:51
【问题描述】:

我正在使用rvest 编写一个数据抓取工具,如下所示:

library(tidyverse)
library(rvest)
library(magrittr)
library(dplyr)
library(tidyr)
library(data.table)
library(zoo)

targets_url <- paste0("https://247sports.com/college/ohio-state/Season/2021-Football/Targets/")

targets <- map_df(targets_url, ~.x %>% read_html %>%
                          html_nodes(".ri-page__star-and-score .score , .position , .meta , .ri-page__name-link") %>%
                          html_text() %>% 
                          str_trim %>% 
                          str_split("   ") %>% 
                          matrix(ncol = 4, byrow = T) %>% 
                          as.data.frame)

df_structure <- apply(targets,2,as.character)

df_targets <- as.data.frame(df_structure) 

您会注意到它创建了一个包含四个变量和 53 行的数据框。

但是现在转到 URL 本身。您会注意到 53 行对应于某些子类别:Top Target、High Choice 和 Interested。这是一张显示示例的图片:

我要做的是创建第五列,其中包含子类别。因此,例如,属于“最高目标”的三个人将被分配另一列,将他们列为“最高目标”。然后接下来的 20 行将第五列读取为“高选择”,依此类推。我在这里的原因是因为我不知道该怎么做。更难的是,并非每一页都有相同的数字here's an example of that。您会看到,虽然上面的图片仅列出了 Top Target (3),但此页面现在有 Top Target (24)。每个页面都不同。

是否有可能改变我原来的脚本:

A) 使用我上面提到的子类别创建第五列

B) 知道什么时候应该切换到下一个子类别

C) 与每个子类别中的总人数无关

部分基于@Dave2e 答案的编辑脚本:

library(rvest)
library(dplyr)
library(stringr)

teams <- c("ohio-state","penn-state","michigan","michigan-state")

targets_url <- paste0("https://247sports.com/college/", teams, "/Season/2021-Football/Targets/")
# read the web page once! then extract the information requested

targets <- map_df(targets_url, ~.x %>% read_html %>%
                    html_nodes(".ri-page__star-and-score .score , .position , .meta , .ri-page__name-link") %>%
                    html_text() %>% 
                    str_trim %>% 
                    str_split("   ") %>% 
                    matrix(ncol = 4, byrow = T) %>% 
                    as.data.frame)

#find the headings and the players
list <- page %>% html_nodes("li.ri-page__list-item")
headers <- which(html_attr(list, "class") == "ri-page__list-item list-header")
#find the category
category <- list[headers] %>% html_node("b.name") %>% html_text()

#extract repeats from header
nrepeats<-as.integer(str_extract(category, "[0-9]+"))

categories <- rep(category, nrepeats)[1:nrow(targets)]
#create combined dataframe
answer <- cbind(categories, targets)

【问题讨论】:

    标签: r web-scraping tidyverse rvest


    【解决方案1】:

    标题位于具有 class="ri-page__list-item list-header" 的“li”节点。注意标题包含该标题下方的玩家数量也很方便。
    此脚本查找标题节点,提取玩家数量,然后创建重复标题向量以合并到目标数据帧。

    library(rvest)
    library(dplyr)
    library(stringr)
    
    targets_url <- paste0("https://247sports.com/college/ohio-state/Season/2021-Football/Targets/")
    # read the web page once! then extract the information requested
    page <- read_html(targets_url)
    
    targets <- page %>%
                html_nodes(".ri-page__star-and-score .score , .position , .meta , .ri-page__name-link") %>%
                 html_text() %>% 
                 str_trim %>% 
                 str_split("   ") %>% 
                 matrix(ncol = 4, byrow = T) %>% 
                 as.data.frame
    
    #find the headings and the players
    list <- page %>% html_nodes("li.ri-page__list-item")
    headers <- which(html_attr(list, "class") == "ri-page__list-item list-header")
    #find the category
    category <- list[headers] %>% html_node("b.name") %>% html_text()
    
    #extract repeats from header
    nrepeats<-as.integer(str_extract(category, "[0-9]+"))
    
    categories <- rep(category, nrepeats)[1:nrow(targets)]
    #create combined dataframe
    answer <- cbind(categories, targets)
    

    更新 - 寻找隐藏数据
    如果列表太长,网页会动态隐藏一些信息。应对现在可以处理该信息。下面的代码找到隐藏的 JSON 数据(包含在“脚本”节点中并解析该数据。它确实返回了一个玩家列表,但不是所有相同的信息。

    #another option
    #find the hidden JSON data
    jsons <- page %>%   html_nodes(xpath = '//*[@type ="application/ld+json"]') 
    allplayers <- jsonlite::fromJSON( html_text(jsons[2]))
    #Similar list, provide URL to each players webpage
    answer2 <- cbind(rep(category, nrepeats), allplayers$athlete)
    

    【讨论】:

    • 这是出色的工作。太感谢了。还有一个问题:如果我用247sports.com/college/penn-state/Season/2021-Football/Targets 切换URL,它会出错。对那里发生的事情有任何见解吗?
    • 作为一名 PSU 校友,我应该从这里开始。该错误是由于列表末尾的名称未显示在初始页面加载中。数据隐藏在页面上。解决方案是以太缩短rep(category, nrepeats) 和/或访问隐藏数据。请参阅上面的更新。另一个选择是 RSelenium。
    • 非常感谢您的帮助。我还有一个问题。查看我编辑的答案。您会注意到我正在将多个团队映射到脚本。虽然它运行没有错误,但您会注意到它只列出了列表中第一个团队的“类别”。为什么这样做?此外,关于如何添加另一列列出它所属的团队的任何建议(所以如果他在俄亥俄州立大学页面链接上,它会说“俄亥俄州立大学”,如果它在宾夕法尼亚州立大学页面上,它会说“Penn州”等...)如果名称重复也没关系,可以将名称附加到多个页面。
    • 我会做什么:将我的整个解决方案封装在一个以团队名称作为参数的函数中。让函数创建 URL 并生成结果的 data.frame,然后在从函数返回数据框之前添加团队名称作为额外的列。使用lapply 或“purrr”调用该函数。结果应该是一个数据框列表,您可以使用bind_rows() 创建最终的大数据框。
    • 另外请注意,我只将网页读入变量“page”并对其进行解析。您的代码正在使用“targets_url”和未定义的变量“page”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 2015-08-01
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 2023-02-01
    相关资源
    最近更新 更多