【问题标题】:Scraping and extracting XML sitemap elements using R and Rvest使用 R 和 Rvest 抓取和提取 XML 站点地图元素
【发布时间】:2020-08-15 21:22:53
【问题描述】:

我需要使用 Rvest 从多个 xml 文件中提取大量 XML 站点地图元素。我已经能够使用 xpaths 从网页中提取 html_nodes,但是对于 xml 文件,这对我来说是新的。

而且,我找不到让我解析 xml 文件地址而不是解析大量 XML 文本块的 Stackoverflow 问题。

我用于 html 的示例:

library(dplyr)
library(rvest)

webpage <- "https://www.example.co.uk/"

data <- webpage %>%
  read_html() %>%
  html_nodes("any given node goes here") %>%
  html_text()

如何调整它以从如下所示的 XML 文件(解析地址)中获取“loc”XML 文件元素:

<urlset>
<url>
<loc>https://www.example.co.uk/</loc>
<lastmod>2020-05-01</lastmod>
<changefreq>always</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://www.example.co.uk/news</loc>
<changefreq>always</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://www.example.co.uk/news/uk</loc>
<changefreq>always</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://www.example.co.uk/news/weather</loc>
<changefreq>always</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://www.example.co.uk/news/world</loc>
<changefreq>always</changefreq>
<priority>0.5</priority>
</url>

这是我在 Dave 提供的脚本中所做的更改:

library(xml2)

#list of files to process
fnames<-c("xml1.xml")

dfs<-lapply(fnames, function(fname) {
  doc<-read_xml(fname)

  #find loc and lastmod
  loc<-trimws(xml_text(xml_find_all(doc, ".//loc")))
  lastmod<-trimws(xml_text(xml_find_all(doc, ".//last")))

  #find all of the nodes/records under the urlset node
  nodes<-xml_children(xml_find_all(doc, ".//urlset"))

  #find the sub nodes names and values
  nodenames<-xml_name(nodes)
  nodevalues<-trimws(xml_text(nodes))

  #make data frame of all the values
  df<-data.frame(file=fname, loc=loc, lastmod=lastmod, node.names=nodenames, 
                 values=nodevalues, stringsAsFactors = FALSE, nrow(0))

})

#Make one long df
longdf<-do.call(rbind, dfs)

#make into a wide format
library(tidyr)
finalanswer<-spread(longdf, key=node.names, value=values)

【问题讨论】:

  • 如果是 XML 那么你只需要 xml2 包(rvest 是这个包的扩展)。将此问题视为开始:stackoverflow.com/questions/54237549/…
  • 谢谢,但我得到“错误:参数暗示不同的行数:1, 0”
  • 我已经编辑了上面的内容以显示我想从中提取 元素的另一个文件。也许这就是为什么我遇到不同行的问题。你能帮忙吗?
  • 这两个文件有不同的结构,所以是的,这会导致错误。第一个具有父节点的“站点地图”,第二个具有“url”。是否有其他类型的文件或只有这 2 个?如果只是 2,我的方法是编写两个不同的函数来解析每种类型,然后合并结果。如果超过 2 或 3 个,那么这将变得更加困难,因为一切都需要相对引用,并且无法直接命名节点。
  • 为简单起见,我更改了所需的文件格式,并根据您的回答添加了我正在使用的脚本。我在你的脚本中没有正确适应什么。我不断收到同样的错误。注意我在工作目录中设置了 XML 文件,并且命名正确。

标签: r xml web-scraping rvest


【解决方案1】:

由于每个 url 节点的子节点数量不同,这是一种可行的方法:

file<-read_xml(text)

library(dplyr)

#find parent nodes
parents <-xml_find_all(file, ".//url")

#parse each child
dfs<-lapply(parents, function(node){
  #Find all children
  nodes <- xml_children(node)

  #get node name and value
  nodenames<-  xml_name(nodes)
  values <- xml_text(nodes)

  #made data frame with results
  df<- as.data.frame(t(values), stringsAsFactors=FALSE)
  names(df)<-nodenames
  df
})

#Make find answer
answer<-bind_rows(dfs)

由于您有多个文件,您可以将脚本包含在外部循环中以循环浏览文件列表。当然是循环中的循环,因此如果每个文件中有大量文件和大量父节点,性能将受到影响。

替代方案:如果子节点数量少,最好直接解析,避免上面的lapply循环。

loc <- xml_find_first(parents, ".//loc") %>% xml_text()
lastmod <- xml_find_first(parents, ".//lastmod") %>% xml_text()
changefreq <- xml_find_first(parents, ".//changefreq") %>% xml_text()
priority <- xml_find_first(parents, ".//priority") %>% xml_text()

answer<-data.frame(loc, lastmod, chargefreq, priority)

【讨论】:

  • 难以置信,戴夫。非常感谢您为我跟进和调整它:)
【解决方案2】:

我有这段代码是我前段时间写的,用于检查文件中的所有 XML 并收集 XML 模式的特定节点,稍加调整你就可以使用一些东西。

library("xml2")
library("XML")

setwd("/xml")
dir <- dir()
tabela=matrix(NA,nrow=length(a),ncol=1)

  for(i in 1:length(dir)){

  visitNode <- function(node) {#Recursive Function to visit the XML tree (depth first)
    if (is.null(node)) {#leaf node reached. Turn back
      return()
    }
    print(paste("Node: ", xmlName(node)))
      num.children = xmlSize(node)

    if(num.children == 0 ) {# Add your code to process the leaf node here
      print(      paste("   ", xmlValue(node)))
    }
    if (num.children > 0){#Go one level deeper
      for (i in 1 : num.children) {
        visitNode(node[[i]][["NFe"]]) #the i-th child of node
      }
    }

  }
  xmlfile <- dir[i]
  xtree <- xmlInternalTreeParse(xmlfile)
  root <- xmlRoot(xtree)
  dataxml <- visitNode(root)
  dataxml <- xmlToList(root)


  df<- as.data.frame(matrix(unlist(dataxml$NFe$infNFe$infAdic$infCpl), nrow=length(dataxml$NFe$infNFe$infAdic$infCpl),byrow=TRUE))

【讨论】:

    猜你喜欢
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多