Interface
Dane pozyskiwane były za pomocą interfejsu REST-API oraz w jednym przypadku, używając dedykowanej biblioteki. W przypadku danych wymagających zarządzania limitem przypisanym do indywidualnego token’a, proces ten odbywał się w środowisku R. Dla danych z serwisów niewymagających autoryzacji - środowisko Power Query.
Turystyka GOV - Power Query
W przypadku środowiska Microsoft, problem ten sprowadzał się do utworzenia zapytania w języku M oraz dalszych przekształceń z użyciem interfejsu graficznego Power Query
= Json.Document(
Web.Contents("
https://api.turystyka.gov.pl/registers/open/cwoh" &
"?city=Kraków&size=300",
[Headers=[accept="application/json
"]]))
Odpowiedzią na powyższe żądanie są dane pochodzące z serwisu turystyka.gov.pl, w formacie JSON. Zapytanie zostało wykonane dla miasta Kraków (obszar analizy) oraz limitem 300 hoteli.
GooglePlaces - R
W związku z tym, że pomiędzy danymi z Google Places, a Turystyka GOV nie ma wspólnego, jednoznacznego identyfikatora, posłużono się trzema wartościami - kodem pocztowym, nazwą ulicy oraz nazwą miejsca. Następnie posłużono się silnikiem Google Find Place do zawężenia poszukiwań, a ostateczną lokację wybrano z zastosowaniem dodatkowych algorytmów podobieństwa tekstowego.
### Function to fetch Google Places data based on name and address
fetch_google_place_id <- function(hotel_name, street, postal_code) {
# Google Places API request
places_url <- "https://maps.googleapis.com/maps/api/place/findplacefromtext/json"
query <- paste(hotel_name, street, postal_code)
params <- list(
input = query,
inputtype = "textquery",
fields = "place_id,name,formatted_address",
key = config::get("google_api_key")
)
response <- GET(places_url, query = params, add_headers(accept = "application/json"))
if (status_code(response) == 200) {
data <- fromJSON(content(response, as = "text", encoding = "UTF-8"))
if (length(data$candidates) > 0) {
matches <- data$candidates |>
as.data.frame(stringsAsFactors = FALSE) |>
mutate(
name_similarity = stringdist::stringdist(
tolower(hotel_name),
tolower(name),
method = "jw"
),
street_match = grepl(
gsub("\\s+", " ", trimws(street)),
gsub("\\s+", " ", trimws(formatted_address)),
ignore.case = TRUE
),
postal_code_match = grepl(
gsub("\\s+", " ", trimws(postal_code)),
gsub("\\s+", " ", trimws(formatted_address)),
ignore.case = TRUE
),
score = (1 - name_similarity) * 0.6 +
street_match * 0.2 +
postal_code_match * 0.2
) |>
arrange(desc(score)) |>
head(1) # Pick the best match
return(matches$place_id[1])
}
}
return(NA)
}
Po dopasowaniu ID z GooglePlaces do Turystyka GOV, możliwe było dalsze importowanie danych. Kody zapytań REST API poniżej.
############ GOOGLE REVIEW AND RATINGS
### Fetch Google reviews and ratings
base_url <- "https://maps.googleapis.com/maps/api/place/details/json"
results <- lapply(dfGooglePlace$id_google, function(place_id) {
params <- list(
place_id = place_id,
fields = "name,rating,reviews,user_ratings_total,photos,price_level",
key = config::get("google_api_key")
)
response <- GET(base_url, query = params, add_headers(accept = "application/json"))
Sys.sleep(2) # Small delay to allow token to activate
if (status_code(response) == 200) {
data <- fromJSON(content(response, as = "text", encoding = "UTF-8"))
# Extract key information with place ID
place_info <- tryCatch({
data$result %>%
as.data.frame(stringsAsFactors = FALSE) %>%
select(any_of(c(
"name",
"user_ratings_total",
"rating",
"reviews.author_name",
"reviews.rating",
"reviews.text",
"relative_time_description",
"reviews.profile_photo_url"
))) %>%
mutate(id_google = place_id)
}, error = function(e) {
data.frame(id_google = place_id)
})
# Handle reviews with place ID
reviews_df <- tryCatch({
if (!is.null(data$result$reviews)) {
data$result$reviews %>%
as.data.frame(stringsAsFactors = FALSE) %>%
select(any_of(c("author_name", "rating", "text", "time"))) %>%
mutate(id_google = place_id)
} else {
data.frame(id_google = place_id)
}
}, error = function(e) {
data.frame(id_google = place_id)
})
list(place_info = place_info, reviews = reviews_df)
} else {
print(paste("Error:", status_code(response), "in place_id:", place_id))
list(place_info = data.frame(id_google = place_id), reviews = data.frame(id_google = place_id))
}
})
Dodatkowo, pobrano informacje o najczęściej odwiedzanych obiektach turystycznych…
####### FIND MOST POPULAR PLACES
### Function to fetch paginated results
# API base URL and parameters
base_url <- "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
latitude <- 50.0619
longitude <- 19.9368
radius <- 10000 # Radius in meters
get_places <- function(location, radius, type, api_key) {
all_results <- list()
next_page_token <- NULL
repeat {
params <- list(
location = location,
radius = radius,
type = type,
key = api_key
)
# Add next_page_token if available
if (!is.null(next_page_token)) {
params$pagetoken <- next_page_token
Sys.sleep(2) # Recommended delay for next request
}
# API request
response <- GET(base_url, query = params)
data <- fromJSON(content(response, "text"), flatten = TRUE)
# Append results
all_results <- append(all_results, list(data$results))
# Check for next page
if (!is.null(data$next_page_token)) {
next_page_token <- data$next_page_token
} else {
break
}
}
Open Street Map - R
Do zebrania informacji o drogach posłużył pakiet osmdata
umożliwiający sprawne korzystanie z API.
pacman::p_load(
sf,
osmdata,
dplyr
)
# Download major road data for Kraków from OpenStreetMap
road_data <- opq(bbox = "Kraków, Poland") %>%
add_osm_feature(key = "highway",
value = c("motorway", "trunk", "primary", "secondary", "tertiary")) %>%
osmdata_sf()
# Extract line geometries representing roads
roads <- road_data$osm_lines
# Convert road lines into points (vertices) for distance calculations
road_points <- st_cast(roads, "POINT")
# Extract coordinates and other relevant information
road_points_df <- road_points %>%
mutate(
longitude = st_coordinates(geometry)[, 1],
latitude = st_coordinates(geometry)[, 2]
) %>%
st_drop_geometry() %>%
select(osm_id, name, highway, longitude, latitude)
readr:::write_csv(road_points_df, "./data/OSM-Road.csv")