R如何检查XPath是否存在

时间:2014-08-26 09:38:28

标签: r xpath web-scraping

希望有比我知识渊博的人可以在这里说清楚。

作为更大的网络抓取工具的一部分,我想从一组页面中提取元数据。当我跑这个时,它倒下了,调查显示这是由于Xpath的一个被要求不存在。

我可以看到一个可能的解决方案是将页面中的所有元数据抓取到一个向量中,并在构建我想要的新向量之前检查每个元素是否存在。

BUT

如果我只抓住我想要的位,如果它们存在于页面中,那就更好了。

require(XML)
require(RCurl)
parsed <- htmlParse("http://www.coindesk.com/information")

meta <- list()
meta[1] <- xpathSApply(parsed, "//meta[starts-with(@property, \"og:title\")]", xmlGetAttr,"content")
meta[2] <- xpathApply(parsed, "//meta[starts-with(@property, \"og:description\")]", xmlGetAttr,"content")
meta[3] <- xpathApply(parsed, "//meta[starts-with(@property, \"og:url\")]",  xmlGetAttr,"content")
meta[4] <- xpathApply(parsed, "//meta[starts-with(@property, \"article:published_time\")]",  xmlGetAttr,"content")
meta[5] <- xpathApply(parsed, "//meta[starts-with(@property, \"article:modified_time\")]",  xmlGetAttr,"content")

这会引发错误,因为og:description不在此页面中。

Error in meta[2] <- xpathApply(parsed, "//meta[starts-with(@property, \"og:description\")]",  : 
  replacement has length zero

任何人都可以建议一个简单的测试,在尝试提取之前检查它的存在,优雅地使用NULL响应吗?

2 个答案:

答案 0 :(得分:3)

假设当您尝试处理空列表时出现错误...

> parsed <- htmlParse("http://www.coindesk.com/information")
> meta <- xpathApply(parsed, "//meta[starts-with(@property, \"og:description\")]", xmlGetAttr,"content")
> meta
list()
> length(meta)==0
[1] TRUE

然后测试length(meta)==0 - 如果元素缺失则为TRUE。否则为FALSE - 如此示例中提取title属性:

> meta <- xpathApply(parsed, "//meta[starts-with(@property, \"og:title\")]", xmlGetAttr,"content")
> meta
[[1]]
[1] "Beginner's guide to bitcoin - CoinDesk's Information Center"

> length(meta)==0
[1] FALSE

答案 1 :(得分:1)

对此的答案很难确定。虽然有一些xpathApply的自定义实现可以解决这个问题,但是对于提出问题的解决方案确实存在于Spacedman的建议中。

IF语句的第一部分调用xPath并检查返回长度是否为0。 如果是,则它将自定义消息应用于列表,“标题NA”或“描述NA”但是 如果长度不为0(即匹配),则将xPath应用于列表。

Simples。

 require(XML)
    require(RCurl)
    parsed <- htmlParse("http://www.coindesk.com/information")

    meta    <- list()
    meta[1] <- if(length(xpathSApply(parsed, "//meta[starts-with(@property, \"og:title\")]", xmlGetAttr,"content"))==0) 
               {
                 "Title NA"
               } 
               else 
               {
                 xpathSApply(parsed, "//meta[starts-with(@property, \"og:title\")]", xmlGetAttr,"content")
               }
    meta[2] <- if(length(xpathApply(parsed, "//meta[starts-with(@property, \"og:description\")]", xmlGetAttr,"content"))==0) 
               {  
                 "Description NA" 
               } 
               else 
               {
                  xpathApply(parsed, "//meta[starts-with(@property, \"og:description\")]", xmlGetAttr,"content")
               }