Add active listings tab from RentCast API
- update_listings.R: pulls 1-mile radius, clips to plat boundary - Listings tab: table with listed date, address, sqft, price, $/sqft - Weekly cron: Sunday 11:30pm (30 min after owners refresh) - httr2 added to renv.lock
This commit is contained in:
68
data-raw/update_listings.R
Normal file
68
data-raw/update_listings.R
Normal file
@@ -0,0 +1,68 @@
|
||||
# update_listings.R
|
||||
# Weekly update: pull active listings from RentCast within 1 mile of
|
||||
# St. Andrews center, clip to plat boundary, save data/listings.rds.
|
||||
# Input: .Renviron (RENTCAST_API_KEY)
|
||||
# data/plats/plats.shp
|
||||
# Output: data/listings.rds
|
||||
|
||||
library(httr2)
|
||||
library(jsonlite)
|
||||
library(sf)
|
||||
library(dplyr)
|
||||
|
||||
# ── API key ───────────────────────────────────────────────────────────────────
|
||||
api_key <- Sys.getenv("RENTCAST_API_KEY")
|
||||
if (identical(api_key, "")) stop("Missing RENTCAST_API_KEY in .Renviron")
|
||||
|
||||
# ── Pull listings ─────────────────────────────────────────────────────────────
|
||||
resp <- request("https://api.rentcast.io/v1/listings/sale") |>
|
||||
req_headers(
|
||||
"Accept" = "application/json",
|
||||
"X-Api-Key" = api_key
|
||||
) |>
|
||||
req_url_query(
|
||||
latitude = 27.076199,
|
||||
longitude = -82.362253,
|
||||
radius = 1,
|
||||
status = "Active",
|
||||
limit = 500
|
||||
) |>
|
||||
req_retry(max_tries = 3) |>
|
||||
req_perform()
|
||||
|
||||
if (resp_status(resp) >= 400)
|
||||
stop("RentCast API error: HTTP ", resp_status(resp), "\n", resp_body_string(resp))
|
||||
|
||||
listings_raw <- jsonlite::fromJSON(resp_body_string(resp), flatten = TRUE)
|
||||
cat("Fetched:", nrow(listings_raw), "listings\n")
|
||||
|
||||
# ── Clip to St. Andrews plat boundary ────────────────────────────────────────
|
||||
plats <- sf::st_read("./data/plats/plats.shp", quiet = TRUE) |>
|
||||
sf::st_union()
|
||||
|
||||
listings_sf <- sf::st_as_sf(
|
||||
listings_raw,
|
||||
coords = c("longitude", "latitude"),
|
||||
crs = 4326,
|
||||
remove = FALSE
|
||||
)
|
||||
|
||||
in_plat <- lengths(sf::st_within(listings_sf, plats)) > 0
|
||||
listings <- listings_raw[in_plat, ]
|
||||
cat("After plat clip:", nrow(listings), "listings\n")
|
||||
|
||||
# ── Select and clean columns ──────────────────────────────────────────────────
|
||||
listings <- listings |>
|
||||
transmute(
|
||||
listed_date = as.Date(listedDate),
|
||||
address = formattedAddress,
|
||||
sqft = as.numeric(squareFootage),
|
||||
price = as.numeric(price),
|
||||
price_per_sqft = round(price / sqft, 0),
|
||||
latitude,
|
||||
longitude
|
||||
) |>
|
||||
arrange(desc(listed_date))
|
||||
|
||||
cat("Listings saved:", nrow(listings), "\n")
|
||||
saveRDS(listings, "./data/listings.rds")
|
||||
Reference in New Issue
Block a user