Извлечение нескольких элементов из нескольких веб-страниц в одну функцию / цикл - PullRequest
0 голосов
/ 09 марта 2020

Я новичок в веб-очистке в R и испытываю трудности с циклическим веб-очисткой для создания нескольких уникальных фреймов данных.

Из базового URL-адреса я использую map_df для извлечения 335 уникальных URL-адресов из двадцати вариантов на базовом URL.

# Common basic URL for multiple pages
url_base <- "url_page=%d"

# Function to pull the specific profile URLs part of a common-named series of URLs
map_df(1:20, function(i) {

  pg <- read_html(sprintf(url_base, i))

  urls <- pg %>%
    rvest::html_nodes('body') %>%
    xml2::xml_find_all("//h3[contains(@class, 'heading-large block-tighter')]") %>%
    html_node("a") %>%
    html_attr("href") %>%
    as.data.frame() %>%
    rename(url_link = '.')

}) -> url_df # Generates a 335 observation data frame.

urls <- pull(url_df, url_link) # Each URL is unique in composition and length

В отличие от базового URL, в 335 извлеченных URL отсутствует одинаковая длина или шаблон.

Я создаю функцию, которая, как мне известно, работает на один URL, который извлекает три разных фрагмента веб-страницы. Первый кусок представляет собой одну текстовую строку. Второй кусок - это 180 уникальных текстовых строк. Третий кусок - это 180 уникальных текстовых / цифровых символов. Данные не организованы в виде таблицы на веб-странице.

# Including function that is wrapped up in a `for` loop below
# Extract Data Function ####
extract_data <- function(x) {
  # Read the web page
  rankprofile <- read_html(x) # Single URL from larger URL dataframe

  # Find the data rows in the profile page

  # Extract University/Program Name
  univ_name <- rankprofile %>%
    rvest::html_nodes('body') %>%
    xml2::xml_find_all("//h1[contains(@class, 'hero-heading flex-media-heading')]") %>%
    rvest::html_text() # Extracts 1 text string per page

  # Extract the table categories
  category <- rankprofile %>%
    rvest::html_nodes('body') %>%
    xml2::xml_find_all("//div[contains(@id, 'ddb-field')]") %>%
    xml2::xml_find_all("//span[contains(@class, 'text-coal flex-medium-8')]") %>%
    rvest::html_text() # Extracts 180 unique text strings per page

  # Extract the table values
  value <- rankprofile %>%
    rvest::html_nodes('body') %>%
    xml2::xml_find_all("//div[contains(@id, 'ddb-field')]") %>%
    xml2::xml_find_all("//span[contains(@class, 'text-strong flex-medium-4 medium-end')]") %>%
    rvest::html_text() # Extracts 180 unique stings or numberics per page

  # Remove white space and make the extracts into data frames
  # Also, name columns
  university_name <- univ_name %>%
    str_squish() %>%
    as.data.frame()

  university_name <- university_name %>%
    rename(Value = '.') %>%
    mutate(Category = "University Name") %>%
    select(Category, Value)

  cat_df <- category %>%
    str_squish() %>%
    as.data.frame() %>%
    rename(Category = '.')

  val_df <- value %>%
    str_squish() %>%
    as.data.frame() %>%
    rename(Value = '.')

  # Bind Category and Value columns
  # Bind Univeristy Name row to Category & Value
  rank_df <- bind_cols(cat_df, val_df) %>%
    bind_rows(university_name)

  return(rank_df)
}

И вот здесь я столкнулся с проблемой. Я пытаюсь поместить список из 355 URL-адресов в for l oop, но он возвращает один фрейм данных rank_df

# Attempting a loop for each unique URL in the `url` object
# but the loop returns a single `rank_df` dataframe instead of 335 dataframes
for (i in 1:335) {
  x <- urls[i]
  extract_rankings(x)
}

Как мне написать последний шаг, чтобы вернуть 355 уникальных данных кадры на основе функции extract_rankings()?

...