使用rlang::duplicate克隆rvest对象失效:修改副本仍变更原对象
问题成因
rvest底层依赖xml2库处理节点,xml2返回的HTML/XML节点对象本质是指向libxml2 C层结构体的外部指针,R层面的变量只是持有这个指针的引用,而非节点数据本身。
rlang::duplicate的作用是复制R层面的对象结构,但不会复制外部指针指向的底层C内存数据,所以你复制得到的x2和原x本质还是指向同一个底层节点,对x2的修改自然会同步到x上,该问题和R的惰性求值没有关系,是外部指针对象的特性导致的。
解决方案
不需要修改节点结构、不需要重新挂载子节点的前提下,有两种常用实现方案,全程不会改动原对象:
方案1:用Xpath直接提取节点自身文本
通过Xpath的text()语法直接匹配当前节点下的直属文本节点,忽略所有子元素节点:
# 直接提取目标节点的直属文本 self_text <- x |> xml2::xml_find_all("./text()") |> rvest::html_text() |> paste(collapse = "") # 输出结果和删除子节点后的结果一致 trimws(self_text) #> [1] "text to extract"
方案2:筛选内容节点中的文本类型
通过xml_contents获取节点下所有直属内容,过滤出文本类型的节点后提取文本:
self_text <- x |> xml2::xml_contents() |> (\(content) content[xml2::xml_type(content) == "text"])() |> xml2::xml_text() |> paste(collapse = "")
内容的提问来源于stack exchange,提问作者geotheory
相关产品推荐
相关产品推荐

