library(httr2)
library(jsonlite)
library(ggplot2)
library(scales)
library(lubridate)
library(knitr)
time_options <- data.frame(
Time_Code = c("now 1-H", "now 4-H", "today 1-m", "today 3-m",
"today 12-m", "today 5-y", "all"),
Meaning = c("Past hour", "Past 4 hours", "Past 30 days",
"Past 90 days", "Past 12 months", "Past 5 years",
"Since 2004")
)
kable(time_options)
| Time_Code | Meaning |
|---|---|
| now 1-H | Past hour |
| now 4-H | Past 4 hours |
| today 1-m | Past 30 days |
| today 3-m | Past 90 days |
| today 12-m | Past 12 months |
| today 5-y | Past 5 years |
| all | Since 2004 |
clean_google_json <- function(text) {
text <- sub("^\\)\\]\\}',?\\n?", "", text)
fromJSON(text, simplifyVector = FALSE)
}
get_google_trends_direct <- function(keyword, geo, time) {
explore_request <- list(
comparisonItem = list(
list(
keyword = keyword,
geo = geo,
time = time
)
),
category = 0,
property = ""
)
explore_request_json <- toJSON(explore_request, auto_unbox = TRUE)
explore_response <- request("https://trends.google.com/trends/api/explore") |>
req_url_query(
hl = "en-US",
tz = "360",
req = explore_request_json
) |>
req_user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") |>
req_headers(
accept = "application/json, text/plain, */*",
"accept-language" = "en-US,en;q=0.9"
) |>
req_error(is_error = function(response) FALSE) |>
req_perform()
explore_status <- resp_status(explore_response)
if (explore_status != 200) {
return(
list(
success = FALSE,
status_code = explore_status,
data = NULL
)
)
}
explore_text <- resp_body_string(explore_response)
explore_data <- clean_google_json(explore_text)
widgets <- explore_data$widgets
time_widget <- NULL
for (widget in widgets) {
if (!is.null(widget$id) && widget$id == "TIMESERIES") {
time_widget <- widget
}
}
if (is.null(time_widget)) {
return(
list(
success = FALSE,
status_code = NA,
data = NULL
)
)
}
data_request_json <- toJSON(time_widget$request, auto_unbox = TRUE)
data_response <- request("https://trends.google.com/trends/api/widgetdata/multiline") |>
req_url_query(
hl = "en-US",
tz = "360",
req = data_request_json,
token = time_widget$token
) |>
req_user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") |>
req_headers(
accept = "application/json, text/plain, */*",
"accept-language" = "en-US,en;q=0.9"
) |>
req_error(is_error = function(response) FALSE) |>
req_perform()
data_status <- resp_status(data_response)
if (data_status != 200) {
return(
list(
success = FALSE,
status_code = data_status,
data = NULL
)
)
}
data_text <- resp_body_string(data_response)
data_json <- clean_google_json(data_text)
timeline <- data_json$default$timelineData
dates <- c()
hits <- c()
for (row in timeline) {
date_value <- as.Date(
as.POSIXct(
as.numeric(row$time),
origin = "1970-01-01",
tz = "UTC"
)
)
hit_value <- as.numeric(row$value[[1]])
dates <- c(dates, date_value)
hits <- c(hits, hit_value)
}
trend_data <- data.frame(
date = dates,
hits = hits
)
list(
success = TRUE,
status_code = 200,
data = trend_data
)
}
trend_result <- get_google_trends_direct(
keyword = "Starbucks",
geo = "US",
time = "today 5-y"
)
if (trend_result$success == TRUE) {
iot <- trend_result$data
} else {
iot <- data.frame(
date = as.Date(character()),
hits = numeric()
)
}
if (trend_result$success == TRUE) {
cat("Google Trends data was successfully retrieved.")
} else {
cat("Google Trends data could not be retrieved from Posit Cloud.")
cat("\n\nStatus code:", trend_result$status_code)
cat("\n\nA status code of 429 means Google Trends is rate-limiting requests from this cloud environment.")
}
## Google Trends data could not be retrieved from Posit Cloud.
##
## Status code: 429
##
## A status code of 429 means Google Trends is rate-limiting requests from this cloud environment.
head(iot)
## [1] date hits
## <0 rows> (or 0-length row.names)
if (nrow(iot) > 0) {
ggplot(iot, aes(x = date, y = hits)) +
geom_line(color = "#00704A", linewidth = 1) +
geom_smooth(
method = "loess",
se = TRUE,
color = "#1E3932",
fill = "#D4E9E2",
alpha = 0.3
) +
scale_x_date(date_labels = "%b %Y", date_breaks = "2 months") +
labs(
title = "Google Search Interest: Starbucks",
subtitle = "United States | Past 5 years | Web Search",
x = NULL,
y = "Relative Interest (0-100)",
caption = "Source: Google Trends"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(color = "gray50"),
axis.text.x = element_text(angle = 30, hjust = 1)
)
} else {
plot.new()
text(
x = 0.5,
y = 0.5,
labels = "Google Trends request was rate-limited by Posit Cloud.\nStatus code: 429",
cex = 1.1
)
}
Google Trends. (2024). Google Trends Tutorials [YouTube series]. Google Search Central. https://developers.google.com/search/blog/2024/09/google-trends-tutorials
Massicotte, P., & Eddelbuettel, D. (2023). gtrendsR: Perform and Display Google Trends Queries [R package]. https://cran.r-project.org/package=gtrendsR
Chan, M. (2019). Vignette: Google Trends with the gtrendsR package. https://martinctc.github.io/blog/vignette-google-trends-with-gtrendsr/