首页 > 解决方案 > R - 使用 tydiverse 和 xml2 将 XML 从多个 URL 解析到数据框

问题描述

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

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

我的最终目标是:

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

我的奋斗从一开始就开始了。我只能运行链接并将其作为 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)


谢谢大家

标签: rxmlxml2

解决方案


问题是,当您调用 时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. xml_ns_strip之后使用read_xml
  3. 利用read_html

此代码将遍历所有 xml 页面,并为您提供所有 365 评论的字符向量。你会发现虽然contentxml的每一页有100个标签,那是因为content每个标签里面有两个entry标签。其中一个具有评论的原始文本,另一个具有相同的内容但以 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


推荐阅读