How to parse addresses from website specifying class in R?

Viewed 45

I would like to parse addresses of all stores on the following website: https://www.carrefour.fr/magasin/region/ looping through the regions. So starting for example with the region "auvergne-rhone-alpes-84", hence full url = https://www.carrefour.fr/magasin/region/auvergne-rhone-alpes-84. Note that I can add more regions afterwards, I just want to make it work with one for now.

carrefour <- "https://www.carrefour.fr/magasin/region/"
addresses_vector = c()

for (current_region in c("auvergne-rhone-alpes-84")) {
  current_region_url = paste(carrefour, current_region, "/", sep="")
  
  x <- GET(url=current_region_url)
  
  html_doc <- read_html(x) %>%
    html_nodes("[class = 'ds-body-text ds-store-card__details--content ds-body-text--size-m ds-body-text--color-standard-2']")
  
  addresses_vector <- c(addresses_vector, html_doc %>%
                          rvest::html_nodes('body')%>%
                          xml2::xml_find_all(".//div[contains(@class, 'ds-body-text ds-store-card__details--content ds-body-text--size-m ds-body-text--color-standard-2')]") %>%
                          rvest::html_text())
}

I also tried with x%>% read_html() %>% rvest::html_nodes(xpath="/html/body/main/div[1]/div/div[2]/div[2]/ol/li[1]/div/div[1]/div[2]/div[2]")%>% rvest::html_text() (copying the whole xpath by hand) or x%>%read_html() %>%html_nodes("div.ds-body-text.ds-store-card__details--content.ds-body-text--size-m.ds-body-text--color-standard-2") %>%html_text() and several other ways but I always get a character(0) element returned.

Any help is appreciated!

1 Answers

You could write a couple of custom functions to help then use purrr to map the store data function to inputs from the output of the first helper function.

First, extract the region urls and extract the region names and region ids. Store these in a tibble. This is the first helper function get_regions.

Then use another function, get_store_info, to extract from these region urls the store info, which is stored in a div tag, from which it is dynamically extracted when JavaScript runs in the browser, but not when using rvest.

Apply the function that extracts the store info over the list of region urls and region ids.

If you use map2_dfr to pass both region id and region link to the function which extracts store data, you then have the region id to link back on to join the result of the map2_dfr to that of region tibble generated earlier.

Then do some column cleaning e.g., drop ones you don't want.

library(rvest)
library(purrr)
library(dplyr)
library(readr)
library(jsonlite)

get_regions <- function() {
  url <- "https://www.carrefour.fr/magasin"
  page <- read_html(url)
  regions <- page %>% html_nodes(".store-locator-footer-list__item > a")
  t <- tibble(
    region = regions %>% html_text(trim = T),
    link = regions %>% html_attr("href") %>% url_absolute(url),
    region_id = NA_integer_
  ) %>% mutate(region_id = str_match(link, "-(\\d+)$")[, 2] %>%
    as.integer())
  return(t)
}

get_store_info <- function(region_url, r_id) {
  region_page <- read_html(region_url)
  store_data <- region_page %>%
    html_node("#store-locator") %>%
    html_attr(":context-stores") %>%
    parse_json(simplifyVector = T) %>%
    as_tibble()
  store_data$region_id <- r_id
  return(store_data)
}

region_df <- get_regions()

store_df <- map2_dfr(region_df$link, region_df$region_id, get_store_info)

final_df <- inner_join(region_df, store_df, by = 'region_id') # now clean columns within this.
Related