【问题标题】:How to return NA when nothing is found in an xpath?在 xpath 中找不到任何内容时如何返回 NA?
【发布时间】:2017-07-24 03:27:45
【问题描述】:

这个问题很难表述,但举个例子就很容易理解了。

我使用 R 来解析 html 代码。

在下面,我有一个名为html的html代码,然后我尝试提取//span[@class="number"]中的所有值以及//span[@class="surface"]中的所有值:

html <- '<div class="line">
<span class="number">Number 1</span>
<span class="surface">Surface 1</span>
</div>
<div class="line">
<span class="surface">Surface 2</span>
</div>' 

page = htmlTreeParse(html,useInternal = TRUE,encoding="UTF-8")

number = unlist(xpathApply(page,'//span[@class="number"]',xmlValue))
surface = unlist(xpathApply(page,'//span[@class="surface"]',xmlValue))

number 的输出是:

[1] "Number 1"

surface 的输出是:

[1] "Surface 1" "Surface 2"

然后,当我尝试 cbind 这两个元素时,我不能,因为它们的长度不同。

所以我的问题是:我该怎么做才能得到number 的输出:

[1] "Number 1" NA

然后我可以结合numbersurface

【问题讨论】:

  • 您是否试图确保数字和表面对保持在一起?因为如果你有第三行只有一个数字,这种方法很容易混淆。然后两个列表都会返回两个元素,但它们不一定是配对的。

标签: html r xpath web-scraping html-parsing


【解决方案1】:
library( 'XML' )  # load library
doc = htmlParse( html )  # parse html
# define xpath expression. div contains class = line, within which span has classes number and surface
xpexpr <- '//div[ @class = "line" ]'  

a1 <- lapply( getNodeSet( doc, xpexpr ), function( x ) { # loop through nodeset
      y <- xmlSApply( x, xmlValue, trim = TRUE )  # get xmlvalue
      names(y) <- xmlApply( x, xmlAttrs ) # get xmlattributes and assign it as names to y
      y   # return y
    } )

遍历a1 并提取numbersurface 的值并相应地设置名称。然后列绑定个数和面值

nm <- c( 'number', 'surface' )
do.call( 'cbind', lapply( a1, function( x ) setNames( x[ nm ], nm ) ) )
#                [,1]        [,2]       
# number  "Number 1"  NA         
# surface "Surface 1" "Surface 2"

数据:

html <- '<div class="line">
<span class="number">Number 1</span>
<span class="surface">Surface 1</span>
</div>
<div class="line">
<span class="surface">Surface 2</span>
</div>' 

【讨论】:

  • 让我知道这是否适合你,否则我会删除它
  • 嗨@Sathish,谢谢你的回答,但我可能不够清楚,我想建立一个矩阵。但似乎我可以用你的解决方案得到一个矩阵...请参阅 alistaire 的解决方案,谢谢
【解决方案2】:

为每个标签选择封闭标签(此处为div)并在其中查找每个标签更容易。加上我觉得更简单的 rvest 和 purrr,

library(rvest)
library(purrr)

html %>% read_html() %>% 
    html_nodes('.line') %>% 
    map_df(~list(number = .x %>% html_node('.number') %>% html_text(), 
                 surface = .x %>% html_node('.surface') %>% html_text()))

#> # A tibble: 2 × 2
#>     number   surface
#>      <chr>     <chr>
#> 1 Number 1 Surface 1
#> 2     <NA> Surface 2

【讨论】:

  • 谢谢你,alistaire,目前,我不完全理解你的代码,但它可以工作。谢谢。 (number=.x表示数字的xml值?)
  • 它使用 CSS 选择器而不是 XPath,map_dflapply 一样遍历结果,但将结果简化为 data.frame。这里我使用它简化的匿名函数语法,其中.x 是为该迭代传递的值。
  • 好的,谢谢。我不熟悉 CSS 选择器。我稍微简化了我的代码,如果我有&lt;span class="number"&gt;Number&lt;div&gt;1&lt;/div&gt;&lt;/span&gt;,我怎样才能得到div 中的值?使用 xPath,我可以做到//span[@class="number"]/div
  • Here's a really nice, quick tutorial on CSS selectors,但等效为 span.number div。但是,如果您喜欢 XPath,html_nodeshtml_node 也会接受,如果您指定将其传递给 xpath 参数。
  • 您使用了 CCS 选择器,因为,我有一个类的值,对吧?如果我没有类值怎么办。例如,在我之前的评论中,我有这个代码&lt;span class="number"&gt;Number&lt;div&gt;1&lt;/div&gt;&lt;/span&gt;,我怎样才能得到一个矩阵,用于 div 中的值(在跨度内)?第 1 行为 1,第 2 行为 NA。
猜你喜欢
  • 2021-06-06
  • 2021-06-05
  • 2013-04-07
  • 2019-12-15
  • 2021-01-11
  • 1970-01-01
  • 1970-01-01
  • 2013-03-04
  • 2021-10-15
相关资源
最近更新 更多