代码之家  ›  专栏  ›  技术社区  ›  Akarsh Jain

使用mclappy时列表中未保留HTML页

  •  1
  • Akarsh Jain  · 技术社区  · 7 年前

    当使用简单的lappy 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 ...
    

    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那样得到想要的结果。救命啊!

    1 回复  |  直到 7 年前
        1
  •  1
  •   hrbrmstr    7 年前

    该缝合了

    (我是说,你用了这个词 线 所以我不会因为一两句双关语而错过这个机会。

    深入手册页 ?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
    

    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"
    

    现在,你们可能都像 “啊哈!看,它起作用了!” 啊,你会的 :

    doc2$node
    ## <pointer: 0x0>
    

    0x0 意味着它没有指向任何东西。你丢失了所有的数据。它不见了。永远。(但是,它有一个很好的运行,所以我们不应该太悲伤abt它)。 这个 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)
    }
    

    除了连接一些连接位外 复杂巫术 功能是, 只是 as.character() . (实际上有点失望。)

    因为并行操作(惯用地)相当于 saveRDS() => readRDS() 当您返回 , html文档 _node[s] 兄弟姐妹)在一个平行的应用程序中,你最终会得到一大堆的东西。

    内容窃贼

    您(至少)还有四个选择:

    • 冷静点,让一个并行应用程序将HTML保存到文件中(HTTP操作很可能是慢的一部分),然后是一个非并行操作,按顺序读取并处理它们-看起来你无论如何都要这么做。请注意,如果你不对文件进行HTML缓存,那么你就是一个水蛭和坏网民,因为你显示出你真的不关心你正在处理的内容的带宽和CPU成本 刮擦。
    • 不要因为做^^^而变得很酷,相反,使用 as.character((read_html(…)) 直接从并行应用程序返回原始的、可序列化的、字符HTML,然后重新- xml2格式 把它们放回你程序的其他部分
    • ±叉子 xml2格式 ,层在一个适当的序列化黑客和不麻烦公关它,因为你可能会花很多时间试图说服他们这是值得的,但最终仍然失败,因为这一点” externalptr

    在现实中,而不是使用 xml2::read_html() 为了获取内容,我会使用 httr::GET() + httr::content(…, as="text") read_html() 使用 libxml2

    推荐文章