我在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]]
包含与网址上的第一条评论相对应的属性,而replies
包含有关第二条评论的回复的信息。我们可以通过查看replies$data$children
找到这些回复。但是回复可以嵌套在另一个回复中,这就是为什么要得到它们,我们需要递归地解析树。
下表列出了评论的结构以及我想要获得的输出:
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
请注意,如果重新运行,数字可能会更改 - 此数据是动态的。
然而,这种方法不包含整个线程的历史记录,它只告诉我们某个节点可能有多少回复,无论它是原始注释还是对回复的回复。
如果有人对如何提出任何建议,请告诉我,我很乐意听取您的意见。
非常感谢!
答案 0 :(得分:1)
我会避免递归,只需使用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
答案 1 :(得分:1)
以下是使用previously answered rjson 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"
我们可以通过终端空间进行拆分,并获取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