R:rvest提取innerHTML

jav*_*ebo 9 r tostring innerhtml web-scraping rvest

使用R中的rvest来抓取网页,我想从节点中提取相应的内容innerHTML,特别是在应用之前将换行符更改为换行符html_text.

所需功能的示例:

library(rvest)
doc <- read_html('<html><p class="pp">First Line<br />Second Line</p>')
innerHTML(doc, ".pp")
Run Code Online (Sandbox Code Playgroud)

应产生以下输出:

[1] "<p class=\"pp\">First Line<br>Second Line</p>"
Run Code Online (Sandbox Code Playgroud)

有了rvest 0.2这个就可以实现toString.XMLNode

# run under rvest 0.2
library(XML)
html('<html><p class="pp">First Line<br />Second Line</p>') %>% 
  html_node(".pp") %>% 
  toString.XMLNode
[1] "<p class=\"pp\">First Line<br>Second Line</p>"
Run Code Online (Sandbox Code Playgroud)

随着更新,rvest 0.2.0.900这不再起作用.

# run under rvest 0.2.0.900
library(XML)
html_node(doc,".pp") %>% 
  toString.XMLNode
[1] "{xml_node}\n<p>\n[1] <br/>"
Run Code Online (Sandbox Code Playgroud)

所需的功能通常在write_xml包的功能中可用xml2,rvest现在取决于 - 如果只能write_xml将其输出提供给变量而不是坚持写入文件.(也是textConnection不接受的).

作为一种解决方法,我可以暂时写入文件:

# extract innerHTML, workaround: write/read to/from temp file
html_innerHTML <- function(x, css, xpath) {
  file <- tempfile()
  html_node(x,css) %>% write_xml(file)
  txt <- readLines(file, warn=FALSE)
  unlink(file)
  txt
}
html_innerHTML(doc, ".pp") 
[1] "<p class=\"pp\">First Line<br>Second Line</p>"
Run Code Online (Sandbox Code Playgroud)

然后,我可以将换行标记转换为换行符:

html_innerHTML(doc, ".pp") %>% 
  gsub("<br\\s*/?\\s*>","\n", .) %>%
  read_html %>%
  html_text
[1] "First Line\nSecond Line"
Run Code Online (Sandbox Code Playgroud)

有没有更好的方式与现有的功能来做到这一点从例如rvest,xml2,XML或其他的包?特别是我想避免写入硬盘.

akr*_*ica 2

正如 @r2evans 指出的,as.character(doc)这就是解决方案。

关于最后一个代码片段,它希望<br>在转换为换行符时从节点中提取 -separated 文本,当前未解决的rvest 问题 #175,注释 #2<br>中有一个解决方法:

此问题的简化版本:

doc <- read_html('<html><p class="pp">First Line<br />Second Line</p>')

# r2evan's solution:
as.character(rvest::html_node(doc, xpath="//p"))
##[1] "<p class=\"pp\">First Line<br>Second Line</p>"

# rentrop@github's solution, simplified:
innerHTML <- function(x, trim = FALSE, collapse = "\n"){
    paste(xml2::xml_find_all(x, ".//text()"), collapse = collapse)
}
innerHTML(doc)
## [1] "First Line\nSecond Line"
Run Code Online (Sandbox Code Playgroud)