【问题标题】:Ignoring non-existent URLs with htmlParse() in R在 R 中使用 htmlParse() 忽略不存在的 URL
【发布时间】:2014-03-31 21:37:30
【问题描述】:

大家好,

我有一个很长的地名列表(约 15,000 个),我想用它们来查找 wiki 页面并从中提取数据。不幸的是,并非所有地方都有 wiki 页面,当 htmlParse() 命中它们时,它会停止函数并返回错误。

    Error: failed to load HTTP resource

我无法检查并删除每个创建不存在 URL 的地名,所以我想知道是否有办法让该功能跳过没有 wiki 页面的地方?

    # Town names to be used
    towns <- data.frame('recID' = c('G62', 'G63', 'G64', 'G65'), 
                    'state' = c('Queensland', 'South_Australia', 'Victoria', 'Western_Australia'),
                    'name'  = c('Balgal Beach', 'Balhannah', 'Ballan', 'Yunderup'),
                    'feature' = c('POPL', 'POPL', 'POPL', 'POPL'))

    towns$state <- as.character(towns$state)

    towns$name <- sub(' ', '_', as.character(towns$name))

   # Function that extract data from wiki
   wiki.tables <- function(towns)  {
      require(RJSONIO)
      require(XML)
      u <- paste('http://en.wikipedia.org/wiki/',
                 sep = '', towns[,1], ',_', towns[,2])
      res <- lapply(u, function(x) htmlParse(x))
      tabs <- lapply(sapply(res, getNodeSet, path = '//*[@class="infobox vcard"]')
             , readHTMLTable)
      return(tabs)
    }

    # Now to run the function. Yunderup will produce a URL that 
    # doesn't exist. So this will result in the error.
    test <- wiki.tables(towns[,c('name', 'state')])

    # It works if I don't include the place that produces a non-existent URL.
    test <- wiki.tables(towns[1:3,c('name', 'state')])

有没有办法识别这些不存在的 URL 并跳过它们或删除它们?

感谢您的帮助!

干杯, 亚当

【问题讨论】:

  • 也许函数内部有一个if 语句来告诉它如果丢失就移动到下一个url?
  • 运行你的代码,我实际上得到了以下错误:Error in (function (classes, fdef, mtable) : unable to find an inherited method for function ‘readHTMLTable’ for signature ‘"XMLNodeSet"’,不是与 URL 相关的错误。
  • G'day Thomas,谢谢我刚刚意识到同样的事情。这是因为创建的 Yunderup URL 存在但其中没有表,例如路径 = '//*[@class="infobox vcard"]'。我试图弄清楚如何放置一个 if 语句来检查我得到的 html 数据是否具有此路径...正如下面的答案所示,该 URL 确实存在,但它不是“正确”类型的 wiki 页面我想要。

标签: r html-parsing web-scraping


【解决方案1】:
You can use the 'url.exists' function from `RCurl`

require(RCurl)
u <- paste('http://en.wikipedia.org/wiki/',
                 sep = '', towns[,'name'], ',_', towns[,'state'])
> sapply(u, url.exists)
   http://en.wikipedia.org/wiki/Balgal_Beach,_Queensland 
                                                    TRUE 
 http://en.wikipedia.org/wiki/Balhannah,_South_Australia 
                                                    TRUE 
           http://en.wikipedia.org/wiki/Ballan,_Victoria 
                                                    TRUE 
http://en.wikipedia.org/wiki/Yunderup,_Western_Australia 
                                                    TRUE 

【讨论】:

    【解决方案2】:

    这是另一个使用httr 包的选项。 (顺便说一句:你不需要RJSONIO)。将您的 wiki.tables(...) 函数替换为:

    wiki.tables <- function(towns)  {
      require(httr)
      require(XML)
      get.HTML<- function(url){
        resp <- GET(url)
        if (resp$status_code==200) return(htmlParse(content(resp,type="text")))
      }
      u <- paste('http://en.wikipedia.org/wiki/',
                 sep = '', towns[,1], ',_', towns[,2])
      res <- lapply(u, get.HTML)
      res <- res[sapply(res,function(x)!is.null(x))]   # remove NULLs
      tabs <- lapply(sapply(res, getNodeSet, path = '//*[@class="infobox vcard"]')
                     , readHTMLTable)
      return(tabs)
    }
    

    这会运行一个 GET 请求并测试状态代码。 url.exists(...) 的缺点是你必须对每个 url 查询两次:一次是查看它是否存在,另一次是获取数据。

    顺便说一句,当我尝试您的代码时,实际上确实存在 Yunderup 网址??

    【讨论】:

    • 感谢 jlhoward。是的,过了一会儿,我意识到 url 确实存在,它是 getNodeSet, path ='//*[@class="infobox vcard"]',但不存在。所以我真的有两个层次的解析要做。摆脱那些没有 URL 的地方,你已经为它们提供了一个很好的解决方案,只在合适的地方从那些 URL 中提取选项卡。我很快就会想出第二​​步,可能会使用 if 语句。
    猜你喜欢
    • 2012-07-27
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    相关资源
    最近更新 更多