R语言爬虫函数生成重复数据的原因排查及优化方案咨询
问题分析与解决方案
首先,咱们先拆解一下你遇到的重复数据问题:向量追加本身并不是重复的直接原因,但你的代码逻辑和TripAdvisor的分页机制可能共同导致了重复。让我们一步步梳理:
为什么会出现重复数据?
- TripAdvisor的分页重叠:最可能的原因是平台的分页逻辑——某些评论可能会出现在多个页码中(比如滚动加载的冗余设计,或者分页参数
or{n}的边界处理问题)。你的代码只是忠实地爬取了每个页面的内容,自然会把重复的评论也抓进来。 - 重复读取页面:你的函数里对同一个URL调用了两次
read_html()(一次抓reviews,一次抓rating),虽然大概率不会导致重复,但可能因网络波动或页面动态内容加载的差异,出现不必要的重复抓取风险。 - 全局变量的隐患:用
<<-赋值全局变量tripadvisor,如果多次运行函数,旧数据不会被清空,会直接追加到已有数据上,这也可能造成重复(不过你说的是单次运行后出现重复,这个可能不是主因)。
最优解决思路
核心是基于评论唯一ID去重,同时优化代码的效率和可读性:
1. 先验证重复来源
在修改代码前,先确认重复的评论是否跨页面出现:
for (url in tripadvisor_urls) { page <- read_html(url) review_ids <- page %>% html_nodes("#REVIEWS .quote a") %>% html_attr("id") cat(sprintf("URL: %s\n评论ID: %s\n\n", url, paste(review_ids, collapse = ", "))) }
如果看到同一个ID出现在多个URL里,就坐实了分页重叠的问题。
2. 改进后的完整代码
我重构了你的函数,解决了重复问题+优化了性能:
library(xml2) library(rvest) library(dplyr) library(stringr) # 用sprintf生成URL,比paste更简洁 tripadvisor_urls <- sprintf( "https://www.tripadvisor.co.uk/Attraction_Review-g186306-d9756771-Reviews-or%d-Suckerpunch_St_Albans-St_Albans_Hertfordshire_England.html", seq(0, 80, 10) ) scrape_tripadvisor <- function(urls) { # 用lapply批量处理每个页面,返回列表 page_results <- lapply(urls, function(url) { # 只读取一次页面,避免重复请求 page <- read_html(url) reviews <- page %>% html_nodes("#REVIEWS .innerBubble") # 提取各字段,处理可能的缺失值 tibble( id = reviews %>% html_node(".quote a") %>% html_attr("id"), headline = reviews %>% html_node(".quote span") %>% html_text(), rating = reviews %>% html_node(".ui_bubble_rating") %>% html_attr("class") %>% str_extract("\\d+") %>% # 用正则提取评分数字,比substr更鲁棒 as.numeric() / 10, date = reviews %>% html_node(".ratingDate") %>% html_attr("title") %>% as.Date("%d %B %Y"), review_text = reviews %>% html_node(".partial_entry") %>% html_text() ) }) # 合并所有页面数据,然后基于唯一ID去重 bind_rows(page_results) %>% distinct(id, .keep_all = TRUE) # 保留每个ID的第一条记录 } # 运行函数,得到去重后的结果 clean_reviews <- scrape_tripadvisor(tripadvisor_urls)
关键改进点
- 基于ID去重:用
distinct(id, .keep_all = TRUE)直接过滤重复评论,这是最可靠的方式(因为id是TripAdvisor评论的唯一标识)。 - 单次页面读取:每个URL只请求一次,减少网络开销和潜在的不一致问题。
- 避免全局变量:函数直接返回数据框,符合R的函数式编程规范,不会污染全局环境。
- 更鲁棒的评分提取:用正则表达式提取评分数字,替代固定位置的
substr(如果页面class属性结构变化,substr会失效,正则更灵活)。 - 用tibble替代data.frame:tibble的输出更友好,处理缺失值的逻辑更清晰。
额外建议
- 添加请求延迟:在
lapply的函数里加入Sys.sleep(2),避免请求过于频繁(即使有授权,友好爬取也能降低被限流的风险)。 - 处理缺失值:可以用
replace_na()给缺失的评分、日期等字段填充默认值,比如replace_na(rating, 0)。
内容的提问来源于stack exchange,提问作者BadAtCoding
相关产品推荐
相关产品推荐

