【问题标题】:How to read json data from list of URLs and tidy it into a dataframe?如何从 URL 列表中读取 json 数据并将其整理到数据框中?
【发布时间】:2019-11-09 00:03:23
【问题描述】:

我正在使用https://ipstack.com 的帮助来对 IP 地址进行地理编码,但我很难在短时间内对所有 1200 个地址进行地理编码。

使用 R,我已将 URL 收集到一个列表中(例如 http://api.ipstack.com/[IP address]?access_key=[access key]),并且可以使用 read_json 读取每个 URL 的 json 数据。但是我无法开发一个循环来从每个 URL 中提取数据。

library(RCurl)
library(jsonlite)

x <- c("http://api.ipstack.com/178.140.119.217?access_key=[access_key]", "http://api.ipstack.com/68.37.21.125?access_key=[access_key]", "http://api.ipstack.com/68.10.255.89?access_key=[access_key]")

read_json(x)
Error in file(path) : invalid 'description' argument

我正在寻找一种能够读取多个 IP 地址并将信息附加到数据帧的解决方案。

*编辑 1:仍然卡住,但我在循环方面取得了一些进展,

library(RCurl)
library(jsonlite)

url_lst = as.character(df$URL)

output = NULL
for (i in url_lst) { 
  x = as.data.frame(read_json(i))
  output = rbind(output,x)
 }

但是,这会导致错误:

Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,  : arguments imply differing number of rows: 1, 0

同样,代码只产生 8 个观察值,而不是 1200 个。

*编辑 2:Bill Ash 的回答比我更深入,但看起来 JSON 数据中的某些值不允许代码成功。

Bill Ash 的代码:

library(httr)
library(tibble)
library(purrr)
library(jsonlite)

ip_addresses <- core_members$ip_address

# a simple function
ip_locate <- function(your_vector_of_ip_addresses, access_key) {

  ip <- your_vector_of_ip_addresses

  map_df(ip, ~{
    out <- httr::GET(url = paste0("http://api.ipstack.com/", .,
                                  "?access_key=", access_key))
    resp <- fromJSON(httr::content(out, "text"), flatten = TRUE)
    tibble::tibble(ip = resp$ip, 
                   country = resp$country_name, 
                   region = resp$region_name, 
                   city = resp$city, 
                   zip = resp$zip, 
                   lat = resp$latitude, 
                   lng = resp$longitude)

  })

}


ip_info <- ip_locate(your_vector_of_ip_addresses = ip_addresses, 
                     access_key = "[access_key]")

# output

ip_info %>% 
  head()

错误开始的地方

ip_info <- ip_locate(your_vector_of_ip_addresses = ip_addresses, 
                     access_key = "[access_key]")

Error: All columns in a tibble must be 1d or 2d objects:
* Column `zip` is NULL
9.
stop(cnd) 
8.
abort(error_column_must_be_vector(names_x[is_xd], classes)) 
7.
check_valid_cols(x) 
6.
lst_to_tibble(xlq$output, .rows, .name_repair, lengths = xlq$lengths) 
5.
tibble::tibble(ip = resp$ip, country = resp$country_name, region = resp$region_name, 
city = resp$city, zip = resp$zip, lat = resp$latitude, lng = resp$longitude) 
4.
.f(.x[[i]], ...) 
3.
map(.x, .f, ...) 
2.
map_df(ip, ~{
out <- httr::GET(url = paste0("http://api.ipstack.com/", 
    ., "?access_key=", access_key))
resp <- fromJSON(httr::content(out, "text"), flatten = TRUE) ... 
1.
ip_locate(your_vector_of_ip_addresses = ip_addresses, access_key = "[access_key]")

因为我只需要这些 IP 地址的坐标,我相信这已经解决了。希望有人愿意继续就这个问题提出建议,但我不会再更新了。

【问题讨论】:

  • ?read_json 表示path= 是“磁盘上的文件”。你试过stream_in(url(..))吗?
  • @r2evans 我确实尝试过,它说“参数'con'必须是一个连接”。我不完全确定如何补救。

标签: r json url


【解决方案1】:

看起来您也可以为批量查找付费。

从那里的文档页面:

批量 IP 查找

ipstack API 还提供同时为多个 IPv4 或 IPv6 地址请求数据的能力。为了批量处理 IP 地址,只需将多个逗号分隔的 IP 地址附加到 API 的基本 URL。

library(httr)
library(tibble)
library(purrr)
library(jsonlite)

# some ip addresses 
ip_addresses <- c("178.140.119.217", "68.37.21.125", "68.10.255.89")

# a simple function
ip_locate <- function(your_vector_of_ip_addresses, access_key) {

  ip <- your_vector_of_ip_addresses

  map_df(ip, ~{
    out <- httr::GET(url = paste0("http://api.ipstack.com/", .,
                    "?access_key=", access_key))
    resp <- fromJSON(httr::content(out, "text"), flatten = TRUE)
    tibble::tibble(ip = resp$ip, 
                   country = resp$country_name, 
                   region = resp$region_name, 
                   city = resp$city, 
                   zip = resp$zip, 
                   lat = resp$latitude, 
                   lng = resp$longitude)

  })

    }

# an example 
ip_info <- ip_locate(your_vector_of_ip_addresses = ip_addresses, 
          access_key = "had to edit out my key")

# output

ip_info %>% 
  head()

# A tibble: 3 x 7
  ip              country       region   city       zip      lat   lng
  <chr>           <chr>         <chr>    <chr>      <chr>  <dbl> <dbl>
1 178.140.119.217 Russia        Moscow   Moscow     101001  55.8  37.6
2 68.37.21.125    United States Michigan Southgate  48195   42.2 -83.2
3 68.10.255.89    United States Virginia Chesapeake 23323   36.8 -76.3

希望这会有所帮助。

【讨论】:

  • 感谢您的回答,看来这就是我正在寻找的解决方案。我认为代码对其余数据(特别是 zip 列)产生了负面反应,因为我收到了错误消息。 “错误:tibble 中的所有列都必须是 1d 或 2d 对象:* 列 zip 为 NULL”
  • 阅读“purrr::possibly”的文档并将其包裹在 tibble 上。应该是您需要为所有 IP 地址运行的内容。或者,您可以尝试将输出变量强制转换为 tibble 中的字符,或者将 map_df 更改为 map,然后再更改列表的 bindrows。希望这会有所帮助。
  • 会的,我尝试阅读 tibble 文档,但没有从中得到太多。
  • Tibble 只是一个花哨的数据框,如果有帮助的话。我认为 purrr:: 功能之一就是您所需要的。要么是‘可能(tibble %>%....., NULL)’,要么是‘try(tibble %>% ..., silent = T)’。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 2021-04-21
  • 1970-01-01
  • 1970-01-01
  • 2019-04-15
  • 2016-10-09
  • 1970-01-01
相关资源
最近更新 更多