仅使用lapply read_html页面结果时,就会保留。
library(xml2)
lapply(c("https://www.analyticsvidhya.com/blog/2018/06/datahack-radio-1-machine-learning-competitions-with-kaggle-ceo-anthony-goldbloom/","https://www.analyticsvidhya.com/blog/2018/09/datahack-radio-lyft-dr-alok-gupta/"), function(x){read_html(x)})
#> [[1]]
#> {xml_document}
#> <html>
#> [1] <head lang="en-US" prefix="og: http://ogp.me/ns#">\n<meta http-equiv ...
#> [2] <body class="post-template-default single single-post postid-45087 s ...
#>
#> [[2]]
#> {xml_document}
#> <html>
#> [1] <head lang="en-US" prefix="og: http://ogp.me/ns#">\n<meta http-equiv ...
#> [2] <body class="post-template-default single single-post postid-46725 s ...
使用并行mclapply时:
library(xml2)
library(parallel)
mclapply(c("https://www.analyticsvidhya.com/blog/2018/06/datahack-radio-1-machine-learning-competitions-with-kaggle-ceo-anthony-goldbloom/","https://www.analyticsvidhya.com/blog/2018/09/datahack-radio-lyft-dr-alok-gupta/"), function(x){read_html(x)}, mc.cores = 2)
#> [[1]]
#> {xml_document}
#>
#> [[2]]
#> {xml_document}
我不知道为什么会发生这种情况,即使使用foreach我也无法像平常的lapply那样获得理想的结果。救命!
答案 0 :(得分:1)
(我的意思是,您使用了 thread 一词,所以我不会错过一两个双关语的机会)。
在?parallel::mclapply
的手册页中,您最终会发现它的工作原理:
您可以阅读?serialize
来查看使用的方法。
xml_document
/ html_document
对象? 首先,让我们做一个:
library(xml2)
(doc <- read_html("<p>hi there!</p>"))
## {xml_document}
## <html>
## [1] <body><p>hi there!</p></body>
看看str
的故事:
str(doc)
## List of 2
## $ node:<externalptr>
## $ doc :<externalptr>
## - attr(*, "class")= chr [1:2] "xml_document" "xml_node"
doc$node
## <pointer: 0x7ff45ab17ce0>
嗯。这些是<externalptr>
对象。 ?"externalptr-class"
(最终)对他们说什么?
…
"externalptr" # raw external pointers for use in C code
由于它不是内置对象,并且数据被隐藏起来并且只能通过package接口访问,因此R不能自己和needs help对其进行序列化。 (该十六进制字符串0x7ff45ab17ce0
是指向不透明数据隐藏位置的内存指针)。
完全是
如果您来自密苏里州(“ Show Me”状态),只需尝试将上面的文档保存到RDS文件中,然后就可以看到没有并行操作和原始连接对象序列化复杂性的情况会发生什么情况。读回去:
tf <- tempfile(fileext = ".rds")
saveRDS(doc, tf)
(doc2 <- readRDS(tf))
## List of 2
## $ node:<externalptr>
## $ doc :<externalptr>
## - attr(*, "class")= chr [1:2] "xml_document" "xml_node"
现在,您可能都像“ AHA!看,它有效!” Aaaaand…您会错:
doc2$node
## <pointer: 0x0>
0x0
表示没有指向任何内容。您已经丢失了所有数据。它消失了。永远。 (但是,它运行良好,所以我们不要太难过吧)。
他们has been discussed by the xml2
devs和{而不是使我们的生活变得更轻松–而是捣碎了?xml_serialize
。
xml_serialize
,但这还不是那么有用吗? 是的。而且,它甚至变得更更好。
希望您的好奇心足以使您继续前进,并找出该相当认真的 xml_serialize()
函数的作用。如果不是,则为R,因此要找出答案,只需键入其名称,而无需使用()
即可得到:
function (object, connection, ...)
{
if (is.character(connection)) {
connection <- file(connection, "w", raw = TRUE)
on.exit(close(connection))
}
serialize(structure(as.character(object, ...), class = "xml_serialized_document"),
connection)
}
此功能xml_serialize
后面的复杂魔术除了连接一些连接位以外,还很容易成为 as.character()
。 (实际上令人失望)。
由于并行操作在返回saveRDS()
,readRDS()
(或它们的xml_document
兄弟姐妹)时(惯常地)等效于html_document
=> _node[s]
在并行应用中,您最终一无所有。
(至少)您有四个选择:
as.character((read_html(…))
直接从并行应用中返回原始的,可序列化的字符HTML,然后将它们重新xml2
重新使用您的程序xml2
层插入适当的序列化黑客程序中,不要打扰它,因为您可能会花费大量时间试图说服他们值得,但由于此“ externalptr
序列化是一件棘手的事情,到处都是危险,您可能会错过一些边缘案例(例如,Hadley / Jim / etc知道他们在做什么,如果被批评了,这是不值得做的事情)。实际上,我不是使用
xml2::read_html()
+httr::GET()
来获取内容,而是使用httr::content(…, as="text")
+read_html()
(如果您很酷并且缓存页面,而又浪费了其他资源自libxml2
起就使用了{{1}},并转换了文档(即使有时只是一点点),与未转换的原始,缓存的源数据相比,最好由认为是比我们聪明。
除了上面的详细模式起泡之外,我真的无话可说。希望这种扩展还可以帮助其他人了解发生了什么。