如何修改R代码提取Reddit帖子全部评论并获取完整JSON?
解决Reddit帖子评论提取不全的问题
问题描述
我需要提取某Reddit帖子的全部评论,原代码仅能获取37条评论,但实际帖子有超过1000条评论。原代码及更新后的尝试如下:
原代码:
library(jsonlite) library(purrr) library(dplyr) library(tidyr) URL <- "https://www.reddit.com/r/FunnyandSad/comments/112yfey/really_surprised_how_this_didnt_become_a_big_news/.json" results = fromJSON(URL) |> pluck("data", "children") |> bind_rows() |> filter(row_number() > 1) |> unnest(data) |> select(id, author, body) |> mutate(comment_id = row_number(), .before = "id")
运行后仅得到37条评论:
> dim(results) [1] 37 4
更新后尝试用read_json:
results = read_json(URL) body_list <- list() for (i in seq_along(results[[2]]$data$children)) { body <- results[[2]]$data$children[[i]]$data$body body_list[[i]] <- body }
仍仅返回36条评论。
问题原因
Reddit的公开JSON接口默认只返回第一页的顶级评论(约25-50条),剩余评论需要通过分页参数after迭代获取;同时原代码未处理嵌套子评论,而帖子中的大量评论属于子评论层级。另外,Reddit会限制未设置User-Agent的请求,可能导致部分内容无法获取。
解决方案
1. 设置合法请求头(User-Agent)
Reddit要求请求必须包含User-Agent字段,否则可能被限流或返回不完整数据,需在请求中添加该字段。
2. 循环分页获取所有顶级评论
每次请求后,从响应中提取data$after字段,作为下一次请求的after参数,直到after为NULL(表示没有更多内容)。
3. 递归提取嵌套子评论
每条顶级评论的data$replies字段中包含其子评论,需要递归遍历所有层级的子评论。
完整代码示例
library(jsonlite) library(dplyr) library(purrr) # 定义请求URL和请求头 base_url <- "https://www.reddit.com/r/FunnyandSad/comments/112yfey/really_surprised_how_this_didnt_become_a_big_news/.json" headers <- c("User-Agent" = "R script for comment scraping (by u/your_username)") # 递归提取所有层级的评论(包括子评论) extract_comments <- function(comment_data) { # 提取当前层级的评论 current_comments <- comment_data |> map_dfr(~{ data <- .x$data tibble( id = data$id, author = data$author, body = data$body, parent_id = data$parent_id, depth = data$depth ) }) # 提取子评论并递归处理 child_comments <- comment_data |> map(~.x$data$replies) |> keep(~!is.null(.x)) |> map(~.x$data$children) |> map_dfr(extract_comments) # 合并当前评论和子评论 bind_rows(current_comments, child_comments) } # 循环分页获取所有评论 all_comments <- tibble() after <- NULL while(TRUE) { # 构建带分页参数的URL request_url <- if(is.null(after)) { base_url } else { paste0(base_url, "?after=", after) } # 发送请求 response <- fromJSON(request_url, headers = headers) # 提取评论部分(response[[2]]是评论区数据) comment_children <- response[[2]]$data$children # 如果没有更多评论,退出循环 if(length(comment_children) == 0) break # 提取当前页的所有评论(包括子评论) page_comments <- extract_comments(comment_children) # 合并到总结果 all_comments <- bind_rows(all_comments, page_comments) # 更新after参数,用于下一页请求 after <- response[[2]]$data$after # 如果after为NULL,说明没有更多内容 if(is.null(after)) break # 加个延迟,避免触发Reddit限流 Sys.sleep(2) } # 查看结果 dim(all_comments) head(all_comments)
说明
User-Agent需要替换为你自己的标识(比如你的Reddit用户名),避免被Reddit判定为恶意请求。Sys.sleep(2)是为了在请求之间添加延迟,遵守Reddit的API速率限制,避免频繁请求被封禁。extract_comments函数会递归遍历所有子评论层级,确保获取到帖子中的所有评论。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

