R中的递归JSON树索引提取

Recursive JSON tree index extraction in R

我在提取 R 中 JSON 树的结构时遇到困难。

考虑以下场景(从 Reddit.com 中提取数据):

library(RJSON)
URL = "http://www.reddit.com/r/newzealand/comments/3p25qy/where_can_i_get_a_chromecast_2/"

X = paste0(gsub("\?ref=search_posts$","",URL),".json?limit=500")
raw_data = fromJSON(readLines(X, warn = FALSE))
main.node = raw_data[[2]]$data$children
replies = main.node[[2]]$data$replies
node = replies$data$children

现在 main.node[[1]] 包含与 URL 上的第一条评论相对应的属性,而 replies 包含有关对第二条评论的回复的信息。我们可以通过查看 replies$data$children 找到这些回复。但是一个回复可以嵌套在另一个回复中,这就是为什么要得到它们,我们需要递归地解析树。

下面的table表示评论的结构以及我试图获得的输出:

row  comment | reply_to_comment | reply_to_reply | desired_output
1)   *       |                  |                | 1
2)           | *                |                | 1.1
3)           | *                |                | 1.2
4)           |                  | *              | 1.2.1
5)           |                  | *              | 1.2.2
6)           | *                |                | 1.3
7)   *       |                  |                | 2
8)           | *                |                | 2.1
9)           |                  | *              | 2.1.1

到目前为止我能得到的最接近的代码由以下代码表示:

 node = main.node
reply_function = function(node){
  struct   = seq_along(node) 
  replies  = node$data$replies
  rep.node = if (is.list(replies)) replies$data$children else NULL
  return(list(struct,lapply(rep.node,function(x) reply_function(x))))
}
[1]  1 2 1 2 1 2 1 2 1 2 1 2 1 2

请注意,如果您重新运行,数字可能会发生变化 -- 此数据是动态的。

然而,这种方法不包含整个线程的历史,它只告诉我们某个节点可能有多少回复,而不管它是原始评论还是对回复的回复。

如果有人对此有任何建议,请告诉我,我很乐意听取您的意见。

非常感谢!

我会避开递归,只使用 unlist,例如:

library(jsonlite)
URL = "http://www.reddit.com/r/newzealand/comments/3p25qy/where_can_i_get_a_chromecast_2/"
X = paste0(gsub("\?ref=search_posts$","",URL),".json?limit=500")
raw_data = fromJSON(readLines(X, warn = FALSE))
data = unlist(raw_data)
comments = names(data)[grepl('\.body$', names(data))]
comments = data[comments]
names(comments) <- NULL
comments

这是一个使用 previously answered rjson reader.

修改版本的方法

首先,我们可以修改之前的递归reader来记录它在哪一层:

get.comments <- function(node, depth=0) {
  if(is.null(node)) {return(list())}
  comment     <- node$data$body
  replies     <- node$data$replies
  reply.nodes <- if (is.list(replies)) replies$data$children else NULL
  return(list(paste0(comment, " ", depth), lapply(1:length(reply.nodes), function(x) get.comments(reply.nodes[[x]], paste0(depth, ".", x)))))
}

现在读取您的数据:

library(rjson)
URL = "http://www.reddit.com/r/newzealand/comments/3p25qy/where_can_i_get_a_chromecast_2/"
X = paste0(gsub("\?ref=search_posts$","",URL),".json?limit=500")
rawdat    <- fromJSON(readLines(X, warn = FALSE))
main.node <- rawdat[[2]]$data$children

然后递归应用函数并取消列出:

txt <- unlist(lapply(1:length(main.node), function(x) get.comments(main.node[[x]], x)))

现在txt是评论的一个向量,级别在最后。例如

"Holy fuck, thank you! Didn't realise this was actually a thing.\n\nfreeeedom 1.1" 

我们可以通过终端space拆分,得到data.frame:

z<-as.data.frame(do.call(rbind, strsplit(txt, ' (?=[^ ]+$)', perl = TRUE)))

       V2
1       1
2     1.1
3   1.1.1
4 1.1.1.1
5       2
6       3
7       4
8     4.1
9     4.2