使用RStudio调用Reddit API爬取r/coding帖子遇问题求助
问题解决:Reddit API爬取限制与时间范围无结果问题
问题原因分析
- 未使用认证令牌:代码中获取了
access_token,但后续GET请求未携带Authorization头,导致以匿名身份访问API,这类访问有严格的条数和请求次数限制。 - 数据绑定逻辑错误:直接用
rbind处理列表格式的posts会导致数据结构混乱,字段丢失或类型错误,影响后续时间过滤。 - 时间判断逻辑缺陷:循环终止条件中
any(last_post_time < start_time)会在单条帖子时间早于开始时间时直接终止,可能遗漏前面符合时间范围的帖子。 - 时间字段混淆:最后打印用了
created(本地时间),但处理时用的是created_utc(UTC时间),时间基准不一致导致过滤失效。
修正后的代码
# 安装所需包 install.packages("jsonlite") install.packages("tidyverse") install.packages("httr") # 加载所需库 library(jsonlite) library(tidyverse) library(httr) # 设置Reddit应用凭证 client_id <- "" client_secret <- "" username <- "" password <- "" user_agent <- "你的应用名称/版本 (联系邮箱)" # 必须填写规范的User-Agent # 认证并获取访问令牌 token_url <- "https://www.reddit.com/api/v1/access_token" response <- POST(token_url, body = list( grant_type = "password", username = username, password = password ), add_headers("User-Agent" = user_agent), authenticate(client_id, client_secret), encode = "form" ) # 检查认证是否成功 if (http_status(response)$category != "Success") { stop("认证失败:", content(response)$error_description) } access_token <- content(response)$access_token # 定义时间范围(统一使用UTC时间) start_time <- as.POSIXct("2022-11-01", tz = "UTC") end_time <- Sys.time() # 初始化数据存储 all_posts <- tibble() after <- "" repeat { # 发送带认证的API请求,指定每页最多获取100条(Reddit API允许的最大值) response <- GET( "https://oauth.reddit.com/r/coding/new/.json", # 使用OAuth专属端点 query = list(after = after, limit = 100), add_headers( "User-Agent" = user_agent, "Authorization" = paste("Bearer", access_token) # 携带认证令牌 ) ) # 检查响应状态 if (http_status(response)$category != "Success") { warning("请求失败:", http_status(response)$reason) break } if (http_type(response) != "application/json") { stop("错误:未获取到JSON格式数据") } data <- content(response)$data posts <- data$children$data if (length(posts) == 0) { break } # 将当前页帖子转为数据框并合并到总数据 current_posts <- bind_rows(posts) all_posts <- bind_rows(all_posts, current_posts) # 转换当前页帖子的UTC时间 current_posts$timestamp <- as.POSIXct(current_posts$created_utc, origin = "1970-01-01", tz = "UTC") # 检查当前页是否存在早于开始时间的帖子,若有则过滤后终止循环 if (any(current_posts$timestamp < start_time)) { current_posts_filtered <- current_posts[current_posts$timestamp >= start_time, ] all_posts <- bind_rows(all_posts %>% filter(timestamp >= start_time), current_posts_filtered) break } # 更新分页标记,无更多分页则终止 after <- data$after if (is.null(after)) { break } Sys.sleep(2) # 遵守API速率限制 } # 最终过滤时间范围并选择字段 filtered_posts <- all_posts %>% filter(timestamp >= start_time & timestamp <= end_time) %>% select(ups, title, subreddit, url, selftext, timestamp) # 展示结果 print(filtered_posts)
关键修正点说明
- 使用OAuth端点:请求地址改为
https://oauth.reddit.com,是认证后请求的标准端点。 - 携带认证令牌:添加
Authorization头提升访问权限,解除匿名访问的条数限制。 - 设置最大分页条数:通过
limit=100让每页返回最多100条数据,减少请求次数。 - 正确数据绑定:用
bind_rows处理列表格式帖子,避免rbind导致的结构错误。 - 优化时间终止逻辑:检查当前页所有帖子时间,仅当存在早于开始时间的帖子时,过滤后再终止,确保获取全部符合条件的内容。
- 统一时间字段:全程使用
created_utc转换的UTC时间戳,避免时间基准不一致的问题。
内容的提问来源于stack exchange,提问作者Ejudah
相关产品推荐
相关产品推荐

