【问题标题】:Extracting hrefs from a list in R with some missing values从R中的列表中提取具有一些缺失值的href
【发布时间】:2016-12-26 01:18:12
【问题描述】:

我热衷于将一组 jekyll 主题的源和演示 url 提取到 data.frame 中

library(rvest)

info <- read_html("https://github.com/jekyll/jekyll/wiki/themes")

data <- info %>%
 html_nodes(" #wiki-body li")

data
{xml_nodeset (115)}


[11] <li>Typewriter - (<a href="https://github.com/alixedi/typewriter">source</a>, <a href="http://alixedi.github.io/typewriter">demo</a>)</li>
[12] <li>block-log - (<a href="https://github.com/anandubajith/block-log">source</a>), <a href="https://anandu.net/demo/block-log/">demo</a>)</li>
[13] <li>Otter Pop - (<a href="https://github.com/tybenz/otter-pop">source</a>)</li>

所以我想要一个包含 3 列的 data.frame(df),例如

name        source                                       demo
Typewriter   https://github.com/alixedi/typewriter         http://alixedi.github.io/typewriter

我能够将所有 href 提取为向量,但是正如您所见,从 [13] 中某些站点没有演示,因此我遇到了困难

有没有一种简单的方法可以从数据创建 df?可能使用 purrr 库

【问题讨论】:

    标签: html r list rvest purrr


    【解决方案1】:
    data_out <- c()
    for (i in 1:length(data)) {
      row <- data.frame(html_text(data[i]), as.character(html_children(data[[i]]))[1], as.character(html_children(data[[i]]))[2])
      data_out <- rbind(data_out, row)
    }
    names(data_out) <- c("name", "source", "demo")
    data_out$name <- gsub(" - [(]source, demo[)]", "", data_out$name)
    data_out$source <- gsub("<a href=\"|\">source</a>", "", data_out$source)
    data_out$demo <- gsub("<a href=\"|\">demo</a>", "", data_out$demo)
    

    【讨论】:

    • 感谢您提供另一种选择
    【解决方案2】:

    这是你的purrr-ish 答案:

    library(rvest)
    library(purrr)
    library(dplyr)
    
    info <- read_html("https://github.com/jekyll/jekyll/wiki/themes")
    
    themes <- html_nodes(info, xpath=".//div[@class='markdown-body']/*/li")
    
    zero_to_na <- function(x) { ifelse(length(x)==0, NA, x) }
    
    df <- data_frame(name=gsub(" [- ]*\\(.*$", "", html_text(themes)),
                     source=map_chr(themes, ~html_attr(html_nodes(., xpath=".//a[contains(., 'source')]"), "href")),
                     demo=map_chr(themes, ~zero_to_na(html_attr(html_nodes(., xpath=".//a[contains(., 'demo')]"), "href"))))
    
    glimpse(df)
    ## Observations: 115
    ## Variables: 3
    ## $ name   <chr> "Jalpc", "Pixyll", "Jekyll Metro", "Midnight", "Leap Day", "F...
    ## $ source <chr> "https://github.com/Jack614/jalpc_jekyll_theme", "https://git...
    ## $ demo   <chr> "http://www.jack003.com", "http://pixyll.com/", "http://blog-...
    

    或者:

    map_df(themes, function(x) {
      data_frame(name=gsub(" [- ]*\\(.*$", "", html_text(x)),
                 source=html_attr(html_nodes(x, xpath=".//a[contains(., 'source')]"), "href"),
                 demo=zero_to_na(html_attr(html_nodes(x, xpath=".//a[contains(., 'demo')]"), "href")))
    })
    

    gsub/sub/etc 任何你不想要的“名字”部分。

    【讨论】:

    • 感谢 inc purrr 功能。这是相当的学习曲线
    【解决方案3】:

    你可以用xpath分别收集有demo数据的和没有demo数据的,把两组分开:

    withDemo <- info %>%
        html_nodes(xpath = "//li[contains(., 'source') and contains(., 'demo')]")
    
    withoutDemo <- info %>%
        html_nodes(xpath = "//li[contains(., 'source') and not(contains(.,'demo'))]")
    

    然后,使用源和演示链接为集合创建数据框:

    sourceNdemo <- withDemo %>%
        html_children() %>%              # get all children
        html_attr("href") %>%            # get the href attributes
        matrix(ncol = 2, byrow = TRUE)   # 2 pieces of data for each row
    
    sourceNdemo <- setNames(
        data.frame(html_text(withDemo), sourceNdemo),  # html_text to get "name" column
        c("name", "source", "demo"))
    

    然后,为只有源数据的数据框创建数据框

    source <- withoutDemo %>% 
        html_children() %>%
        html_attr("href")
    
    # set demo = NA for easy rbind-ing
    source <- data.frame(name = html_text(withoutDemo), source = source, demo = NA)
    

    rbind两个数据框

    allInfo <- rbind(sourceNdemo, source)
    

    “名称”列现在包含“Jalpc - (source, demo)”和“”Bitwiser-Material (source, demo)”之类的条目。您可以使用删除额外的“(source, demo)”位gsub:

    allInfo$name <- sub("\\s(-\\s)?\\(.+$", "", allInfo$name, perl = TRUE)
    

    【讨论】:

    • 这似乎是最快的方法,对于较大的输入可能是更好的选择
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多