我正在尝试从 R 中的纳斯达克请求 URL 中提取 JSON 文件,但没有成功。我已经能够用 Python 制定解决方案,但如果可能的话,我真的很想在 R 中找到解决方案。
我已联系纳斯达克帮助台,但他们不支持通过请求 API URL 访问数据。
我在 Stack Overflow 上看到了几种解决方案,但似乎没有一个适合我的特定情况。这是最简单的尝试和我收到的结果:
library(jsonlite)
data <- fromJSON('https://api.nasdaq.com/api/calendar/dividends?date=2023-10-09')
Error in open.connection(con, "rb") : cannot open the connection
In addition: Warning message:
In open.connection(con, "rb") :
InternetOpenUrl failed: 'The operation timed out'
我不认为上述尝试是正确的方法,所以我希望有人看到这一点并找到可行的解决方案。
我的预期结果是将从请求 API URL (https://api.nasdaq.com/api/calendar/dividends?date=2023-10-09) 中提取 JSON 文件并转换为 R数据框。
确实,该网站(故意?)挂在一些基于标题的查询上。
library(httr)
url <- 'api.nasdaq.com/api/calendar/dividends?date=2023-10-09'
response <- GET(url, add_headers(
`User-Agent`= "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0"
,`Accept-Language`= "en-US,en;q=0.5"
))
status_code(response)
# [1] 200
str(content(response))
# List of 3
# $ data :List of 2
# ..$ calendar :List of 3
# .. ..$ asOf : chr "Mon, Oct 9, 2023"
# .. ..$ headers:List of 8
# .. .. ..$ symbol : chr "Symbol"
# .. .. ..$ companyName : chr "Name"
# .. .. ..$ dividend_Ex_Date : chr "Ex-Dividend Date"
# .. .. ..$ payment_Date : chr "Payment Date"
# .. .. ..$ record_Date : chr "Record Date"
# .. .. ..$ dividend_Rate : chr "Dividend"
# .. .. ..$ indicated_Annual_Dividend: chr "Indicated Annual Dividend"
# .. .. ..$ announcement_Date : chr "Announcement Date"
# .. ..$ rows :List of 2
# .. .. ..$ :List of 8
# .. .. .. ..$ companyName : chr "Brady Corporation Common Stock"
# .. .. .. ..$ symbol : chr "BRC"
# .. .. .. ..$ dividend_Ex_Date : chr "10/09/2023"
# .. .. .. ..$ payment_Date : chr "10/31/2023"
# .. .. .. ..$ record_Date : chr "10/10/2023"
# .. .. .. ..$ dividend_Rate : num 0.235
# .. .. .. ..$ indicated_Annual_Dividend: num 0.94
# .. .. .. ..$ announcement_Date : chr "9/04/2023"
# .. .. ..$ :List of 8
# .. .. .. ..$ companyName : chr "Saba Capital Income & Opportunities Fund SBI"
# .. .. .. ..$ symbol : chr "BRW"
# .. .. .. ..$ dividend_Ex_Date : chr "10/09/2023"
# .. .. .. ..$ payment_Date : chr "10/31/2023"
# .. .. .. ..$ record_Date : chr "10/10/2023"
# .. .. .. ..$ dividend_Rate : num 0.085
# .. .. .. ..$ indicated_Annual_Dividend: num 1.02
# .. .. .. ..$ announcement_Date : chr "9/29/2023"
# ..$ timeframe:List of 2
# .. ..$ minDate: chr "1922-05-22T00:00:00"
# .. ..$ maxDate: chr "2104-06-02T00:00:00"
# $ message: NULL
# $ status :List of 3
# ..$ rCode : int 200
# ..$ bCodeMessage : NULL
# ..$ developerMessage: NULL
我显示了我的标题的结果,尽管最终你的结果也有效。
在我的 Firefox 浏览器中,我发送到该 URL,它立即生效。打开浏览器开发工具 (
F12
),转到 Network 选项卡,右键单击请求行(应显示 200)并选择 复制值 >> 复制请求标头,我得到了:
GET /api/calendar/dividends?date=2023-10-09 HTTP/2
Host: api.nasdaq.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Pragma: no-cache
Cache-Control: no-cache
(还有一个
Cookie:
标题,但我在不太可能发生的情况下删除了它,这对我/我的浏览器来说意味着一些个人的东西*耸耸肩*。)
我将它们转换为 R 友好的字符串参数向量
hdrs <- clipr::read_clip()
hdrs |>
grep("^(GET|Host:) ", x = _, value = TRUE, invert = TRUE) |>
sub("^([^:]+):", ", `\\1` =", x = _) |>
paste(collapse = "\n") |>
sub("^, ", "", x = _) |>
cat("\n")
# `User-Agent` = Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0
# , `Accept` = text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
# , `Accept-Language` = en-US,en;q=0.5
# , `Accept-Encoding` = gzip, deflate, br
# , `Connection` = keep-alive
# , `Upgrade-Insecure-Requests` = 1
# , `Sec-Fetch-Dest` = document
# , `Sec-Fetch-Mode` = navigate
# , `Sec-Fetch-Site` = cross-site
# , `Pragma` = no-cache
# , `Cache-Control` = no-cache
(我真正的控制台输出没有预先添加
#
),然后我将其复制/粘贴到模板表达式中
response <- GET(url, add_headers(
###
))
status_code(response)
用
###
'ed 标题覆盖 cat
。我运行它并立即得到一个200
,这意味着它成功了。然后我删除了所有选项并再次尝试,它挂起了(毫不奇怪)。我一次添加了几个,直到再次得到 200
,最终提出了两个产生影响的标题。
最终我找到了有效的方法(我认为你注释的代码大部分是相同的)。
我将在这里使用
dplyr
,因为它比基本列更适合于列表列。
library(dplyr)
quux <- content(response)
tibble(asOf = quux$data$calendar$asOf) %>%
reframe(asOf, rows = lapply(quux$data$calendar$rows, as.data.frame)) %>%
tidyr::unnest(rows)
# # A tibble: 2 × 9
# asOf companyName symbol dividend_Ex_Date payment_Date record_Date dividend_Rate indicated_Annual_Dividend announcement_Date
# <chr> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <chr>
# 1 Mon, Oct 9, 2023 Brady Corporation Common Stock BRC 10/09/2023 10/31/2023 10/10/2023 0.235 0.94 9/04/2023
# 2 Mon, Oct 9, 2023 Saba Capital Income & Opportunities Fund SBI BRW 10/09/2023 10/31/2023 10/10/2023 0.085 1.02 9/29/2023
我认为
quux$data$headers
只是将 rows
中找到的名称与更易于人类阅读的名称进行映射的一种方法,因此它并没有增加太多。同样,minDate
和 maxDate
可能会让您知道,但在结果框架中可能并不那么重要。
可能有更好的方法来框架化它,但这目前有效,并且可能足以获取数据。