R - 使用 tydiverse 和 xml2 将 XML 从多个 URL 解析为数据框

R - Parsing XML from multiple URL to Data Frame with tydiverse and xml2

这个问题可能会被标记为重复,但我无法让它工作。 作为记录,我已经阅读了所有其他 Whosebug 问题并阅读了文档。

我想从 iTunes 中提取多个页面的数据评论(link:https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=1/xml),我想以整洁和动态的方式进行,最好使用 XML2tydiverse.

我的最终目标是:

在一个列中包含所有可用字段(如 ID、作者等)并填充数据的数据框。

我的奋斗从头开始。我只能运行 link 并将其作为XML 获取,但我不能运行 提取XML 代码的简单代码行。我显然在这里遗漏了一些东西。 我也不知道如何浏览这些页面。我知道有多少页存在,但我想以动态方式拥有它。

library("tidyverse")
library("xml2")


# Data extraction ---------------------------------------------------------

df_xml <- read_xml('https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=1/xml')

teste <- xml_text(xml_find_all(df_xml, '//feed/entry/ author')) *here I try to extract the field author*
> teste
> character(0)


提前谢谢大家

问题是当您调用 xml_find_all(df_xml, '//feed/entry/ author') 时,搜索找不到您要查找的节点,因为它们都在 xml 命名空间内。

uri <- "https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=1/xml"
my_xml <- read_xml(uri)
xml_find_all(my_xml, "//feed")
#> {xml_nodeset (0)}

您可以像这样找出文档中使用了哪些名称空间:

xml_ns(my_xml)
#> d1 <-> http://www.w3.org/2005/Atom
#> im <-> http://itunes.apple.com/rss

所以你可以在你的 xpath 中指定你想要使用的命名空间,你将得到你正在寻找的节点,如下所示:

xml_find_all(my_xml, "//d1:feed")
#> {xml_nodeset (1)}
#> [1] <feed xmlns:im="http://itunes.apple.com/rss" xmlns="http://www.w3.org/2005/Atom ...

这显然有点烦人,因为您必须在 xpath 中为所有标签添加前缀 d1:,并且您的文档结构是这样的,您可以在没有名称空间的情况下使用,因此最好忽略他们。

我发现最简单的方法是使用 read_html 而不是 read_xml,因为除其他外,它会自动去除名称空间并且更容易出错。但是,有一个函数 xml_ns_strip,如果您愿意,可以在阅读 read_xml 后调用它。

因此,您在本文档中处理名称空间的三个选项是:

  1. 所有标签名称前缀为d1:
  2. read_xml
  3. 之后使用xml_ns_strip
  4. 使用read_html

此代码将遍历 xml 的所有页面,并为您提供所有 365 条评论的特征向量。你会发现虽然xml的每一页都有100个content标签,那是因为每个entry标签里面有两个content标签。其中一个有评论的原始文本,另一个有相同的内容,但以 html 的字符串形式。因此,循环丢弃包含字符串的 html 以支持原始文本:

library("tidyverse")
library("xml2")

base <- "https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page="
reviews <- author <- review_date <- character()
max_pages <- 100

for(i in seq(max_pages))
{
  cat("Trying", paste0(base, i, "/xml"), "\n")
  my_xml       <- paste0(base, i, "/xml") %>% read_xml() %>% xml_ns_strip()
  next_reviews <- xml_find_all(my_xml, xpath = '//feed/entry/content') %>% 
                  xml_text() %>%
                  subset(seq_along(.) %% 2 == 1)  
  if(length(next_reviews) == 0){
    result <- tibble(review_date, author, reviews)
    break
  }

  reviews      <- c(reviews, next_reviews)
  next_author  <- xml_text(xml_find_all(my_xml, xpath = '//feed/entry/author/name'))
  author       <- c(author, next_author)
  next_date    <- xml_text(xml_find_all(my_xml, xpath = '//feed/entry/updated'))
  review_date  <- c(review_date, next_date)
}
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=1/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=2/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=3/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=4/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=5/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=6/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=7/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=8/xml 
#> Trying https://itunes.apple.com/gb/rss/customerreviews/id=1388411277/page=9/xml 

现在 result 将包含一个 tibble,其中包含三个感兴趣的字段:

result
#> # A tibble: 367 x 3
#>    review_date          author      reviews                                           
#>    <chr>                <chr>       <chr>                                             
#>  1 2020-05-05T02:38:35~ **stace**   "Really good and useful app. Nice to be able to g~
#>  2 2020-05-05T01:51:49~ fire-hazza~ "Not for Scotland or Wales cmon man"              
#>  3 2020-05-04T23:45:59~ Adz-Coco    "Unable to register due to NHS number. My number ~
#>  4 2020-05-04T23:34:50~ Matthew ba~ "Probably spent about £5 developing this applicat~
#>  5 2020-05-04T16:40:17~ Jenny19385~ "Why it is so complicated to sign up an account? ~
#>  6 2020-05-04T14:39:54~ Sienna hea~ "Thankyou NHS for this excellent app I feel a lot~
#>  7 2020-05-04T13:09:45~ Raresole    "A great app that lets me book appointments and a~
#>  8 2020-05-04T12:28:56~ chanters934 "Unable to login. App doesn’t recognise the code ~
#>  9 2020-05-04T11:26:44~ Ad_T        "Unfortunately my surgery must not be participati~
#> 10 2020-05-04T08:25:17~ tonyproctor "It’s a good app although would be better with a ~
#> # ... with 357 more rows