Проблема в том, что когда вы вызываете 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
, если хотите.
Итак, ваши три варианта работы с пространствами имен в этом документе:
- Префикс всех имен тегов с помощью
d1:
- Используйте
xml_ns_strip
после read_xml
- Используйте
read_html
Этот код пройдёт oop через все страницы xml и даст вам вектор символов всех 365 обзоров. Вы обнаружите, что, хотя на каждой странице из xml есть 100 content
тегов, это потому, что внутри каждого entry
тегов есть два content
тегов. Один из них содержит исходный текст обзора, а другой - то же содержание, но в виде строки html. Поэтому l oop отбрасывает строки, содержащие 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