如何通过函数将 URL 传递给 dplyr:mutate 时修复 "invalid char in json text"
How to fix "invalid char in json text" when passing a URL via function to dplyr:mutate
我编写了一个函数来通过 API 检索数据。输出格式为JSON。 https://jsoneditoronline.org/?id=ac0ec7ececae49ca92599ff912458a84
对于每个查询,一个变量(路径)应该改变。此变量位于列 (product_folder) 中的数据框 (product_folders_summarised) 中。
library(tidyverse)
library(httr)
library(jsonlite)
library(data.table)
func_visibility <- function(product_folder) {
api_url <- "https://api.where-the-data-comes-from.com/example"
api_key <- "_API_KEY_"
format <- "json"
request <-
fromJSON(
paste0(api_url, "?api_key=",api_key,"&format=",format,"&path=",product_folder),
simplifyVector = TRUE,
simplifyDataFrame = TRUE,
flatten = TRUE
)
request <- lapply(request, function(x) {
x[sapply(x, is.null)] <- NA
unlist(x)
})
request <- as.data.frame(t(request$answer))
request <- select(request, -sichtbarkeitsindex.path, -sichtbarkeitsindex.date)
return(request)
}
product_folders_summarised <- product_folders_summarised %>%
dplyr::mutate(visibility_value = func_visibility(product_folder))
数据帧结构如下:
|product_folder|value_1|value_2|
|https://www.example.de/folder/|this|that|
|https://www.example.de/anotherfolder/|...|...|
我希望数据框 (product_folders_summarised) 的值取自列 (product_folder),然后传递给函数,然后 visibility_value 添加为列。
相反,我收到了错误消息
Error: lexical error: invalid char in json text.
https://api.https://api.where-the-data-comes-from.com/example.
(right here) ------^
我现在已经按照 r2evans 的建议调整了我的功能。
func_visibility <- function(path) {
api_url <- "https://api.where-the-data-comes-from.com/example"
api_key <- "_API_KEY_"
format <- "json"
request <- paste0(api_url,"?api_key=",api_key,"&format=",format,"&path=",path)
request <- lapply(request, jsonlite::fromJSON)
request <- lapply(request, function(x) {
x[sapply(x, is.null)] <- NA
as.data.frame(t(x))
unlist(x)
})
return(request)
}
product_folders_summarised_short <- product_folders_summarised_short %>%
dplyr::mutate(sichtbarkeitsindex_value = func_visibility(product_folder))
现在从 API 检索数据。数据被写入数据框的新最后一列:
c(method = "domain.sichtbarkeitsindex", answer.sichtbarkeitsindex.path = "https://www.example.de/folder/", answer.sichtbarkeitsindex.date = "2019-09-02T00:00:00+02:00", answer.sichtbarkeitsindex.value = "0", credits.used = "1")
在我的第一次尝试中(参见第一个代码块),我将数据转换为数据帧。
request <- as.data.frame(t(request$answer)),
request <- select(request, -sichtbarkeitsindex.path, -sichtbarkeitsindex.date),
应用于单个 URL,这有效。现在我整合了
`as.data.frame(t(x))`,
但我只得到 API 中的数据存储为字符向量的结果。
您认为将数据作为字符向量写入数据帧的最后一列是否更容易,以便在将第一个函数传递给另一个函数后将向量分配给新的数据帧?
如果您深入了解 jsonlite::fromJSON
如何处理其参数,您会发现它调用了:
jsonlite::fromJSON
jsonlite:::parse_and_simplify
jsonlite:::parseJSON
jsonlite:::parse_string
(注意大多数是内部的,不是导出的)...最后一个函数是
function (txt, bigint_as_char)
{
if (length(txt) > 1) {
txt <- paste(txt, collapse = "\n")
}
.Call(R_parse, txt, bigint_as_char)
}
这意味着您的 json 字符串向量正在使用 \n
折叠成长度 1(这对我来说似乎很奇怪......)。因此,有效的 JSON 向量实际上变成了 ndjson(换行符分隔 json),而 fromJSON
不会。
两个选项:
在您的 lapply
中进行 json 解析。
jsonvec <- c('{"a":1}', '{"b":2}')
lapply(jsonvec, jsonlite::fromJSON)
# [[1]]
# [[1]]$a
# [1] 1
# [[2]]
# [[2]]$b
# [1] 2
使用jsonlite::stream_in
(做做json)并禁用简化:
jsonvec <- c('{"a":1}', '{"b":2}')
jsonlite::stream_in(textConnection(jsonvec), simplifyDataFrame = FALSE)
# Imported 2 records. Simplifying...
# [[1]]
# [[1]]$a
# [1] 1
# [[2]]
# [[2]]$b
# [1] 2
使用 Vectorize
将非矢量友好函数转换为矢量友好函数。
jsonvec <- c('{"a":1}', '{"b":2}')
Vectorize(jsonlite::fromJSON, USE.NAMES=FALSE)(jsonvec)
# $a
# [1] 1
# $b
# [1] 2
这可以让您只用 Vectorize(fromJSON)
替换代码中 fromJSON
的任何实例,注意它 returns 然后您可以在向量上使用的函数。
鉴于你是依赖fromJSON
下载数据,我建议第一种或第三种方案。
我现在采取了不同的方法。解决方案是使用rowwise() %>%
。否则整列将用作向量。
library(tidyverse)
library(httr)
library(jsonlite)
func_sichtbarkeit <- function(pfad, output) {
httr::GET(
url = "https://api.where-the-data-comes-from.com/example",
query = list(
api_key = "_API_KEY_",
format = "json",
country ="de",
date = "2019-09-08",
daily = "true",
path = pfad
)
) -> res
httr::warn_for_status(res) # Prüfen auf Status 200 und bei Bedarf warnen
out <- httr::content(res, as = "text", encoding = "UTF-8") # Abrufen der Daten als text und URF-8 encodiert
out <- jsonlite::fromJSON(out) # JSON parsen
answer_raw <- out$answer$sichtbarkeitsindex # Zutreffenden Datensatz aus dem JSON auswählen
visibility_raw <- answer_raw[[1]][["value"]] # Reduktion auf SI Wert
return(visibility_raw)
}
all_search_2019_09_08 <- all_search %>%
rowwise() %>%
dplyr::mutate(visibility_value_2019_09_08 = func_sichtbarkeit(address))
我编写了一个函数来通过 API 检索数据。输出格式为JSON。 https://jsoneditoronline.org/?id=ac0ec7ececae49ca92599ff912458a84
对于每个查询,一个变量(路径)应该改变。此变量位于列 (product_folder) 中的数据框 (product_folders_summarised) 中。
library(tidyverse)
library(httr)
library(jsonlite)
library(data.table)
func_visibility <- function(product_folder) {
api_url <- "https://api.where-the-data-comes-from.com/example"
api_key <- "_API_KEY_"
format <- "json"
request <-
fromJSON(
paste0(api_url, "?api_key=",api_key,"&format=",format,"&path=",product_folder),
simplifyVector = TRUE,
simplifyDataFrame = TRUE,
flatten = TRUE
)
request <- lapply(request, function(x) {
x[sapply(x, is.null)] <- NA
unlist(x)
})
request <- as.data.frame(t(request$answer))
request <- select(request, -sichtbarkeitsindex.path, -sichtbarkeitsindex.date)
return(request)
}
product_folders_summarised <- product_folders_summarised %>%
dplyr::mutate(visibility_value = func_visibility(product_folder))
数据帧结构如下:
|product_folder|value_1|value_2|
|https://www.example.de/folder/|this|that|
|https://www.example.de/anotherfolder/|...|...|
我希望数据框 (product_folders_summarised) 的值取自列 (product_folder),然后传递给函数,然后 visibility_value 添加为列。
相反,我收到了错误消息
Error: lexical error: invalid char in json text.
https://api.https://api.where-the-data-comes-from.com/example.
(right here) ------^
我现在已经按照 r2evans 的建议调整了我的功能。
func_visibility <- function(path) {
api_url <- "https://api.where-the-data-comes-from.com/example"
api_key <- "_API_KEY_"
format <- "json"
request <- paste0(api_url,"?api_key=",api_key,"&format=",format,"&path=",path)
request <- lapply(request, jsonlite::fromJSON)
request <- lapply(request, function(x) {
x[sapply(x, is.null)] <- NA
as.data.frame(t(x))
unlist(x)
})
return(request)
}
product_folders_summarised_short <- product_folders_summarised_short %>%
dplyr::mutate(sichtbarkeitsindex_value = func_visibility(product_folder))
现在从 API 检索数据。数据被写入数据框的新最后一列:
c(method = "domain.sichtbarkeitsindex", answer.sichtbarkeitsindex.path = "https://www.example.de/folder/", answer.sichtbarkeitsindex.date = "2019-09-02T00:00:00+02:00", answer.sichtbarkeitsindex.value = "0", credits.used = "1")
在我的第一次尝试中(参见第一个代码块),我将数据转换为数据帧。
request <- as.data.frame(t(request$answer)),
request <- select(request, -sichtbarkeitsindex.path, -sichtbarkeitsindex.date),
应用于单个 URL,这有效。现在我整合了
`as.data.frame(t(x))`,
但我只得到 API 中的数据存储为字符向量的结果。
您认为将数据作为字符向量写入数据帧的最后一列是否更容易,以便在将第一个函数传递给另一个函数后将向量分配给新的数据帧?
如果您深入了解 jsonlite::fromJSON
如何处理其参数,您会发现它调用了:
jsonlite::fromJSON
jsonlite:::parse_and_simplify
jsonlite:::parseJSON
jsonlite:::parse_string
(注意大多数是内部的,不是导出的)...最后一个函数是
function (txt, bigint_as_char)
{
if (length(txt) > 1) {
txt <- paste(txt, collapse = "\n")
}
.Call(R_parse, txt, bigint_as_char)
}
这意味着您的 json 字符串向量正在使用 \n
折叠成长度 1(这对我来说似乎很奇怪......)。因此,有效的 JSON 向量实际上变成了 ndjson(换行符分隔 json),而 fromJSON
不会。
两个选项:
在您的
lapply
中进行 json 解析。jsonvec <- c('{"a":1}', '{"b":2}') lapply(jsonvec, jsonlite::fromJSON) # [[1]] # [[1]]$a # [1] 1 # [[2]] # [[2]]$b # [1] 2
使用
jsonlite::stream_in
(做做json)并禁用简化:jsonvec <- c('{"a":1}', '{"b":2}') jsonlite::stream_in(textConnection(jsonvec), simplifyDataFrame = FALSE) # Imported 2 records. Simplifying... # [[1]] # [[1]]$a # [1] 1 # [[2]] # [[2]]$b # [1] 2
使用
Vectorize
将非矢量友好函数转换为矢量友好函数。jsonvec <- c('{"a":1}', '{"b":2}') Vectorize(jsonlite::fromJSON, USE.NAMES=FALSE)(jsonvec) # $a # [1] 1 # $b # [1] 2
这可以让您只用
Vectorize(fromJSON)
替换代码中fromJSON
的任何实例,注意它 returns 然后您可以在向量上使用的函数。
鉴于你是依赖fromJSON
下载数据,我建议第一种或第三种方案。
我现在采取了不同的方法。解决方案是使用rowwise() %>%
。否则整列将用作向量。
library(tidyverse)
library(httr)
library(jsonlite)
func_sichtbarkeit <- function(pfad, output) {
httr::GET(
url = "https://api.where-the-data-comes-from.com/example",
query = list(
api_key = "_API_KEY_",
format = "json",
country ="de",
date = "2019-09-08",
daily = "true",
path = pfad
)
) -> res
httr::warn_for_status(res) # Prüfen auf Status 200 und bei Bedarf warnen
out <- httr::content(res, as = "text", encoding = "UTF-8") # Abrufen der Daten als text und URF-8 encodiert
out <- jsonlite::fromJSON(out) # JSON parsen
answer_raw <- out$answer$sichtbarkeitsindex # Zutreffenden Datensatz aus dem JSON auswählen
visibility_raw <- answer_raw[[1]][["value"]] # Reduktion auf SI Wert
return(visibility_raw)
}
all_search_2019_09_08 <- all_search %>%
rowwise() %>%
dplyr::mutate(visibility_value_2019_09_08 = func_sichtbarkeit(address))