Избегайте кодирования URL в R

Я пытаюсь получить широту/долготу из Google Geocoding API, но запрос не выполняется, когда в адресе присутствуют датские местные символы. Я подозреваю, что это потому, что функция httr::GET кодирует URL-адрес, но я не совсем уверен, прав ли я.

Если вы скопируете/вставите эту ссылку прямо в браузер, вы получите действительный результат: http://maps.googleapis.com/maps/api/geocode/json?address=Søholmen+9,+4500+Дания

Но приведенный ниже код недействителен, даже если URL-адрес тот же, прежде чем он будет проанализирован в функции GET. Это работает, если я использую адрес без моих местных символов.

library(httr)
library(jsonlite)
library(stringr)

address <- "Søholmen 9, 4500 Denmark"
# address <- "Kronprinsesse Sofies Vej 6, 2000 Denmark"

base_url <- "http://maps.googleapis.com/maps/api/geocode/json?"

# An address OR components
geo_url <- paste0(base_url, "address=", str_replace_all(address, pattern = " ", replacement = "+"))

# Get the result
# get the content
# Parse the JSON
temp_geo_results <- httr::GET(url = URLencode(URL = geo_url), verbose())
temp_geo_results <- httr::content(temp_geo_results, as = "text")
temp_geo_results <- jsonlite::fromJSON(temp_geo_results)

Вот моя информация о сеансе ()

R version 3.1.2 (2014-10-31)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=Danish_Denmark.1252  LC_CTYPE=Danish_Denmark.1252        LC_MONETARY=Danish_Denmark.1252
[4] LC_NUMERIC=C                    LC_TIME=Danish_Denmark.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] stringr_0.6.2   jsonlite_0.9.10 httr_0.5       

loaded via a namespace (and not attached):
[1] RCurl_1.95-4.3 tools_3.1.2 

РЕДАКТИРОВАТЬ: я удалил строку кода, не необходимую для вопроса, и добавил свой файл sessionInfo.


person KERO    schedule 02.03.2015    source источник
comment
Возможно, другой вариант — использовать другой вариант кодировки и построить url с помощью функций build_url/parse_url из пакета httr, но я не уверен, как это сделать.   -  person KERO    schedule 02.03.2015
comment
Этот URL-адрес также дает правильный ответ: http://maps.googleapis.com/maps/api/geocode/json?address=S%C3%B8holmen+9,+4500+Denmark Таким образом, вы можете закодировать вручную, как предложил @KERO, и тогда это сработает.   -  person LauriK    schedule 02.03.2015
comment
@LauriK Если я скопирую / вставлю ваш URL-адрес в свой браузер и функцию GET, я получу неверный запрос / нулевой результат.   -  person KERO    schedule 02.03.2015
comment
Странный. У меня работает в Хроме.   -  person LauriK    schedule 02.03.2015
comment
Эти проблемы с кодировкой время от времени сбивают меня с толку. Я должен прочитать об этом. Я также использую хром и даже сохранил свой документ R как UTF-8.   -  person KERO    schedule 02.03.2015
comment
Не могли бы вы зарегистрировать это как ошибку httr на github?   -  person hadley    schedule 07.03.2015
comment
Конечно.. Я сделаю это прямо сейчас.   -  person KERO    schedule 07.03.2015


Ответы (4)


Кажется, это проблема с кодировкой.

Следующее работает отлично для меня:

address <- "Søholmen 9, 4500 Denmark"
u <- sprintf("http://maps.googleapis.com/maps/api/geocode/json?address=%s", 
             gsub('\\s+', '+', enc2utf8(address)))

fromJSON(content(GET(u), as='text'))
person jbaums    schedule 02.03.2015
comment
Я попытался обернуть адрес в enc2utf8, и это работает. Я думал, что смогу избежать этих проблем, сохранив файл R как UTF-8. Очевидно нет. Спасибо за помощь. Очень признателен! - person KERO; 02.03.2015
comment
Хороший вопрос - enc2utf8 здесь, вероятно, более разумно. Я отредактирую. - person jbaums; 02.03.2015

Вы можете использовать пакеты rvest

library(rvest); library(jsonlite)
address <- "Søholmen 9, 4500 Denmark"
# address <- "Kronprinsesse Sofies Vej 6, 2000 Denmark"
base_url <- "http://maps.googleapis.com/maps/api/geocode/json?"

# An address OR components
geo_url <- paste0(base_url, "address=", str_replace_all(address, pattern = " ", replacement = "+"))
geo_url <- iconv(geo_url, to="UTF-8")

temp_geo_results <- html_text(html_nodes(html(geo_url) , "p"))
temp_geo_results <- fromJSON(temp_geo_results)
person dimitris_ps    schedule 02.03.2015

Как я решил аналогичную проблему: установка Encoding между rawToChar и fromJSON, как показано ниже (не исполняемый файл).

library(httr)
library(jsonlite)

call_api <- GET("YOUR_URL",
                  add_headers(.headers=c(`Authorization` = "YOUR_KEY")))

strange_characters <- rawToChar(call_api$content) #wherever the raw_data is

# if you pass Encoding(strange_characters) you will get "unknown". So run the line below.
Encoding(strange_characters) <- "UTF-8" 
  
right_characters <- fromJSON(strange_characters)
person André Jakob    schedule 18.03.2021

Я могу поделиться грубым способом, как я решил ту же проблему на своем языке:

deencode <- function(text){
  output <- NULL
  for(i in 1:length(text)){
    temp <- text[i]
    temp <- gsub("ā", "a", temp)  
    temp <- gsub("Ā", "A", temp)
    temp <- gsub("č", "c", temp)
    temp <- gsub("Č", "C", temp)
    temp <- gsub("ē", "e", temp)
    temp <- gsub("Ē", "E", temp)
    temp <- gsub("ģ", "g", temp)
    temp <- gsub("Ģ", "G", temp)
    temp <- gsub("ī", "i", temp)
    temp <- gsub("Ī", "I", temp)
    temp <- gsub("ķ", "k", temp)
    temp <- gsub("Ķ", "K", temp)
    temp <- gsub("ļ", "l", temp)
    temp <- gsub("Ļ", "L", temp)
    temp <- gsub("ņ", "n", temp)
    temp <- gsub("Ņ", "N", temp)
    temp <- gsub("š", "s", temp)
    temp <- gsub("Š", "S", temp)
    temp <- gsub("ū", "u", temp)
    temp <- gsub("Ū", "u", temp)
    temp <- gsub("ž", "z", temp)
    temp <- gsub("Ž", "Z", temp)
    output <- c(output, temp)
  }
  return(output)
}

После этой упрощенной замены все заработало, по крайней мере, в Google geocode API.

person statespace    schedule 02.03.2015
comment
gsub векторизован, поэтому вам не нужно перебирать элементы text :) - person jbaums; 02.03.2015