Как проверить действительный вызов API в R? RCurl и httr пока не помогают

Я хочу импортировать данные JSON из UN COMTRADE. Итак, я написал список допустимых стран и лет, а затем запустил цикл, который работает нормально, за исключением случаев, когда определенный год не содержит данных для страны.

Учитывая это, я хочу проверить, действителен ли мой вызов API, поэтому я пишу это:

library(RCurl)

# this is an actual valid API call    
string = "http://comtrade.un.org/api/get?max=50000&type=C&freq=A&px=S2&ps=2010&r=4&p=all&rg=2&cc=AG4&fmt=json"

url.exists(string, useragent="curl/7.47.0 RCurl/1.95-4.8")

Но даже для действительных кодов стран и лет, которые могут отображаться в интернет-браузере в виде текста JSON, вывод R говорит:

url.exists(string, useragent="curl/7.47.0 RCurl/1.95-4.8")
[1] FALSE

С httr да

library(httr)
!http_error(string)

и я получаю [1] FALSE

Как я могу исправить этот ложноотрицательный результат?


person pachamaltese    schedule 23.02.2017    source источник
comment
Можете ли вы проверить содержимое httr::GET(string), например, посмотреть код состояния запроса: httr::GET(string)[['status_code']].   -  person SymbolixAU    schedule 24.02.2017


Ответы (1)


Я взял пик на url.exists(), а затем написал эту более простую версию

> g = basicTextGatherer()
> x = curlPerform(url=string, headerfunction=g$update, nobody=TRUE)
> g$value()
[1] "HTTP/1.1 302 Moved Temporarily\r\nLocation: https://comtrade.un.org/api/get?max=50000&type=C&freq=A&px=S2&ps=2010&r=4&p=all&rg=2&cc=AG4&fmt=json\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nDate: Thu, 23 Feb 2017 23:09:13 GMT\r\nAge: 0\r\nConnection: close\r\nVia: 1.1 localhost.localdomain\r\n\r\n"

URL-адрес http: перенаправляется на https:, поэтому я попытался

> string = sub("http", "https", string)
> g = basicTextGatherer()
> x = curlPerform(url=string, headerfunction=g$update, nobody=TRUE)
> g$value()
[1] "HTTP/1.1 405 Method Not Allowed\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nAllow: GET\r\nContent-Length: 73\r\nContent-Type: application/json; charset=utf-8\r\nExpires: -1\r\nServer: Microsoft-IIS/7.5\r\nX-AspNet-Version: 4.0.30319\r\nX-Powered-By: ASP.NET\r\nDate: Thu, 23 Feb 2017 23:11:02 GMT\r\n\r\n"

Метод 'HEAD', подразумеваемый параметром curl nobody, не поддерживается. По этой же причине httr::http_error() терпит неудачу — потому что он выполняет запрос HEAD. На стороне сервера принято решение не поддерживать запросы HEAD, поэтому на стороне пользователя ничего нельзя сделать.

Вы также можете попытаться получить только один байт (например, RCurl::getURL(string, followlocation=TRUE, range="0-1")), но это также может не поддерживаться (и не для этого запроса — возвращается весь ответ на запрос).

Таким образом, единственный способ проверить, существует ли файл на самом деле, — это получить его. Я бы использовал httr::GET(), может быть, как

tryCatch({
    response <- httr::GET(string)
    stop_for_status(response)
    ## ...
}, http_error=function(e) {
    ## log error or otherwise recover
})

В любом случае, это, вероятно, более эффективное решение. Если запрос выполнен успешно, то сначала для проверки, а затем для выполнения запроса требуется два сетевых вызова, тогда как для выполнения запроса без проверки требуется только один сетевой вызов. Если запрос завершается ошибкой, то при обоих подходах требуется только один сетевой вызов, а возвращаемое значение одинаково компактно. Таким образом, мы сохраняем задержку, вызванную сетевым вызовом, в наиболее распространенном сценарии.

person Martin Morgan    schedule 23.02.2017